优化了 还是卡
This commit is contained in:
@@ -87,7 +87,8 @@ type Taskflow_Frame_Response = {protocol: "aethera.taskflow.frames"; version: 1;
|
||||
captured: number; complete: boolean; frames: Taskflow_Frame_Trace[]};
|
||||
type Taskflow_Worker_State = {id: number; task_count: number; current_queue_size: number; current_queue_capacity: number;
|
||||
peak_queue_size: number; max_queue_capacity: number; active_task: {native_id: string; type: string; time_ns: number};
|
||||
task_time_ns: number; busy_time_ns: number; idle_time_ns: number; min_task_time_ns: number; max_task_time_ns: number; utilization: number};
|
||||
task_time_ns: number; busy_time_ns: number; cpu_time_ns: number; non_cpu_time_ns: number; idle_time_ns: number;
|
||||
min_task_time_ns: number; max_task_time_ns: number; utilization: number; cpu_utilization: number};
|
||||
type Taskflow_Type_State = {name: string; count: number; total_time_ns: number; min_time_ns: number; max_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;
|
||||
@@ -95,7 +96,8 @@ type Taskflow_Runtime_State = {protocol: "aethera.taskflow.runtime"; version: 1;
|
||||
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;
|
||||
longest_task: {native_id: string; name: string; type: string; time_ns: number}; total_task_time_ns: number;
|
||||
worker_busy_time_ns: number; observed_wall_time_ns: number; worker_utilization: number;
|
||||
worker_busy_time_ns: number; worker_cpu_time_ns: number; observed_wall_time_ns: number;
|
||||
worker_utilization: number; worker_cpu_utilization: number;
|
||||
task_types: Taskflow_Type_State[]; workers: Taskflow_Worker_State[]};
|
||||
|
||||
const default_plot_execution_policy = (): Plot_Execution_Policy => ({visible: true});
|
||||
@@ -1221,6 +1223,11 @@ function taskflow_graph_analysis(graph: Taskflow_Graph_Trace, executions: Taskfl
|
||||
const last_completed = rows.length ? Math.max(...rows.map(row => row.completed_ms)) : graph.finished_ms;
|
||||
const longest = rows.reduce<Taskflow_Execution_Trace | null>(
|
||||
(result, row) => !result || row.duration_ms > result.duration_ms ? row : result, null);
|
||||
const longest_non_cpu = rows.reduce<Taskflow_Execution_Trace | null>((result, row) => {
|
||||
const value = Math.max(0, row.duration_ms - row.cpu_duration_ms);
|
||||
const previous = result ? Math.max(0, result.duration_ms - result.cpu_duration_ms) : -1;
|
||||
return value > previous ? row : result;
|
||||
}, null);
|
||||
const events = rows.flatMap(row => [
|
||||
{time: row.started_ms, delta: 1},
|
||||
{time: row.finished_ms, delta: -1}
|
||||
@@ -1281,7 +1288,7 @@ function taskflow_graph_analysis(graph: Taskflow_Graph_Trace, executions: Taskfl
|
||||
maximum_parallelism,
|
||||
layer_count: width_by_level.size,
|
||||
parallel_layer_count: [...width_by_level.values()].filter(width => width > 1).length,
|
||||
longest
|
||||
longest, longest_non_cpu
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1459,7 +1466,7 @@ function Taskflow_Frame_Pane({plot}: {plot: Plot}) {
|
||||
<div title="提交 Taskflow 到整个 Topology 完成的墙钟时间,包含 Executor 排队。"><dt>Topology 墙钟</dt><dd>{milliseconds(graph_analysis.wall_time)}</dd></div>
|
||||
<div title="所有节点任务体墙钟时长之和;包含 worker 被 OS 抢占或任务体内阻塞的时间。"><dt>任务体墙钟总和</dt><dd>{milliseconds(graph_analysis.execution_time)}</dd></div>
|
||||
<div title="通过 worker 线程 CPU 时钟测得,不包含 OS 抢占和任务内睡眠。"><dt>任务体实际 CPU</dt><dd>{milliseconds(graph_analysis.cpu_execution_time)}</dd></div>
|
||||
<div title="任务体墙钟减去线程 CPU 时间;包含 OS 抢占、内核等待或任务体内阻塞。"><dt>Worker 被抢占/阻塞</dt><dd>{milliseconds(graph_analysis.descheduled_time)}</dd></div>
|
||||
<div title="任务体墙钟减去 Windows 线程 CPU 计费时间。短任务受约 15.625 ms 计费粒度影响,只能视为估算,不能单独证明锁等待或 OS 抢占。"><dt>非 CPU 计费墙钟(估算)</dt><dd>{milliseconds(graph_analysis.descheduled_time)}</dd></div>
|
||||
<div title="Topology 墙钟中至少有一个节点任务体正在执行的区间并集。"><dt>任务体墙钟并集</dt><dd>{milliseconds(graph_analysis.body_wall_time)}</dd></div>
|
||||
<div title="Topology 墙钟中只有 Observer on_entry/on_exit 在执行、没有任务体执行的区间。"><dt>Observer 独占墙钟</dt><dd>{milliseconds(graph_analysis.observer_wall_time)}</dd></div>
|
||||
<div title="所有节点 Observer entry 墙钟耗时之和,包含并行重叠。"><dt>Observer entry 墙钟</dt><dd>{milliseconds(graph_analysis.observer_entry_time)}</dd></div>
|
||||
@@ -1474,6 +1481,7 @@ function Taskflow_Frame_Pane({plot}: {plot: Plot}) {
|
||||
<div title="Observer 时间区间内同时执行的最大节点数量。"><dt>实际最大并行</dt><dd>{graph_analysis.maximum_parallelism}</dd></div>
|
||||
<div title="同一层节点没有相互依赖,可以并行;串行图的并行层数量为零。"><dt>依赖层 / 并行层</dt><dd>{graph_analysis.layer_count} / {graph_analysis.parallel_layer_count}</dd></div>
|
||||
<div title={graph_analysis.longest?.node_id}><dt>最长执行节点</dt><dd>{graph_analysis.longest ? milliseconds(graph_analysis.longest.duration_ms) : "--"}</dd></div>
|
||||
<div title={graph_analysis.longest_non_cpu?.node_id}><dt>最长非 CPU 节点(估算)</dt><dd>{graph_analysis.longest_non_cpu ? `${taskflow_node_name(graph_analysis.longest_non_cpu.node_id.split("/").at(-1) ?? graph_analysis.longest_non_cpu.node_id)} · ${milliseconds(Math.max(0, graph_analysis.longest_non_cpu.duration_ms - graph_analysis.longest_non_cpu.cpu_duration_ms))}` : "--"}</dd></div>
|
||||
{graph.stage === "render_2d.paint" && paint_analysis ? <>
|
||||
<div title="同一物理帧 paint_started 到 paint_finished 的完整区间。"><dt>同帧 Paint 总墙钟</dt><dd>{milliseconds(paint_analysis.total)}</dd></div>
|
||||
<div title="主帧 ensure_size 与完整像素清屏。"><dt>帧目标准备</dt><dd>{milliseconds(paint_analysis.frame_target)}</dd></div>
|
||||
@@ -1505,18 +1513,20 @@ function Taskflow_Runtime_Pane() {
|
||||
return <section className="workspacePane"><header className="taskflowRuntimeHeader"><div><span className="eyebrow">全局执行域</span><h2>Taskflow 总体观测</h2><p>每秒读取一次累计 Observer 状态;逐帧拓扑捕获在各图的“Taskflow 帧分析”页按需开启。</p></div><button onClick={() => void load()}>刷新</button></header>
|
||||
<div className="workspaceBody taskflowRuntimePane">{error ? <p className="taskflowError">{error}</p> : null}{state ? <>
|
||||
<dl className="taskflowRuntimeSummary">
|
||||
<div><dt>Worker</dt><dd>{state.worker_count}</dd></div><div><dt>总体占用率</dt><dd>{state.worker_utilization.toFixed(1)}%</dd></div>
|
||||
<div><dt>Worker</dt><dd>{state.worker_count}</dd></div><div title="Worker 位于最外层任务体内的累计墙钟占比,不等同于 CPU 利用率。"><dt>任务体墙钟占用</dt><dd>{state.worker_utilization.toFixed(1)}%</dd></div>
|
||||
<div title="按 Worker 最外层活跃区间累计的线程 CPU 时间占比。"><dt>线程 CPU 占用</dt><dd>{state.worker_cpu_utilization.toFixed(1)}%</dd></div>
|
||||
<div><dt>活跃 Worker</dt><dd>{state.active_workers}/{state.worker_count}</dd></div><div><dt>活跃任务</dt><dd>{state.active_tasks}</dd></div>
|
||||
<div><dt>活跃 Topology</dt><dd>{state.active_topologies}</dd></div><div><dt>活跃 Taskflow</dt><dd>{state.active_taskflows}</dd></div>
|
||||
<div><dt>累计任务</dt><dd>{state.observed_tasks.toLocaleString("zh-CN")}</dd></div><div><dt>失败 Taskflow</dt><dd>{state.failed_taskflows}</dd></div>
|
||||
<div><dt>队列峰值</dt><dd>{state.peak_worker_queue_size}</dd></div><div title={`${state.longest_task.name || state.longest_task.native_id} · ${state.longest_task.type}`}><dt>最长任务</dt><dd>{nanoseconds(state.longest_task.time_ns)}</dd></div>
|
||||
</dl>
|
||||
<p className="diagnosticNotice">Observer 的任务持续时间包含任务体内部的锁等待或阻塞;队列峰值与就绪等待能定位 Executor 拥塞,但 Taskflow 原生 Observer 不提供具体互斥量名称。具体帧请在逐帧 DAG 中核对并行关系、Worker 与长尾。</p>
|
||||
<p className="diagnosticNotice">任务体墙钟占用表示 Worker 正位于任务调用栈中,不等同于 CPU 使用率。线程 CPU 占用按最外层活跃区间累计;两者差值包含 OS 未计费、内核等待和任务体阻塞,但不能仅凭差值断定某一把锁。Executor 拥塞应结合队列峰值和逐帧就绪等待判断。</p>
|
||||
<section className="taskflowRuntimeSection"><header><strong>Worker 占用与队列</strong><span>累计值,不在 GET 时重新计算任务样本。</span></header><div className="taskflowWorkerGrid">{state.workers.map(worker => <article key={worker.id}>
|
||||
<header><strong>Worker {worker.id}</strong><span>{worker.utilization.toFixed(1)}%</span></header>
|
||||
<div className="taskflowUtilization"><i style={{width: `${Math.min(100, worker.utilization)}%`}}/></div>
|
||||
<header><strong>Worker {worker.id}</strong><span>墙 {worker.utilization.toFixed(1)}% · CPU {worker.cpu_utilization.toFixed(1)}%</span></header>
|
||||
<div className="taskflowUtilization" title={`任务体墙钟 ${worker.utilization.toFixed(1)}% / 线程 CPU ${worker.cpu_utilization.toFixed(1)}%`}><i style={{width: `${Math.min(100, worker.utilization)}%`}}/><b style={{width: `${Math.min(100, worker.cpu_utilization)}%`}}/></div>
|
||||
<dl><div><dt>任务</dt><dd>{worker.task_count}</dd></div><div><dt>队列 当前/峰值</dt><dd>{worker.current_queue_size}/{worker.peak_queue_size}</dd></div>
|
||||
<div><dt>最长</dt><dd>{nanoseconds(worker.max_task_time_ns)}</dd></div><div><dt>活跃持续</dt><dd>{worker.active_task.time_ns ? nanoseconds(worker.active_task.time_ns) : "空闲"}</dd></div></dl>
|
||||
<div><dt>最长</dt><dd>{nanoseconds(worker.max_task_time_ns)}</dd></div><div><dt>活跃持续</dt><dd>{worker.active_task.time_ns ? nanoseconds(worker.active_task.time_ns) : "空闲"}</dd></div>
|
||||
<div><dt>累计 CPU</dt><dd>{nanoseconds(worker.cpu_time_ns)}</dd></div><div><dt>非 CPU 墙钟</dt><dd>{nanoseconds(worker.non_cpu_time_ns)}</dd></div></dl>
|
||||
{worker.active_task.time_ns ? <code className="taskflowActiveTask" title={worker.active_task.native_id}>{worker.active_task.type} · {worker.active_task.native_id}</code> : null}
|
||||
</article>)}</div></section>
|
||||
<section className="taskflowRuntimeSection"><header><strong>Taskflow 原生任务类型</strong><span>按 Observer TaskType 累计执行次数与耗时。</span></header>
|
||||
|
||||
@@ -232,12 +232,14 @@ canvas { display: block; width: 100%; height: 100%; background: #070d18; }
|
||||
.taskflowRuntimeHeader { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 17px 16px 14px; border-bottom: 1px solid #20314b; background: #0b1524; }
|
||||
.taskflowRuntimeHeader h2 { margin: 4px 0 0; font-size: 21px; }
|
||||
.taskflowRuntimeHeader p { margin: 5px 0 0; color: #71839e; font-size: 11px; }
|
||||
.taskflowWorkerGrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 9px; padding: 11px; }
|
||||
.taskflowWorkerGrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); align-content: start; gap: 9px; max-height: min(58vh, 720px); overflow-y: auto; padding: 11px; scrollbar-gutter: stable; }
|
||||
.taskflowWorkerGrid article { padding: 10px; border: 1px solid #1f334e; border-radius: 8px; background: #091321; }
|
||||
.taskflowWorkerGrid article > header { display: flex; justify-content: space-between; color: #dce8f8; font-size: 11px; }
|
||||
.taskflowWorkerGrid article > header span { color: #5ce4c2; font: 11px/1 ui-monospace, monospace; }
|
||||
.taskflowUtilization { height: 6px; overflow: hidden; margin: 9px 0; border-radius: 99px; background: #18273b; }
|
||||
.taskflowUtilization i { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg, #3aa58d, #5ce4c2); }
|
||||
.taskflowUtilization { position: relative; height: 9px; overflow: hidden; margin: 9px 0; border-radius: 99px; background: #18273b; }
|
||||
.taskflowUtilization i, .taskflowUtilization b { position: absolute; left: 0; display: block; border-radius: inherit; }
|
||||
.taskflowUtilization i { top: 0; height: 100%; background: #2b887c; }
|
||||
.taskflowUtilization b { bottom: 0; height: 4px; background: #5ce4c2; }
|
||||
.taskflowWorkerGrid dl { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; margin: 0; }
|
||||
.taskflowWorkerGrid dl > div { display: flex; justify-content: space-between; gap: 5px; color: #71839e; font-size: 9px; }
|
||||
.taskflowWorkerGrid dd { margin: 0; color: #aec0d8; font-family: ui-monospace, monospace; }
|
||||
|
||||
Reference in New Issue
Block a user