From b9f19de776f9f3d81e2f59ff02432025e7dd4606 Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Thu, 27 Aug 2026 20:58:04 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=82=E5=AF=9F=E8=80=85=E6=95=88=E5=BA=94?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/kernel/Taskflow_Frame_Access.hpp | 8 +- kernel/src/kernel/frame.cpp | 34 ++-- kernel/src/kernel/frame.hpp | 5 - kernel/src/kernel/render_common.cpp | 214 ++++---------------- kernel/src/kernel/render_common.hpp | 4 - web_server/src/Plot.cpp | 5 - web_server/src/Web_Server.cpp | 4 - webapp_gallery/src/app.tsx | 101 +++------ 8 files changed, 85 insertions(+), 290 deletions(-) diff --git a/kernel/src/kernel/Taskflow_Frame_Access.hpp b/kernel/src/kernel/Taskflow_Frame_Access.hpp index 19639a3..b83b48f 100644 --- a/kernel/src/kernel/Taskflow_Frame_Access.hpp +++ b/kernel/src/kernel/Taskflow_Frame_Access.hpp @@ -23,14 +23,10 @@ struct Taskflow_Frame_Access { Render_Frame& frame, std::size_t worker, std::uint64_t native_id, std::size_t queue_size, std::size_t queue_capacity, Clock::time_point entered, Clock::time_point started, - Clock::time_point finished, std::uint64_t cpu_entered_ns, - std::uint64_t cpu_started_ns, std::uint64_t cpu_duration_ns, - std::uint64_t cpu_cycles, std::uint64_t cooperative_wait_ns, - bool cpu_time_coarse); + Clock::time_point finished, std::uint64_t cooperative_wait_ns); static void finish_task_observer( Render_Frame& frame, std::size_t worker, std::size_t task, - Clock::time_point completed, std::uint64_t cpu_finished_ns, - std::uint64_t cpu_completed_ns) noexcept; + Clock::time_point completed) noexcept; [[nodiscard]] static Taskflow_Graph_Token begin_graph( Render_Frame& frame, Task_Graph& graph, std::string_view stage); static void finish_graph(Taskflow_Graph_Token token, diff --git a/kernel/src/kernel/frame.cpp b/kernel/src/kernel/frame.cpp index a0ed490..5980592 100644 --- a/kernel/src/kernel/frame.cpp +++ b/kernel/src/kernel/frame.cpp @@ -51,7 +51,7 @@ void Render_Frame::begin(Frame_Identity identity, for (auto& measurement : d->measurements) measurement.store(0, std::memory_order_relaxed); d->taskflow_trace_requested.store(false, std::memory_order_relaxed); - d->taskflow_workers.clear(); + for (auto& worker : d->taskflow_workers) worker.tasks.clear(); d->taskflow_graphs.clear(); d->markers[static_cast(Frame_Trace_Marker::created)].store(encode_present_value(0), std::memory_order_relaxed); } @@ -177,7 +177,10 @@ Taskflow_Frame_Trace Render_Frame::take_taskflow_trace() { static_cast(index), decode_present_value(encoded)}); } - result.graphs = std::move(d->taskflow_graphs); + result.graphs.reserve(d->taskflow_graphs.size()); + for (auto& graph : d->taskflow_graphs) + result.graphs.push_back(std::move(graph)); + d->taskflow_graphs.clear(); for (auto& worker : d->taskflow_workers) { for (auto& task : worker.tasks) result.tasks.push_back(std::move(task)); @@ -341,9 +344,11 @@ Taskflow_Frame_Trace Render_Frame::take_taskflow_trace() { void detail::Taskflow_Frame_Access::begin_capture(Render_Frame& frame, std::size_t workers) { auto& data = *frame.d; - data.taskflow_workers.clear(); data.taskflow_workers.resize(workers); - for (auto& worker : data.taskflow_workers) worker.tasks.reserve(64); + for (auto& worker : data.taskflow_workers) { + worker.tasks.clear(); + if (worker.tasks.capacity() < 64) worker.tasks.reserve(64); + } data.taskflow_graphs.clear(); } @@ -356,10 +361,7 @@ std::size_t detail::Taskflow_Frame_Access::append_task( Render_Frame& frame, std::size_t worker, std::uint64_t native_id, std::size_t queue_size, std::size_t queue_capacity, Clock::time_point entered, Clock::time_point started, - Clock::time_point finished, std::uint64_t cpu_entered_ns, - std::uint64_t cpu_started_ns, std::uint64_t cpu_duration_ns, - std::uint64_t cpu_cycles, std::uint64_t cooperative_wait_ns, - bool cpu_time_coarse) { + Clock::time_point finished, std::uint64_t cooperative_wait_ns) { auto& data = *frame.d; if (worker >= data.taskflow_workers.size()) return std::numeric_limits::max(); @@ -376,22 +378,15 @@ std::size_t detail::Taskflow_Frame_Access::append_task( trace.finished_ms = elapsed_ms(finished); trace.completed_ms = trace.finished_ms; trace.duration_ms = std::max(0.0, trace.finished_ms - trace.started_ms); - trace.cpu_duration_ms = static_cast(cpu_duration_ns) / 1'000'000.0; - trace.cpu_cycles = cpu_cycles; trace.cooperative_wait_ms = static_cast(cooperative_wait_ns) / 1'000'000.0; - trace.cpu_time_coarse = cpu_time_coarse; trace.observer_entry_ms = std::max(0.0, trace.started_ms - trace.entered_ms); - trace.observer_entry_cpu_ms = cpu_started_ns >= cpu_entered_ns - ? static_cast(cpu_started_ns - cpu_entered_ns) / 1'000'000.0 - : 0.0; data.taskflow_workers[worker].tasks.push_back(std::move(trace)); return data.taskflow_workers[worker].tasks.size() - 1; } void detail::Taskflow_Frame_Access::finish_task_observer( Render_Frame& frame, std::size_t worker, std::size_t task, - Clock::time_point completed, std::uint64_t cpu_finished_ns, - std::uint64_t cpu_completed_ns) noexcept { + Clock::time_point completed) noexcept { auto& data = *frame.d; if (worker >= data.taskflow_workers.size() || task >= data.taskflow_workers[worker].tasks.size()) return; @@ -400,9 +395,6 @@ void detail::Taskflow_Frame_Access::finish_task_observer( completed - data.created_at).count(); trace.observer_exit_ms = std::max( 0.0, trace.completed_ms - trace.finished_ms); - trace.observer_exit_cpu_ms = cpu_completed_ns >= cpu_finished_ns - ? static_cast(cpu_completed_ns - cpu_finished_ns) / 1'000'000.0 - : 0.0; } detail::Taskflow_Graph_Token detail::Taskflow_Frame_Access::begin_graph( @@ -411,6 +403,10 @@ detail::Taskflow_Graph_Token detail::Taskflow_Frame_Access::begin_graph( graph.stage = stage; graph.taskflow_name = taskflow.name(); graph.nodes = detail::Task_Graph_Access::nodes(taskflow); + for (auto& worker : frame.d->taskflow_workers) { + const auto required = worker.tasks.size() + graph.nodes.size(); + if (worker.tasks.capacity() < required) worker.tasks.reserve(required); + } graph.submitted_ms = std::chrono::duration( Clock::now() - frame.d->created_at).count(); frame.d->taskflow_graphs.push_back(std::move(graph)); diff --git a/kernel/src/kernel/frame.hpp b/kernel/src/kernel/frame.hpp index aae8a11..c09e871 100644 --- a/kernel/src/kernel/frame.hpp +++ b/kernel/src/kernel/frame.hpp @@ -109,14 +109,9 @@ struct Taskflow_Task_Trace { double finished_ms{}; /* Observer on_exit 进入,即任务体已经结束的时间。 */ double completed_ms{}; /* Observer on_exit 与按帧追踪写入全部结束的时间。 */ double duration_ms{}; /* 仅任务体 started 到 finished 的持续时间。 */ - double cpu_duration_ms{}; /* 任务体独占当前 worker 片段的线程 CPU 时间;cooperative corun 期间不计入。 */ - std::uint64_t cpu_cycles{}; /* Windows QueryThreadCycleTime 的独占 CPU 周期;用于短任务 CPU 活动判定,不直接换算秒。 */ double cooperative_wait_ms{}; /* Task_Graph::corun/corun_until 主动让出 Worker 的墙钟时间。 */ - bool cpu_time_coarse{}; /* 当前平台的线程 CPU 时间源是否为低分辨率计费时钟(Windows GetThreadTimes)。 */ double observer_entry_ms{}; /* on_entry 诊断本身的耗时。 */ double observer_exit_ms{}; /* on_exit 诊断与按帧追踪写入的耗时。 */ - double observer_entry_cpu_ms{}; /* on_entry 诊断实际消耗的 worker CPU 时间。 */ - double observer_exit_cpu_ms{}; /* on_exit 诊断实际消耗的 worker CPU 时间。 */ double ready_ms{}; /* 前驱完成或根 run 提交后的估算就绪时间。 */ double queue_wait_ms{}; /* ready 到 entered 的估算 Executor 排队时间。 */ }; diff --git a/kernel/src/kernel/render_common.cpp b/kernel/src/kernel/render_common.cpp index fcc7efc..71fba57 100644 --- a/kernel/src/kernel/render_common.cpp +++ b/kernel/src/kernel/render_common.cpp @@ -72,32 +72,6 @@ std::uint64_t thread_cpu_cycles(HANDLE thread) noexcept { : 0; } #endif -std::uint64_t current_thread_cpu_ns() noexcept { -#if defined(_WIN32) - return thread_cpu_ns(GetCurrentThread()); -#elif defined(CLOCK_THREAD_CPUTIME_ID) - timespec value{}; - if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &value) != 0) return 0; - return static_cast(value.tv_sec) * 1'000'000'000ULL + - static_cast(value.tv_nsec); -#else - return 0; -#endif -} -std::uint64_t current_thread_cpu_cycles() noexcept { -#if defined(_WIN32) - return thread_cpu_cycles(GetCurrentThread()); -#else - return 0; -#endif -} -constexpr bool thread_cpu_time_is_coarse() noexcept { -#if defined(_WIN32) - return true; -#else - return false; -#endif -} struct Task_Observer : public tf::ObserverInterface { private: using Clock = std::chrono::steady_clock; @@ -120,9 +94,9 @@ private: std::atomic_uint64_t active_task_hash{}; std::atomic_uint64_t active_task_started_ns{}; std::atomic_uint64_t active_segment_started_ns{}; - std::atomic_uint64_t active_segment_cpu_started_ns{}; #if defined(_WIN32) std::atomic_uintptr_t native_thread_handle{}; /* Watchdog 只读的真实 Worker 线程句柄。 */ + std::atomic_uint64_t cpu_time_origin_ns{}; /* 首次进入 Worker 时的累计线程 CPU,读取侧据此计算观测期增量。 */ std::atomic_uint64_t active_cpu_cycles{}; /* 连续片段最近一次采样的 Worker CPU 周期。 */ std::atomic_uint64_t active_cpu_progress_ns{}; /* CPU 周期最后前进的墙钟时刻。 */ #endif @@ -130,32 +104,19 @@ private: std::atomic_bool active_task_reported{}; std::atomic_uint64_t task_time_ns{}; std::atomic_uint64_t busy_time_ns{}; - std::atomic_uint64_t cpu_time_ns{}; std::atomic_uint64_t min_task_time_ns{std::numeric_limits::max()}; std::atomic_uint64_t max_task_time_ns{}; - std::atomic_size_t max_predecessors{}; - std::atomic_size_t max_successors{}; - std::atomic_size_t max_strong_dependencies{}; - std::atomic_size_t max_weak_dependencies{}; std::atomic_uint64_t first_task_time_ns{}; std::atomic_uint64_t last_task_time_ns{}; std::atomic_uint64_t longest_task_time_ns{}; std::atomic_size_t longest_task_hash{}; std::atomic longest_task_type{tf::TaskType::UNDEFINED}; - std::atomic> longest_task_name{}; }; struct Start_Record { Clock::time_point entered{}; /* Observer on_entry 进入时间。 */ Clock::time_point started{}; /* on_entry 完成、任务体即将执行的时间。 */ Clock::time_point segment_started{}; /* 当前连续独占 Worker 片段的起点。 */ std::uint64_t maximum_segment_ns{}; /* 已结束连续独占片段的最大墙钟。 */ - std::uint64_t cpu_entered_ns{}; /* on_entry 进入时的 worker CPU 时间。 */ - std::uint64_t cpu_started_ns{}; /* 任务体开始前的 worker CPU 时间,仅用于 Observer entry 统计。 */ - std::uint64_t cpu_segment_started_ns{}; /* 当前任务独占 Worker 片段的线程 CPU 起点。 */ - bool cpu_segment_active{}; /* CPU 累计值本身允许为 0,不能拿 0 当未启动哨兵。 */ - std::uint64_t cpu_duration_ns{}; /* 已累计的任务独占 Worker CPU;嵌套 corun/子任务不计入。 */ - std::uint64_t cpu_cycle_segment_started{}; /* Windows 当前独占片段的 QueryThreadCycleTime 起点。 */ - std::uint64_t cpu_cycles{}; /* Windows 已累计的任务独占 CPU 周期。 */ Clock::time_point cooperative_wait_started{}; /* 主动 corun 让出 Worker 的墙钟起点。 */ std::uint64_t cooperative_wait_ns{}; /* 已累计 cooperative wait 墙钟。 */ Render_Frame* frame{}; /* 进入任务时唯一活动的按帧捕获。 */ @@ -167,7 +128,6 @@ private: }; std::vector> starts; std::vector worker_busy_starts; - std::vector worker_cpu_starts; std::unique_ptr worker_statistics; std::size_t worker_statistics_count{}; std::uint64_t worker_occupation_limit_ns{}; /* 单节点连续非 CPU 等待 Worker 的上限。 */ @@ -278,41 +238,6 @@ private: } } } - static void close_cpu_segment( - Start_Record& active, std::uint64_t cpu_now_ns, - std::uint64_t cycle_now) noexcept { - if (!active.frame || !active.cpu_segment_active) return; - if (cpu_now_ns >= active.cpu_segment_started_ns) - active.cpu_duration_ns += - cpu_now_ns - active.cpu_segment_started_ns; -#if defined(_WIN32) - if (cycle_now >= active.cpu_cycle_segment_started) - active.cpu_cycles += cycle_now - active.cpu_cycle_segment_started; -#else - static_cast(cycle_now); -#endif - active.cpu_segment_started_ns = 0; - active.cpu_cycle_segment_started = 0; - active.cpu_segment_active = false; - } - static void close_cpu_segment(Start_Record& active) noexcept { - if (!active.frame || !active.cpu_segment_active) return; - close_cpu_segment(active, current_thread_cpu_ns(), - current_thread_cpu_cycles()); - } - static void open_cpu_segment( - Start_Record& active, std::uint64_t cpu_now_ns, - std::uint64_t cycle_now) noexcept { - if (!active.frame) return; - active.cpu_segment_started_ns = cpu_now_ns; - active.cpu_cycle_segment_started = cycle_now; - active.cpu_segment_active = true; - } - static void open_cpu_segment(Start_Record& active) noexcept { - if (!active.frame) return; - open_cpu_segment(active, current_thread_cpu_ns(), - current_thread_cpu_cycles()); - } void pause_worker(std::size_t worker) noexcept { if (worker >= starts.size() || starts[worker].empty()) return; const auto now = Clock::now(); @@ -324,15 +249,12 @@ private: active.maximum_segment_ns = std::max( active.maximum_segment_ns, elapsed); } - close_cpu_segment(active); active.segment_started = {}; if (active.cooperative_wait_started == Clock::time_point{}) active.cooperative_wait_started = now; active.cooperatively_suspended = true; worker_statistics[worker].active_segment_started_ns.store( 0, std::memory_order_release); - worker_statistics[worker].active_segment_cpu_started_ns.store( - 0, std::memory_order_release); #if defined(_WIN32) worker_statistics[worker].active_cpu_cycles.store( 0, std::memory_order_release); @@ -352,17 +274,11 @@ private: } active.cooperatively_suspended = false; active.segment_started = now; - open_cpu_segment(active); worker_statistics[worker].active_segment_started_ns.store( clock_ns(now), std::memory_order_release); - worker_statistics[worker].active_segment_cpu_started_ns.store( - current_thread_cpu_ns(), std::memory_order_release); #if defined(_WIN32) - const auto handle = worker_statistics[worker].native_thread_handle.load( - std::memory_order_acquire); - worker_statistics[worker].active_cpu_cycles.store( - thread_cpu_cycles(reinterpret_cast(handle)), - std::memory_order_release); + worker_statistics[worker].active_cpu_cycles.store(0, + std::memory_order_release); worker_statistics[worker].active_cpu_progress_ns.store( clock_ns(now), std::memory_order_release); #endif @@ -392,10 +308,9 @@ public: void set_up(std::size_t workers) override { starts.resize(workers); worker_busy_starts.resize(workers); - worker_cpu_starts.resize(workers); worker_statistics = std::make_unique(workers); worker_statistics_count = workers; - for (auto& worker : starts) worker.reserve(8); + for (auto& worker : starts) worker.reserve(32); watchdog_thread = std::thread([this] { run_watchdog(); }); @@ -412,12 +327,11 @@ public: GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &duplicated, 0, FALSE, DUPLICATE_SAME_ACCESS)) { - std::uintptr_t expected{}; - if (!worker_state.native_thread_handle.compare_exchange_strong( - expected, reinterpret_cast(duplicated), - std::memory_order_release, - std::memory_order_relaxed)) - CloseHandle(duplicated); + worker_state.cpu_time_origin_ns.store( + thread_cpu_ns(duplicated), std::memory_order_relaxed); + worker_state.native_thread_handle.store( + reinterpret_cast(duplicated), + std::memory_order_release); } } #endif @@ -429,19 +343,16 @@ public: now - parent.segment_started).count()); parent.maximum_segment_ns = std::max( parent.maximum_segment_ns, elapsed); - close_cpu_segment(parent); parent.segment_started = {}; } } - if (worker_starts.empty()) { - worker_busy_starts[worker.id()] = now; - worker_cpu_starts[worker.id()] = current_thread_cpu_ns(); - } + if (worker_starts.empty()) worker_busy_starts[worker.id()] = now; + const auto queue_size = worker.queue_size(); + const auto queue_capacity = worker.queue_capacity(); Start_Record record{}; record.entered = now; - record.cpu_entered_ns = current_thread_cpu_ns(); - record.queue_size = worker.queue_size(); - record.queue_capacity = worker.queue_capacity(); + record.queue_size = queue_size; + record.queue_capacity = queue_capacity; record.native_id = static_cast(task.hash_value()); record.type = task.type(); worker_starts.push_back(std::move(record)); @@ -450,55 +361,30 @@ public: const auto active_depth = worker_state.active_depth.fetch_add( 1, std::memory_order_relaxed) + 1; update_max(worker_state.peak_active_depth, active_depth); - worker_state.current_queue_size.store(worker.queue_size(), std::memory_order_relaxed); - worker_state.current_queue_capacity.store(worker.queue_capacity(), std::memory_order_relaxed); + worker_state.current_queue_size.store(queue_size, std::memory_order_relaxed); + worker_state.current_queue_capacity.store(queue_capacity, std::memory_order_relaxed); worker_state.active_task_hash.store(task.hash_value(), std::memory_order_relaxed); worker_state.active_task_started_ns.store(clock_ns(now), std::memory_order_relaxed); worker_state.active_segment_started_ns.store(clock_ns(now), std::memory_order_release); - worker_state.active_segment_cpu_started_ns.store( - current_thread_cpu_ns(), std::memory_order_release); #if defined(_WIN32) - const auto native_handle = worker_state.native_thread_handle.load( - std::memory_order_acquire); - worker_state.active_cpu_cycles.store( - thread_cpu_cycles(reinterpret_cast(native_handle)), - std::memory_order_release); + worker_state.active_cpu_cycles.store(0, std::memory_order_release); worker_state.active_cpu_progress_ns.store( clock_ns(now), std::memory_order_release); #endif worker_state.active_task_type.store(task.type(), std::memory_order_relaxed); worker_state.active_task_reported.store(false, std::memory_order_relaxed); - update_max(worker_state.peak_queue_size, worker.queue_size()); - update_max(worker_state.max_queue_capacity, worker.queue_capacity()); - update_max(worker_state.max_predecessors, task.num_predecessors()); - update_max(worker_state.max_successors, task.num_successors()); - update_max(worker_state.max_strong_dependencies, - task.num_strong_dependencies()); - update_max(worker_state.max_weak_dependencies, - task.num_weak_dependencies()); + update_max(worker_state.peak_queue_size, queue_size); + update_max(worker_state.max_queue_capacity, queue_capacity); if (!task.name().empty()) worker_state.named_task_count.fetch_add(1, std::memory_order_relaxed); update_first(worker_state.first_task_time_ns, clock_ns(now)); - const auto task_cpu_started_ns = current_thread_cpu_ns(); - const auto task_cpu_cycle_started = worker_starts.back().frame - ? current_thread_cpu_cycles() : 0; - worker_starts.back().cpu_started_ns = task_cpu_started_ns; - worker_starts.back().cpu_segment_started_ns = task_cpu_started_ns; - worker_starts.back().cpu_cycle_segment_started = - task_cpu_cycle_started; - worker_starts.back().cpu_segment_active = - worker_starts.back().frame != nullptr; worker_starts.back().started = Clock::now(); worker_starts.back().segment_started = worker_starts.back().started; } void on_exit(tf::WorkerView worker, tf::TaskView task) override { const auto finished = Clock::now(); - const auto cpu_finished_ns = current_thread_cpu_ns(); auto& worker_starts = starts[worker.id()]; auto& active = worker_starts.back(); - const auto cpu_finished_cycles = active.frame - ? current_thread_cpu_cycles() : 0; - close_cpu_segment(active, cpu_finished_ns, cpu_finished_cycles); if (active.cooperative_wait_started != Clock::time_point{}) { active.cooperative_wait_ns += static_cast( std::chrono::duration_cast( @@ -538,9 +424,6 @@ public: longest, elapsed, std::memory_order_relaxed)) { worker_state.longest_task_hash.store(task.hash_value(), std::memory_order_relaxed); worker_state.longest_task_type.store(task.type(), std::memory_order_relaxed); - worker_state.longest_task_name.store( - std::make_shared(task.name()), - std::memory_order_release); } worker_state.active_depth.fetch_sub(1, std::memory_order_relaxed); std::optional trace_task; @@ -550,39 +433,27 @@ public: *start.frame, worker.id(), static_cast(task.hash_value()), start.queue_size, start.queue_capacity, start.entered, - start.started, finished, start.cpu_entered_ns, - start.cpu_started_ns, start.cpu_duration_ns, - start.cpu_cycles, start.cooperative_wait_ns, - thread_cpu_time_is_coarse()); + start.started, finished, start.cooperative_wait_ns); } catch (...) { /* Observer 不能让按需诊断分配失败改变渲染任务的完成语义。 */ } } - const auto cpu_completed_ns = current_thread_cpu_ns(); const auto completed = Clock::now(); if (start.frame) { if (trace_task) detail::Taskflow_Frame_Access::finish_task_observer( - *start.frame, worker.id(), *trace_task, completed, - cpu_finished_ns, cpu_completed_ns); + *start.frame, worker.id(), *trace_task, completed); } if (worker_starts.empty()) { auto busy = static_cast( std::chrono::duration_cast( completed - worker_busy_starts[worker.id()]).count()); worker_state.busy_time_ns.fetch_add(busy, std::memory_order_relaxed); - const auto cpu_started = worker_cpu_starts[worker.id()]; - const auto cpu = cpu_completed_ns >= cpu_started - ? cpu_completed_ns - cpu_started - : 0; - worker_state.cpu_time_ns.fetch_add(cpu, std::memory_order_relaxed); worker_state.active_task_hash.store(0, std::memory_order_relaxed); worker_state.active_task_started_ns.store(0, std::memory_order_relaxed); worker_state.active_segment_started_ns.store(0, std::memory_order_release); - worker_state.active_segment_cpu_started_ns.store( - 0, std::memory_order_release); #if defined(_WIN32) worker_state.active_cpu_cycles.store(0, std::memory_order_release); worker_state.active_cpu_progress_ns.store(0, @@ -601,8 +472,6 @@ public: if (parent.cooperatively_suspended) { worker_state.active_segment_started_ns.store( 0, std::memory_order_release); - worker_state.active_segment_cpu_started_ns.store( - 0, std::memory_order_release); #if defined(_WIN32) worker_state.active_cpu_cycles.store(0, std::memory_order_release); @@ -611,20 +480,13 @@ public: #endif } else { - const auto parent_cpu_started_ns = current_thread_cpu_ns(); - const auto parent_cpu_cycle_started = parent.frame - ? current_thread_cpu_cycles() : 0; const auto parent_resumed = Clock::now(); parent.segment_started = parent_resumed; - open_cpu_segment(parent, parent_cpu_started_ns, - parent_cpu_cycle_started); worker_state.active_segment_started_ns.store( clock_ns(parent_resumed), std::memory_order_release); - worker_state.active_segment_cpu_started_ns.store( - parent_cpu_started_ns, std::memory_order_release); #if defined(_WIN32) - worker_state.active_cpu_cycles.store( - parent_cpu_cycle_started, std::memory_order_release); + worker_state.active_cpu_cycles.store(0, + std::memory_order_release); worker_state.active_cpu_progress_ns.store( clock_ns(parent_resumed), std::memory_order_release); #endif @@ -657,10 +519,6 @@ public: state.named_task_count = 0; state.peak_observed_worker_queue_size = 0; state.max_observed_worker_queue_capacity = 0; - state.max_predecessors = 0; - state.max_successors = 0; - state.max_strong_dependencies = 0; - state.max_weak_dependencies = 0; state.total_task_time_ns = 0; state.worker_busy_time_ns = 0; state.worker_cpu_time_ns = 0; @@ -696,7 +554,17 @@ public: : std::string{}; target.task_time_ns = source.task_time_ns.load(std::memory_order_relaxed); target.busy_time_ns = source.busy_time_ns.load(std::memory_order_relaxed); - target.cpu_time_ns = source.cpu_time_ns.load(std::memory_order_relaxed); +#if defined(_WIN32) + const auto native_handle = source.native_thread_handle.load( + std::memory_order_acquire); + const auto cpu_origin = source.cpu_time_origin_ns.load( + std::memory_order_acquire); + const auto cpu_now = thread_cpu_ns( + reinterpret_cast(native_handle)); + target.cpu_time_ns = cpu_now >= cpu_origin ? cpu_now - cpu_origin : 0; +#else + target.cpu_time_ns = 0; +#endif target.non_cpu_time_ns = target.busy_time_ns > target.cpu_time_ns ? target.busy_time_ns - target.cpu_time_ns : 0; @@ -724,16 +592,6 @@ public: state.max_observed_worker_queue_capacity = std::max( state.max_observed_worker_queue_capacity, target.max_observed_queue_capacity); - state.max_predecessors = std::max(state.max_predecessors, - source.max_predecessors.load(std::memory_order_relaxed)); - state.max_successors = std::max(state.max_successors, - source.max_successors.load(std::memory_order_relaxed)); - state.max_strong_dependencies = std::max( - state.max_strong_dependencies, - source.max_strong_dependencies.load(std::memory_order_relaxed)); - state.max_weak_dependencies = std::max( - state.max_weak_dependencies, - source.max_weak_dependencies.load(std::memory_order_relaxed)); state.total_task_time_ns += target.task_time_ns; state.worker_busy_time_ns += target.busy_time_ns; state.worker_cpu_time_ns += target.cpu_time_ns; @@ -765,8 +623,8 @@ public: state.longest_task_time_ns = longest; state.longest_task_hash = source.longest_task_hash.load( std::memory_order_relaxed); - const auto name = source.longest_task_name.load( - std::memory_order_acquire); + const auto name = detail::taskflow_node_name( + state.longest_task_hash); state.longest_task_name = name ? *name : std::string{}; state.longest_task_type = std::string(tf::to_string( source.longest_task_type.load(std::memory_order_relaxed))); diff --git a/kernel/src/kernel/render_common.hpp b/kernel/src/kernel/render_common.hpp index e6938c3..7ead39c 100644 --- a/kernel/src/kernel/render_common.hpp +++ b/kernel/src/kernel/render_common.hpp @@ -80,10 +80,6 @@ struct Task_Runtime_State : State_Type { std::size_t named_task_count{}; std::size_t peak_observed_worker_queue_size{}; std::size_t max_observed_worker_queue_capacity{}; - std::size_t max_predecessors{}; - std::size_t max_successors{}; - std::size_t max_strong_dependencies{}; - std::size_t max_weak_dependencies{}; std::size_t longest_task_hash{}; std::string longest_task_name; std::string longest_task_type; diff --git a/web_server/src/Plot.cpp b/web_server/src/Plot.cpp index a906553..d07bccc 100644 --- a/web_server/src/Plot.cpp +++ b/web_server/src/Plot.cpp @@ -341,14 +341,9 @@ nlohmann::json taskflow_trace_json( {"started_ms", task.started_ms}, {"finished_ms", task.finished_ms}, {"completed_ms", task.completed_ms}, {"duration_ms", task.duration_ms}, - {"cpu_duration_ms", task.cpu_duration_ms}, - {"cpu_cycles", task.cpu_cycles}, {"cooperative_wait_ms", task.cooperative_wait_ms}, - {"cpu_time_coarse", task.cpu_time_coarse}, {"observer_entry_ms", task.observer_entry_ms}, {"observer_exit_ms", task.observer_exit_ms}, - {"observer_entry_cpu_ms", task.observer_entry_cpu_ms}, - {"observer_exit_cpu_ms", task.observer_exit_cpu_ms}, {"queue_wait_ms", task.queue_wait_ms}}); } return { diff --git a/web_server/src/Web_Server.cpp b/web_server/src/Web_Server.cpp index 2fe97d2..d5ee505 100644 --- a/web_server/src/Web_Server.cpp +++ b/web_server/src/Web_Server.cpp @@ -84,10 +84,6 @@ nlohmann::json taskflow_runtime_json() { {"named_tasks", state.named_task_count}, {"peak_worker_queue_size", state.peak_observed_worker_queue_size}, {"max_worker_queue_capacity", state.max_observed_worker_queue_capacity}, - {"max_predecessors", state.max_predecessors}, - {"max_successors", state.max_successors}, - {"max_strong_dependencies", state.max_strong_dependencies}, - {"max_weak_dependencies", state.max_weak_dependencies}, {"longest_task", {{"native_id", std::to_string(state.longest_task_hash)}, {"name", state.longest_task_name}, {"type", state.longest_task_type}, diff --git a/webapp_gallery/src/app.tsx b/webapp_gallery/src/app.tsx index 1b87ff8..2e8439b 100644 --- a/webapp_gallery/src/app.tsx +++ b/webapp_gallery/src/app.tsx @@ -81,9 +81,8 @@ type Taskflow_Graph_Trace = {stage: string; name: string; submitted_ms: number; completed: boolean; nodes: Taskflow_Node_Trace[]}; type Taskflow_Execution_Trace = {native_id: string; node_id: string; worker_id: number; worker_queue_size: number; worker_queue_capacity: number; ready_ms: number; entered_ms: number; started_ms: number; finished_ms: number; - completed_ms: number; duration_ms: number; cpu_duration_ms: number; cpu_cycles: number; cooperative_wait_ms: number; - cpu_time_coarse: boolean; observer_entry_ms: number; observer_exit_ms: number; - observer_entry_cpu_ms: number; observer_exit_cpu_ms: number; queue_wait_ms: number}; + completed_ms: number; duration_ms: number; cooperative_wait_ms: number; + observer_entry_ms: number; observer_exit_ms: number; queue_wait_ms: number}; type Frame_Policy_State = { generation: number; configuration: {mode: Frame_Pacing_Mode; render_enabled: boolean; video_enabled: boolean; fixed_rate_fps: number}; @@ -113,8 +112,7 @@ type Taskflow_Type_State = {name: string; count: number; total_time_ns: number; type Taskflow_Runtime_State = {protocol: "aethera.taskflow.runtime"; version: 1; worker_count: number; active_topologies: number; active_taskflows: number; peak_active_taskflows: number; completed_taskflows: number; failed_taskflows: number; active_tasks: number; peak_active_tasks: number; active_workers: number; peak_active_workers: number; observed_tasks: number; - named_tasks: number; peak_worker_queue_size: number; max_worker_queue_capacity: number; max_predecessors: number; - max_successors: number; max_strong_dependencies: number; max_weak_dependencies: number; + named_tasks: number; peak_worker_queue_size: number; max_worker_queue_capacity: number; longest_task: {native_id: string; name: string; type: string; time_ns: number}; total_task_time_ns: number; worker_busy_time_ns: number; worker_cpu_time_ns: number; observed_wall_time_ns: number; worker_utilization: number; worker_cpu_utilization: number; @@ -1203,20 +1201,6 @@ function nanoseconds(value: number) { return milliseconds(value / 1_000_000); } -function cpu_cycles(value: number) { - if (!Number.isFinite(value) || value <= 0) return "--"; - if (value >= 1_000_000_000) return `${(value / 1_000_000_000).toFixed(2)} Gcy`; - if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(2)} Mcy`; - if (value >= 1_000) return `${(value / 1_000).toFixed(1)} Kcy`; - return `${Math.round(value)} cy`; -} - -function task_cpu_label(sample: Taskflow_Execution_Trace) { - if (sample.cpu_time_coarse && sample.cpu_duration_ms === 0 && sample.cpu_cycles > 0) - return "低于系统 CPU 计时分辨率"; - return milliseconds(sample.cpu_duration_ms); -} - type Taskflow_Node_Phase = "prepare" | "paint" | "control" | "completion" | "other"; function taskflow_node_phase(name: string): Taskflow_Node_Phase { @@ -1340,7 +1324,7 @@ function Taskflow_Node_Label({node, sample, summary, state, level}: { node, execution: sample ?? null, aggregate: summary ? { present: summary.present, executed: summary.executed, frames: summary.frames, - duration: summary.duration, queue: summary.queue, cpu: summary.cpu, observer: summary.observer, + duration: summary.duration, queue: summary.queue, observer: summary.observer, workers: summary.workers, stability: summary.stability } : null, state: state ?? null @@ -1375,8 +1359,7 @@ function Taskflow_Node_Label({node, sample, summary, state, level}: { {node.type} · 样本 {summary.executed}/{summary.frames} · W {summary.workers.join(", ") || "--"} 执行 {milliseconds(summary.duration.average)} ± {milliseconds(summary.duration.variability)} · P95 {milliseconds(summary.duration.p95)} 排队 {milliseconds(summary.queue.average)} ± {milliseconds(summary.queue.variability)} · P99 {milliseconds(summary.queue.p99)} - 线程 CPU{summary.cpu_time_coarse ? "(低分辨率)" : ""} {milliseconds(summary.cpu.average)} · CPU 活动 {cpu_cycles(summary.cycles.average)} - 协作等待 {milliseconds(summary.cooperative_wait.average)} · Observer {milliseconds(summary.observer.average)} + 协作等待 {milliseconds(summary.cooperative_wait.average)} · Observer 墙钟 {milliseconds(summary.observer.average)} : node.type === "diagnostic" ? <> 运行时收尾 开始 {sample ? `+${sample.started_ms.toFixed(3)} ms` : "--"} · 结束 {sample ? `+${sample.finished_ms.toFixed(3)} ms` : "--"} @@ -1385,8 +1368,7 @@ function Taskflow_Node_Label({node, sample, summary, state, level}: { {node.type} · W{sample?.worker_id ?? "--"} 就绪 {sample ? `+${sample.ready_ms.toFixed(3)} ms` : "--"} · 开始 {sample ? `+${sample.started_ms.toFixed(3)} ms` : "--"} 任务体 {sample ? milliseconds(duration) : "未执行"} · 排队 {sample ? milliseconds(wait) : "--"} - 线程 CPU {sample ? task_cpu_label(sample) : "--"}{sample?.cpu_time_coarse ? "(低分辨率)" : ""} · CPU 活动 {sample ? cpu_cycles(sample.cpu_cycles) : "--"} - 协作等待 {sample ? milliseconds(sample.cooperative_wait_ms) : "--"} · 未归因墙时 {sample ? `${sample.cpu_time_coarse ? "≈ " : ""}${milliseconds(Math.max(0, duration - sample.cooperative_wait_ms - sample.cpu_duration_ms))}` : "--"} + 协作等待 {sample ? milliseconds(sample.cooperative_wait_ms) : "--"} · 独占任务体 {sample ? milliseconds(Math.max(0, duration - sample.cooperative_wait_ms)) : "--"} Observer {sample ? milliseconds(sample.observer_entry_ms + sample.observer_exit_ms) : "--"}} {Object.entries(node.attributes ?? {}).map(([key, value]) => {key}:{value})} ; @@ -1434,23 +1416,19 @@ function taskflow_graph_analysis(graph: Taskflow_Graph_Trace, executions: Taskfl const execution_time = leaf_rows.reduce((sum, row) => sum + row.duration_ms, 0); const module_envelope_time = module_rows.reduce((sum, row) => sum + row.duration_ms, 0); const diagnostic_time = diagnostic_rows.reduce((sum, row) => sum + row.duration_ms, 0); - const cpu_execution_time = leaf_rows.reduce((sum, row) => sum + row.cpu_duration_ms, 0); const cooperative_wait_time = leaf_rows.reduce((sum, row) => sum + row.cooperative_wait_ms, 0); - const cpu_cycles_total = leaf_rows.reduce((sum, row) => sum + row.cpu_cycles, 0); - const cpu_time_coarse = leaf_rows.some(row => row.cpu_time_coarse); - const unattributed_wall_time = Math.max(0, execution_time - cooperative_wait_time - cpu_execution_time); + const exclusive_body_time = Math.max(0, execution_time - cooperative_wait_time); const observer_entry_time = task_rows.reduce((sum, row) => sum + row.observer_entry_ms, 0); const observer_exit_time = task_rows.reduce((sum, row) => sum + row.observer_exit_ms, 0); - const observer_cpu_time = task_rows.reduce((sum, row) => sum + row.observer_entry_cpu_ms + row.observer_exit_cpu_ms, 0); const queue_time = task_rows.reduce((sum, row) => sum + row.queue_wait_ms, 0); const first_entered = task_rows.length ? Math.min(...task_rows.map(row => row.entered_ms)) : graph.submitted_ms; const last_completed = task_rows.length ? Math.max(...task_rows.map(row => row.completed_ms)) : graph.finished_ms; const longest = task_rows.reduce( (result, row) => !result || row.duration_ms > result.duration_ms ? row : result, null); - const longest_unattributed = task_rows.reduce((result, row) => { - const value = Math.max(0, row.duration_ms - row.cooperative_wait_ms - row.cpu_duration_ms); + const longest_exclusive = task_rows.reduce((result, row) => { + const value = Math.max(0, row.duration_ms - row.cooperative_wait_ms); const previous = result - ? Math.max(0, result.duration_ms - result.cooperative_wait_ms - result.cpu_duration_ms) + ? Math.max(0, result.duration_ms - result.cooperative_wait_ms) : -1; return value > previous ? row : result; }, null); @@ -1510,8 +1488,8 @@ function taskflow_graph_analysis(graph: Taskflow_Graph_Trace, executions: Taskfl for (const level of levels.values()) width_by_level.set(level, (width_by_level.get(level) ?? 0) + 1); return { rows, task_rows, leaf_rows, module_rows, diagnostic_rows, levels, wall_time, execution_time, - module_envelope_time, diagnostic_time, diagnostic_wall_time, cpu_execution_time, cooperative_wait_time, - cpu_cycles_total, cpu_time_coarse, unattributed_wall_time, observer_entry_time, observer_cpu_time, + module_envelope_time, diagnostic_time, diagnostic_wall_time, cooperative_wait_time, + exclusive_body_time, observer_entry_time, observer_exit_time, queue_time, body_wall_time, observer_wall_time, idle_wall_time, initial_wait, completion_tail, unattributed_completion_tail, internal_idle_time: Math.max(0, idle_wall_time - initial_wait - unattributed_completion_tail), @@ -1521,12 +1499,11 @@ function taskflow_graph_analysis(graph: Taskflow_Graph_Trace, executions: Taskfl diagnostic_node_count: graph.nodes.filter(node => node.type.toLowerCase() === "diagnostic").length, layer_count: width_by_level.size, parallel_layer_count: [...width_by_level.values()].filter(width => width > 1).length, - longest, longest_unattributed, + longest, longest_exclusive, longest_duration: longest?.duration_ms ?? 0, - longest_unattributed_duration: longest_unattributed - ? Math.max(0, longest_unattributed.duration_ms - - longest_unattributed.cooperative_wait_ms - - longest_unattributed.cpu_duration_ms) + longest_exclusive_duration: longest_exclusive + ? Math.max(0, longest_exclusive.duration_ms - + longest_exclusive.cooperative_wait_ms) : 0 }; } @@ -1539,15 +1516,12 @@ const taskflow_graph_metric_definitions = [ {key: "module_envelope_time", label: "Module 包络总和", unit: "milliseconds", description: "每帧所有 Taskflow Module Observer 包络之和。"}, {key: "diagnostic_time", label: "收尾诊断总和", unit: "milliseconds", description: "Executor 返回后的运行计数、状态发布、Observer graph 退役与完成记录墙钟之和。"}, {key: "diagnostic_wall_time", label: "收尾诊断并集", unit: "milliseconds", description: "Topology 尾部被明确归因到诊断收尾节点的时间区间并集。"}, - {key: "cpu_execution_time", label: "叶子任务线程 CPU", unit: "milliseconds", description: "每帧叶子任务独占 Worker 的线程 CPU 时间之和。"}, - {key: "cpu_cycles_total", label: "叶子任务 CPU 活动", unit: "cycles", description: "每帧叶子任务 QueryThreadCycleTime 活动量之和。"}, {key: "cooperative_wait_time", label: "累计协作等待", unit: "milliseconds", description: "每帧 Task_Graph 协作等待墙钟之和。"}, - {key: "unattributed_wall_time", label: "未归因墙时", unit: "milliseconds", description: "任务体墙钟扣除协作等待和线程 CPU 后的守恒余量。"}, + {key: "exclusive_body_time", label: "独占任务体墙钟", unit: "milliseconds", description: "任务体墙钟扣除显式协作让出后的总和。"}, {key: "body_wall_time", label: "任务体墙钟并集", unit: "milliseconds", description: "每帧至少有一个任务体执行的时间区间并集。"}, {key: "observer_wall_time", label: "Observer 独占墙钟", unit: "milliseconds", description: "只有 Observer 活动、没有任务体执行的时间区间。"}, {key: "observer_entry_time", label: "Observer entry 墙钟", unit: "milliseconds", description: "每帧所有 Observer entry 墙钟之和。"}, {key: "observer_exit_time", label: "Observer exit 墙钟", unit: "milliseconds", description: "每帧所有 Observer exit 墙钟之和。"}, - {key: "observer_cpu_time", label: "Observer 实际 CPU", unit: "milliseconds", description: "每帧 Observer entry/exit 真正占用的 Worker CPU 时间。"}, {key: "idle_wall_time", label: "无任务墙钟", unit: "milliseconds", description: "Topology 中没有捕获任务体或 Observer 活动的区间。"}, {key: "queue_time", label: "累计节点排队", unit: "milliseconds", description: "各节点从前驱完成到进入 Worker 的估算等待之和。"}, {key: "initial_wait", label: "首次准入等待", unit: "milliseconds", description: "Topology 提交后首节点进入 Worker 前的等待。"}, @@ -1559,20 +1533,20 @@ const taskflow_graph_metric_definitions = [ {key: "layer_count", label: "依赖层", unit: "count", description: "每帧 DAG 的依赖层数量。"}, {key: "parallel_layer_count", label: "并行层", unit: "count", description: "每帧包含多个可并行节点的依赖层数量。"}, {key: "longest_duration", label: "最长节点执行", unit: "milliseconds", description: "每帧最长执行节点的任务体墙钟。"}, - {key: "longest_unattributed_duration", label: "最长节点未归因墙时", unit: "milliseconds", description: "每帧单节点最大的未归因墙钟。"} + {key: "longest_exclusive_duration", label: "最长独占任务体", unit: "milliseconds", description: "每帧单节点扣除显式协作让出后的最大任务体墙钟。"} ] as const; type Taskflow_Graph_Metric_Key = typeof taskflow_graph_metric_definitions[number]["key"]; type Taskflow_Node_Stability = "stable" | "variable" | "missing" | "long_tail"; type Taskflow_Node_Aggregate = { node: Taskflow_Node_Trace; present: number; executed: number; frames: number; - duration: Distribution_Statistics; queue: Distribution_Statistics; cpu: Distribution_Statistics; - cycles: Distribution_Statistics; cooperative_wait: Distribution_Statistics; cpu_time_coarse: boolean; + duration: Distribution_Statistics; queue: Distribution_Statistics; + cooperative_wait: Distribution_Statistics; observer: Distribution_Statistics; workers: number[]; stability: Taskflow_Node_Stability; }; type Taskflow_Graph_Aggregate = { key: string; graph: Taskflow_Graph_Trace; frames: number; samples: number; topology_variants: number; metrics: Record; - completed_frames: number; cpu_time_coarse_frames: number; + completed_frames: number; nodes: Map; edge_presence: Map; }; @@ -1602,7 +1576,7 @@ function aggregate_taskflow_graph(frames: Taskflow_Frame_Trace[], key: string): .map(graph => ({frame, graph}))); if (!samples.length) return null; type Mutable_Node = {template: Taskflow_Node_Trace; present: number; executed: number; duration: number[]; - queue: number[]; cpu: number[]; cycles: number[]; cooperative_wait: number[]; cpu_time_coarse: boolean; + queue: number[]; cooperative_wait: number[]; observer: number[]; workers: Set}; const accumulated = new Map(); const edges = new Map(); @@ -1610,7 +1584,6 @@ function aggregate_taskflow_graph(frames: Taskflow_Frame_Trace[], key: string): const metric_samples = Object.fromEntries(taskflow_graph_metric_definitions.map( definition => [definition.key, [] as number[]])) as Record; let completed_frames = 0; - let cpu_time_coarse_frames = 0; for (const {frame, graph} of samples) { const native_to_id = new Map(graph.nodes.map(node => [node.native_id, node.id])); const execution = new Map(frame.executions.map(value => [value.native_id, value])); @@ -1618,11 +1591,10 @@ function aggregate_taskflow_graph(frames: Taskflow_Frame_Trace[], key: string): const analysis = taskflow_graph_analysis(graph, frame.executions); for (const definition of taskflow_graph_metric_definitions) metric_samples[definition.key].push(analysis[definition.key]); - if (analysis.cpu_time_coarse) ++cpu_time_coarse_frames; if (graph.completed) ++completed_frames; for (const node of graph.nodes) { const current = accumulated.get(node.id) ?? {template: node, present: 0, executed: 0, - duration: [], queue: [], cpu: [], cycles: [], cooperative_wait: [], cpu_time_coarse: false, + duration: [], queue: [], cooperative_wait: [], observer: [], workers: new Set()}; ++current.present; const sample = execution.get(node.native_id); @@ -1630,10 +1602,7 @@ function aggregate_taskflow_graph(frames: Taskflow_Frame_Trace[], key: string): ++current.executed; current.duration.push(sample.duration_ms); current.queue.push(sample.queue_wait_ms); - current.cpu.push(sample.cpu_duration_ms); - current.cycles.push(sample.cpu_cycles); current.cooperative_wait.push(sample.cooperative_wait_ms); - current.cpu_time_coarse = current.cpu_time_coarse || sample.cpu_time_coarse; current.observer.push(sample.observer_entry_ms + sample.observer_exit_ms); current.workers.add(sample.worker_id); } @@ -1671,8 +1640,7 @@ function aggregate_taskflow_graph(frames: Taskflow_Frame_Trace[], key: string): const node = {...value.template, native_id: id, id, predecessors: predecessors.get(id) ?? [], successors: successors.get(id) ?? []}; nodes.set(id, {node, present: value.present, executed: value.executed, frames: frames.length, - duration, queue, cpu: distribution_statistics(value.cpu), cycles: distribution_statistics(value.cycles), - cooperative_wait: distribution_statistics(value.cooperative_wait), cpu_time_coarse: value.cpu_time_coarse, + duration, queue, cooperative_wait: distribution_statistics(value.cooperative_wait), observer: distribution_statistics(value.observer), workers: [...value.workers].sort((left, right) => left - right), stability}); return node; @@ -1682,24 +1650,23 @@ function aggregate_taskflow_graph(frames: Taskflow_Frame_Trace[], key: string): definition => [definition.key, distribution_statistics(metric_samples[definition.key])])) as Record; return {key, frames: frames.length, samples: samples.length, topology_variants: topology_signatures.size, - metrics, completed_frames, cpu_time_coarse_frames, nodes, edge_presence: edges, + metrics, completed_frames, nodes, edge_presence: edges, graph: {...first, submitted_ms: 0, finished_ms: metrics.wall_time.average, nodes: graph_nodes}}; } -function taskflow_metric_value(value: number, unit: "milliseconds" | "cycles" | "count") { +function taskflow_metric_value(value: number, unit: "milliseconds" | "count") { if (unit === "milliseconds") return milliseconds(value); - if (unit === "cycles") return cpu_cycles(value); return value.toLocaleString("zh-CN", {maximumFractionDigits: 3}); } -function taskflow_variance_value(value: number, unit: "milliseconds" | "cycles" | "count") { +function taskflow_variance_value(value: number, unit: "milliseconds" | "count") { if (!Number.isFinite(value)) return "--"; - const suffix = unit === "milliseconds" ? " ms²" : unit === "cycles" ? " cy²" : ""; + const suffix = unit === "milliseconds" ? " ms²" : ""; return `${value.toLocaleString("zh-CN", {maximumFractionDigits: 6})}${suffix}`; } function taskflow_distribution_value(statistic: Distribution_Statistics, - unit: "milliseconds" | "cycles" | "count") { + unit: "milliseconds" | "count") { return <>均值 {taskflow_metric_value(statistic.average, unit)} · 方差 {taskflow_variance_value(statistic.variance, unit)} · 范围 [{taskflow_metric_value(statistic.minimum, unit)}, {taskflow_metric_value(statistic.maximum, unit)}]; } @@ -1935,7 +1902,6 @@ function Taskflow_Dag({graph, executions, frame, aggregate, components, gallery_ topology_variants: aggregate.topology_variants, metrics: aggregate.metrics, completed_frames: aggregate.completed_frames, - cpu_time_coarse_frames: aggregate.cpu_time_coarse_frames, nodes: Object.fromEntries(aggregate.nodes)} : undefined, executions: executions.filter(value => native_ids.has(value.native_id)), all_executions: frame?.executions ?? executions @@ -2414,7 +2380,7 @@ function Taskflow_Frame_Pane({plot, components}: {plot: Plot; components: Compon
波动节点
{[...aggregate.nodes.values()].filter(node => node.stability === "variable").length}
缺帧节点
{[...aggregate.nodes.values()].filter(node => node.stability === "missing").length}
长尾节点
{[...aggregate.nodes.values()].filter(node => node.stability === "long_tail").length}
-
完成帧 / CPU 粗粒度帧
{aggregate.completed_frames} / {aggregate.cpu_time_coarse_frames}
+
完成帧
{aggregate.completed_frames}
{taskflow_graph_metric_definitions.map(definition => { const statistic = aggregate.metrics[definition.key]; return
@@ -2427,15 +2393,12 @@ function Taskflow_Frame_Pane({plot, components}: {plot: Plot; components: Compon
Topology 墙钟
{milliseconds(graph_analysis.wall_time)}
叶子任务墙钟总和
{milliseconds(graph_analysis.execution_time)}
Module 包络总和
{milliseconds(graph_analysis.module_envelope_time)}
-
叶子任务线程 CPU{graph_analysis.cpu_time_coarse ? "(低分辨率)" : ""}
{milliseconds(graph_analysis.cpu_execution_time)}
-
叶子任务 CPU 活动
{cpu_cycles(graph_analysis.cpu_cycles_total)}
累计协作等待
{milliseconds(graph_analysis.cooperative_wait_time)}
-
未归因墙时{graph_analysis.cpu_time_coarse ? "(估算)" : ""}
{milliseconds(graph_analysis.unattributed_wall_time)}
+
独占任务体墙钟
{milliseconds(graph_analysis.exclusive_body_time)}
任务体墙钟并集
{milliseconds(graph_analysis.body_wall_time)}
Observer 独占墙钟
{milliseconds(graph_analysis.observer_wall_time)}
Observer entry 墙钟
{milliseconds(graph_analysis.observer_entry_time)}
Observer exit 墙钟
{milliseconds(graph_analysis.observer_exit_time)}
-
Observer 实际 CPU
{milliseconds(graph_analysis.observer_cpu_time)}
无任务墙钟
{milliseconds(graph_analysis.idle_wall_time)}
累计节点排队
{milliseconds(graph_analysis.queue_time)}
首次准入等待
{milliseconds(graph_analysis.initial_wait)}
@@ -2451,7 +2414,7 @@ function Taskflow_Frame_Pane({plot, components}: {plot: Plot; components: Compon
实际最大并行
{graph_analysis.maximum_parallelism}
依赖层 / 并行层
{graph_analysis.layer_count} / {graph_analysis.parallel_layer_count}
最长执行节点
{graph_analysis.longest ? milliseconds(graph_analysis.longest.duration_ms) : "--"}
-
最长未归因墙时节点
{graph_analysis.longest_unattributed ? `${taskflow_node_name(graph_analysis.longest_unattributed.node_id.split("/").at(-1) ?? graph_analysis.longest_unattributed.node_id)} · ${graph_analysis.longest_unattributed.cpu_time_coarse ? "≈ " : ""}${milliseconds(Math.max(0, graph_analysis.longest_unattributed.duration_ms - graph_analysis.longest_unattributed.cooperative_wait_ms - graph_analysis.longest_unattributed.cpu_duration_ms))}` : "--"}
+
最长独占任务体节点
{graph_analysis.longest_exclusive ? `${taskflow_node_name(graph_analysis.longest_exclusive.node_id.split("/").at(-1) ?? graph_analysis.longest_exclusive.node_id)} · ${milliseconds(Math.max(0, graph_analysis.longest_exclusive.duration_ms - graph_analysis.longest_exclusive.cooperative_wait_ms))}` : "--"}
状态
{graph.completed ? "完成" : "未完成"}
set_fullscreen_view(value ? "dag" : null)}