28 KiB
下面这份直接作为 Codex 的完整执行计划使用。所有条目都按强制要求执行,不保留旧实现,不增加兼容层,不引入独立 PerfTrace 库。
Renderive Kernel Render DAG 完整改造执行计划
0. 总目标
将 Plot 内部渲染执行统一改造成:
Renderable 状态
+
Renderable 数据依赖
+
Renderable 图层依赖
+
prepare_buffer 状态
+
paint_buffer 状态
+
Renderable 内部任务 DAG
│
▼
render_plan compiler
│
▼
ONE Render DAG
│
▼
ONE Taskflow
│
▼
Frame 执行
│
├── 普通运行:不记录详细性能
│
└── Capture:直接写 Frame execution slots
│
▼
三缓冲完成交换
│
▼
immutable frame_snapshot
│
┌─────┴────────┐
▼ ▼
frame_analysis node_statistics
│ │
└──────┬───────┘
▼
后端 API
│
▼
前端 DAG + Worker Timeline + 多帧统计
Kernel Render DAG 必须同时成为:
执行依赖的唯一事实来源
Taskflow 编译的唯一事实来源
单帧性能分析的唯一事实来源
前端 DAG 展示的唯一事实来源
1. 锁死 Renderable 三阶段语义
Renderable 的执行语义必须明确分成:
prepare
↓
paint
↓
composite
这三个阶段不是全局阶段,不允许建立全局 barrier。
它们是每个 Renderable 以及 Renderable 内部任务自己的局部依赖关系。
必须严格执行以下语义。
prepare
prepare 必须完成:
读取自身业务数据
读取其他 Renderable 提供的数据
处理所有跨 Renderable dependency
坐标转换
数据转换
几何计算
可见范围计算
裁剪信息计算
布局结果准备
分片
索引生成
raster 前置数据生成
paint 所需全部输入生成
prepare 最终必须只产生当前 Renderable 自己的:
prepare_buffer
paint
paint 必须满足:
禁止读取其他 Renderable
禁止解析 dependency
禁止查询其他 Renderable 当前状态
禁止重新执行跨 Renderable 数据计算
禁止临时从 Axis/Series/其他对象读取绘制输入
paint 只能读取:
自身 prepare_buffer
自身 paint-only 配置
自身 paint target
paint 只能写:
自身 paint_buffer
必须满足这个验证原则:
将其他 Renderable 全部从
paint的可访问环境中移除,只保留当前 Renderable 的prepare_buffer,paint仍必须能够完整正确执行。
composite
composite 必须:
只读取已经完成的 paint_buffer
按照 layer 关系完成图层组合
不读取 Renderable 原始业务数据
不执行 prepare 计算
2. 建立强类型 prepare_buffer
每一个需要 prepare 数据的 Renderable 必须拥有自己的强类型 Prepare Buffer。
禁止实现:
std::unordered_map<std::string, std::any>
禁止通过通用字符串字段传递 Renderable 绘制输入。
例如:
Axis
└── axis_prepare_buffer
Spectrum
└── spectrum_prepare_buffer
Waterfall
└── waterfall_prepare_buffer
Afterglow
└── afterglow_prepare_buffer
具体字段由各 Renderable 自己定义。
例如 Waterfall:
waterfall_prepare_buffer
├── transformed_data
├── visible_range
├── partition_description
├── chunk_metadata
├── raster_parameters
└── 其他 paint 必需数据
Paint 不得绕过这些结构重新访问数据源。
3. 审计并拆除所有混合 Prepare/Paint 实现
逐个审计所有 Renderable。
重点处理:
Waterfall
Spectrum
Afterglow
同时扫描其他 Renderable 中:
paint()
build_paint_task_graph()
render()
raster()
内部是否仍包含:
数据变换
跨 Renderable 查询
坐标计算
布局计算
分片
输入数据准备
全部迁移到 Prepare。
原来的混合实现直接删除。
不得保留:
旧 paint path
+
新 prepare path
两套兼容逻辑。
绘制结果必须保持一致。
4. Prepare Buffer 与 Paint Buffer 完全独立缓存
每个 Renderable 必须独立维护:
prepare_buffer validity
paint_buffer validity
不得继续使用一个 Renderable 整体缓存状态同时代表两者。
缓存关系必须严格满足:
prepare invalid
↓
paint 必须 invalid
但:
paint invalid
不得无条件导致:
prepare invalid
5. 建立独立 Prepare/Paint Revision
现有 revision/cache revision 体系必须拆到能够分别回答:
当前 prepare_buffer 是否仍有效
当前 paint_buffer 是否仍有效
至少在语义上存在:
prepare input revision
prepare output revision
paint input revision
paint output revision
具体字段名称保持现有项目命名风格。
Prepare 有效性必须依赖
自身数据 revision
依赖 Renderable 提供的数据 revision
会影响 prepare 的尺寸/范围/坐标参数
prepare-only properties
Paint 有效性必须依赖
当前 prepare_buffer revision
paint-only properties
影响 raster/output 的尺寸和配置
例如:
仅颜色变化
必须能够得到:
prepare cache = valid
paint cache = invalid
例如:
依赖 Axis 范围变化
必须得到:
prepare cache = invalid
paint cache = invalid
6. 修正 Dependency Invalidations
跨 Renderable dependency 必须只描述 Prepare 数据依赖。
例如:
Series depends on Axis
必须编译成:
Axis Prepare
↓
Series Prepare
不得编译成:
Axis Paint
↓
Series Prepare
不得继续使用:
整个 Renderable A
↓
整个 Renderable B
这种粗粒度执行约束。
Prepare 数据变化向 dependency 后继传播:
A prepare invalid
↓
B prepare invalid
↓
B paint invalid
Paint-only 状态变化不得传播到其他 Renderable 的 Prepare:
A paint invalid
不得导致:
B prepare invalid
7. 建立 Renderable DAG Builder 接口
Renderable 必须正式提供建图能力。
保留运行时多态。
建立与现有类体系匹配的虚函数,语义必须等价于:
virtual void build_prepare_graph(render_graph_builder &builder);
virtual void build_paint_graph(render_graph_builder &builder);
两个函数必须写入同一个:
render_graph_builder
不得分别生成两张最终 Graph。
简单 Renderable:
Prepare
↓
Paint
复杂 Renderable 可以展开自己的内部 DAG。
8. Waterfall 必须展开真实内部 DAG
Waterfall 分片必须全部成为正式 Node。
不得把分片隐藏为一个 Waterfall Task 内部的匿名并行执行。
例如:
Waterfall Prepare
│
├── Chunk 0 Prepare -> Chunk 0 Paint ─┐
├── Chunk 1 Prepare -> Chunk 1 Paint ─┤
├── Chunk 2 Prepare -> Chunk 2 Paint ─┤
└── Chunk N Prepare -> Chunk N Paint ─┤
▼
Merge
如果某些分片只需要单独的 Prepare 或单独 Paint,则按真实依赖建立节点。
不得为了统一结构制造不存在的任务。
动态 Chunk 必须拥有稳定逻辑 Node ID。
9. prepare -> paint 只能是局部依赖
禁止建立:
所有 Prepare 完成
↓
所有 Paint 开始
这种全局 Barrier。
必须形成流水式 DAG:
Prepare A -> Paint A
Prepare B -------------> Paint B
Prepare C -> Paint C
因此实际运行允许:
Prepare A 完成
↓
Paint A 开始
同时:
Prepare B
Prepare C
仍在执行。
这条必须通过并发测试明确验证。
10. Paint 必须最大程度并行
所有 Renderable 的 Paint 必须只写自己的独立:
paint_buffer
因此:
Axis Paint
Series Paint
Waterfall Paint
Legend Paint
在不存在真实 Paint 依赖的情况下必须允许完全并行。
不得直接将:
layer_node_
转换为:
Paint A -> Paint B
从而人为串行化 Paint。
11. Layer 关系必须编译到 Composite
图层顺序必须主要落实到 Composite DAG。
例如:
Background Paint
Series Paint
Axis Paint
可以并行。
最终:
Background Paint
↓
Composite Background
│
Series Paint
└────> Composite Series
│
Axis Paint
└────> Composite Axis
具体依赖按照现有 Layer Graph 的真实顺序生成。
必须保持最终像素结果与原实现一致。
12. 最终只有一张 Render DAG
最终 Compiler 输入必须为:
Renderable internal graph
+
dependency_node_
+
layer_node_
+
prepare_buffer validity
+
paint_buffer validity
+
Renderable 当前状态
输出必须只有:
render_plan
└── graph
Graph 内统一存在:
prepare node
paint node
composite node
不得生成:
prepare_graph
paint_graph
两张最终执行图。
13. Buffer 必须在建图阶段裁剪任务
缓存命中的工作必须直接从本帧有效 DAG 中删除。
禁止继续生成:
cache_hit
空 Task。
完整路径:
Prepare
↓
Paint
↓
Composite
Prepare Cache Hit
本帧必须生成:
Paint
↓
Composite
Paint 直接读取已有 Prepare Buffer。
Paint Cache Hit
本帧必须生成:
Composite
Composite 直接读取已有 Paint Buffer。
Prepare/Paint 均失效
生成:
Prepare
↓
Paint
↓
Composite
14. 建立稳定 node_id
Kernel/Plot 必须统一分配 DAG Node 身份。
所有逻辑任务必须拥有:
node_id
包括:
Prepare
Paint
Composite
Waterfall dynamic chunks
内部 merge
内部 geometry task
规则严格保持:
逻辑任务身份不变
=> node_id 不变
逻辑任务语义改变
=> 分配新 node_id
node 退休
=> node_id 永不复用
15. Node 必须带最小元数据
每个 Render Node 至少包含:
node_id
owner/renderable id
name
kind
execution_index
kind 至少有:
prepare
paint
composite
不提前添加无实际使用场景的分类。
16. 建立单一 render_plan
建立:
render_plan
├── version
└── graph
├── nodes
└── edges
render_plan 必须代表:
当前 Plot 在当前 Renderable、Dependency、Layer、Prepare Cache、Paint Cache 状态下真正会执行的完整 Render DAG。
17. 建立 render_plan_version
以下任一情况发生时必须产生新 Version:
active node set 改变
Node 增加
Node 删除
Edge 改变
Waterfall 分片拓扑变化
dependency topology 变化
layer/composite topology 变化
prepare cache 裁剪结果变化
paint cache 裁剪结果变化
仅以下变化不得产生新 Version:
Task 实际耗时变化
Task Worker 改变
调度顺序不同
实际并行程度不同
18. Render Plan 编译成一个 Taskflow
必须满足:
1 Render Node
=
1 Taskflow Task
以及:
1 Render Edge
=
1 Taskflow dependency
最终:
render_plan.graph
↓
Taskflow
↓
Taskflow Executor
不得生成两个前后 Taskflow。
19. Taskflow 只遵守偏序关系
DAG Edge 只表示:
B 不能在 A 完成以前执行
没有 Edge 的 Node 必须交由 Taskflow 自由调度。
不得写:
固定 Worker
固定执行次序
手工串行队列
除非任务本身存在真实依赖。
20. 性能采集必须请求式开启
正常运行:
capture = disabled
不得常驻记录完整 Node 时序。
必须实现:
capture_next_frame()
以及:
capture_frames(count)
例如:
capture_frames(20)
必须从后续完整 Render Frame 开始连续捕获 20 帧,然后自动停止。
21. Capture Controller 必须保持极简
Plot/Kernel 内维护:
capture enabled
remaining frame count
capture session id
使用必要的原子状态实现。
不得增加:
Event system
Record system
MPSC performance queue
TLS trace system
collector thread
22. Frame 必须持有 Capture 状态
每个正在 Render 的 Frame 在开始执行时必须确定:
capture_this_frame
该状态在本 Frame 生命周期内保持不变。
不得执行到一半再打开 Capture。
23. Frame 性能数据使用预分配 List
不得在 Task 热路径使用:
map<node_id, execution>
unordered_map<node_id, execution>
Render Plan 编译时给每个 Node 分配:
execution_index
例如:
Node #100 -> slot 0
Node #101 -> slot 1
Node #203 -> slot 2
Capture Frame 创建:
node_execution[]
长度直接根据 Plan 确定。
24. node_execution 必须记录真实时序
至少记录:
node_id
start_time
end_time
worker_id
status
duration 不重复存储:
duration = end_time - start_time
时间源必须保持单调并能在 Worker 间比较。
25. Taskflow Worker 只能写自己的 Execution Slot
编译 Taskflow 时将:
Task
直接绑定:
execution_index
Capture 开启:
execution.start = now
execution.worker = worker
执行真实任务
execution.end = now
execution.status = complete
不同 Task 不得写同一个 slot。
热路径不得用 mutex 保护整个性能数据结构。
26. Capture 关闭时不得采集详细时间
Capture 关闭时 Task 必须直接进入正常执行路径。
不得仍然执行:
now()
start record
end record
statistics aggregation
只保留最小 capture branch。
27. Renderable 自定义指标直接写 Execution Slot
Renderable 实现允许对自己当前 Node 补充固定性能指标。
例如 Waterfall Prepare:
input_count
chunk_size
prepared_cells
Paint:
pixel_count
primitive_count
不得在 Worker 热路径实现:
unordered_map<string, any>
使用固定结构或固定 metric slot。
28. Frame Snapshot 必须绑定 render_plan_version
Capture Frame 至少包含:
frame_id
render_plan_version
render_start
render_end
node_execution[]
不再创建:
Trace
Span
Record
Event
等额外运行层。
一帧自己的执行数据就是唯一运行快照。
29. 三缓冲交换必须成为 Snapshot 发布边界
运行阶段:
working frame
│
Taskflow 写 execution slots
│
render complete
│
triple-buffer exchange
│
completed frame
进入 Completed 后:
frame performance
必须不可再修改。
外部读取 Completed Frame 时不得需要锁住 Taskflow Worker。
30. 建立 Capture Repository
三缓冲不负责保存历史性能帧。
Capture 请求的 Completed Frame 必须在冷路径复制/移动到:
capture_repository
结构:
capture_session
├── session_id
├── requested_count
├── captured_count
├── active
└── frame_snapshots[]
抓取达到请求数量以后必须自动结束 Session。
31. 保存 Render Plan 历史结构
必须能够:
render_plan_version
↓
找到当时对应的 Render DAG
连续 20 帧过程中允许:
Frame 100 -> Plan 30
Frame 101 -> Plan 30
Frame 102 -> Plan 31
Frame 103 -> Plan 32
每帧必须绑定自己真实执行的 Plan Version。
不得假定一个 Capture Session 只有一个 DAG Version。
32. 实现 frame_analysis
所有重分析必须发生在 Render 热路径之外。
输入:
render_plan
+
frame_snapshot
输出:
frame_analysis
至少计算:
total_render_duration
node_duration
node_start_offset
node_end_offset
dependency_ready_time
scheduler_wait
critical_path
critical_path_duration
critical_path_contribution
total_work_duration
peak_parallelism
average_parallelism
parallel_overlap
worker utilization
bottleneck nodes
33. Scheduler Wait 必须从 DAG 和实际时间推导
对于:
A ─┐
├──> C
B ─┘
计算:
dependency_ready(C)
=
max(A.end, B.end)
然后:
scheduler_wait(C)
=
C.start - dependency_ready(C)
Source Node:
dependency_ready
=
render_start
不得为了获得 Wait 再增加事件采集系统。
34. 正确处理并行节点的耗时占比
不得简单计算:
node_duration / sum(all node durations)
作为“帧耗时占比”。
必须明确输出不同指标:
work_contribution
critical_path_contribution
并行节点允许 Work Duration 总和远大于 Wall Duration。
35. 实现 node_statistics
按稳定:
node_id
聚合多帧数据。
至少维护:
execution_count
average
moving_average
p50
p95
p99
min
max
critical_path_frequency
average_scheduler_wait
短生命周期 Waterfall Node 同样统计。
36. 支持按 render_plan_version 聚合
必须支持:
Plan v30
├── frame...
└── statistics
Plan v31
├── frame...
└── statistics
用于直接比较 DAG 编译策略变化后的性能。
例如:
Plan v30 P95 render = 8.4 ms
Plan v31 P95 render = 6.1 ms
37. 后端增加 Capture API
按照当前后端/Adminive API 风格接入。
必须提供等价能力:
请求下一帧
请求连续 N 帧
查看 capture 状态
查看 capture session
查看 captured frame 列表
读取单帧 snapshot
读取单帧 analysis
读取 render plan topology
读取 node statistics
读取 plan version statistics
禁止为了这些 API 重新实时读取 Worker 数据。
接口只读取:
completed snapshots
analysis
statistics
38. 前端增加 Performance Capture 页面
前端必须提供:
Capture next frame
Capture N frames
默认 N 可输入:
20
Capture 时显示:
captured 7 / 20
完成后显示捕获到的 Frame 列表。
39. Frame 列表必须显示 Version
例如:
Frame #10381 Plan v57 6.81 ms
Frame #10382 Plan v57 7.02 ms
Frame #10383 Plan v58 5.93 ms
点击 Frame 后必须加载:
frame_snapshot
+
对应 render_plan_version
+
frame_analysis
40. 前端主视图必须是一张完整 Render DAG
不得拆成:
Prepare DAG
Paint DAG
两个主图。
必须显示完整:
Prepare
↓
Paint
↓
Composite
以及跨 Renderable 数据依赖。
例如:
Axis Prepare ────────────────┐
│ │
▼ ▼
Axis Paint Series Prepare
│ │
│ ▼
│ Series Paint
│ │
│ ▼
│ Composite Series
│ │
└──────────────────────┼──> Composite Axis
Waterfall 内部 Chunk 必须可以展开。
41. 前端 DAG Node 必须按 kind 区分
至少区分:
prepare
paint
composite
节点上直接显示:
当前 duration
scheduler_wait
worker
critical contribution
historical p95
不得只有一个模糊的百分比字段。
42. 前端必须显示 Prepare/Paint Cache 独立状态
Renderable Detail 必须显示:
prepare cache: HIT/MISS
paint cache: HIT/MISS
例如:
Spectrum
prepare cache: HIT
paint cache: MISS
用户必须能够直接理解为什么本 Frame DAG 中:
Spectrum Prepare
不存在,而:
Spectrum Paint
存在。
43. 前端必须实现真实 Worker Timeline
同一个 Frame 必须能够按真实时间显示:
time ─────────────────────────────────────────>
Worker 0
[Axis Prepare][Axis Paint ]
Worker 1
[Series Prepare ][Series Paint]
Worker 2
[WF Prepare][Chunk0 Prep][Chunk0 Paint]
Worker 3
[Chunk1 Prep][Chunk1 Paint]
Worker 4
[Composite]
这张 Timeline 使用:
start_time
end_time
worker_id
直接生成。
44. DAG 与 Timeline 必须双向联动
点击 DAG Node:
Chunk 7 Paint
必须在 Timeline 高亮它的真实执行区间。
点击 Timeline 区间:
Worker 3 / 2.3ms ~ 3.7ms
必须高亮对应 DAG Node。
45. 前端 Node Detail 必须展示当前与历史对比
例如:
Waterfall / Chunk 7 / Paint
current duration 1.42 ms
scheduler wait 0.18 ms
worker 3
moving average 1.13 ms
p95 1.67 ms
p99 2.10 ms
critical contribution 12.4%
critical path frequency 14 / 20
Renderable 自定义指标同时显示。
46. 连续 N 帧必须提供统计视图
Capture 20 帧以后必须提供:
total render
avg
p50
p95
max
parallelism
average
peak
scheduler wait
average
p95
critical path
node frequency
不得只提供 20 个单帧链接。
47. 不同 Plan Version 必须支持直接比较
如果 Capture 中存在:
Plan v57
Plan v58
必须能够比较:
frame count
render avg
render p95
peak parallelism
average parallelism
scheduler wait
critical path nodes
并展示拓扑变化:
新增 node
删除 node
新增 edge
删除 edge
缓存裁剪变化
48. 测试执行顺序
所有阶段必须遵守:
先补测试
↓
确认测试失败
↓
修改实现
↓
相关测试通过
↓
全量测试通过
↓
再进入下一阶段
不得先整体改完再补测试。
49. 必须增加的核心测试
覆盖:
prepare 禁止依赖 paint 结果
paint 不访问其他 Renderable
prepare_buffer 独立有效
paint_buffer 独立有效
prepare invalid -> paint invalid
paint invalid 不反向 invalid prepare
dependency 只约束 prepare
prepare 完成后对应 paint 可立即执行
不存在全局 prepare barrier
无依赖 Renderable prepare 真并行
独立 paint_buffer 的 paint 真并行
layer 顺序只正确约束 composite
cache hit 节点真正不进入 DAG
node_id 跨 plan version 稳定
retired node_id 不复用
Waterfall 动态分片 node 正确
render_plan_version 正确变化
一张 DAG 正确编译一个 Taskflow
Capture off 不生成 execution timing
Capture next frame 只抓一帧
Capture 20 frames 正好抓 20 帧
多 worker 写不同 execution slot 无竞争
Frame A/B 不串 performance 数据
三缓冲交换以后 snapshot 不再变化
Plan version 与 Frame 正确绑定
scheduler_wait 推导正确
critical path 正确
并行时间重叠计算正确
前端 API 返回 Plan + Frame 完整数据
50. 并发与 Sanitizer 验证
必须执行:
高并发 Taskflow 测试
Waterfall 大量动态 Chunk
持续 Render
Capture 连续多帧
Capture 开关反复操作
Plan 高频变化
缓存高频命中/失效
并运行项目当前环境可用的:
ASan
UBSan
TSan
TSan 重点检查:
Frame execution slots
capture controller
triple-buffer publish
capture repository
plan history
51. 性能回归验证
必须单独比较:
Capture OFF
情况下改造前后的 Render 性能。
Capture OFF 不得因为性能分析系统引入明显:
锁竞争
动态内存分配
hash lookup
时间采样
队列 push
observer 聚合
Capture ON 的开销单独测量。
52. 清理旧性能统计路径
当 Frame Capture + node_statistics 完成以后,审计现有 Renderable Task Observer / Task Execution Snapshot / Rolling
Statistics 等机制。
如果职责已经完全被新结构替换:
直接删除旧实现
不得保留双统计路径。
仅保留仍有独立语义、没有被新系统替代的统计能力。
53. 最终代码结构必须满足
Plot
│
├── Renderable graph relationships
│
├── render_plan compiler
│ └── ONE Render DAG
│
├── Taskflow executor
│
├── frame buffers
│ ├── prepare_buffer state
│ ├── paint_buffer state
│ └── optional performance snapshot
│
├── capture controller
│
├── capture repository
│
├── frame_analysis
│
└── node_statistics
前端:
Performance
│
├── Capture Control
├── Captured Frames
├── Render DAG
├── Worker Timeline
├── Node Detail
├── Multi-frame Statistics
└── Plan Version Comparison
54. 最终不可破坏的设计规则
这部分直接放到 Codex 任务最顶部:
所有跨 Renderable 数据访问必须在
prepare完成。
paint禁止访问其他 Renderable,只能消费自身prepare_buffer。
prepare_buffer与paint_buffer必须是完全独立的两层缓存。
prepare缓存失效必须使paint缓存失效;paint缓存失效不得反向污染prepare。Prepare、Paint、Composite 最终必须构成同一张 Render DAG。
禁止建立全局 Prepare→Paint Barrier。
某个 Prepare 完成后,只要其真实依赖已经满足,对应 Paint 必须立即允许进入 Taskflow 调度。
独立
paint_buffer的 Paint 必须尽可能并行,Layer 顺序落实到 Composite。缓存命中的工作必须在 Render DAG 构建阶段直接裁剪。
Kernel Render DAG 是执行、Taskflow 编译和性能分析的唯一拓扑事实来源。
性能时序完全绑定 Frame,不建立 Trace/Event/Record/MPSC 性能事件体系。
Capture 必须请求式开启,支持下一帧和连续 N 帧。
Capture 开启时 Taskflow Task 直接写 Frame 预分配 Execution Slot。
三缓冲交换完成后 Frame Snapshot 必须不可变。
性能分析必须在完成帧冷路径执行。
前端必须同时展示 Render DAG 偏序关系和本 Frame 的真实 Worker 时序。
不得触碰 git。
所有代码保持 K&R 风格,不增加无意义空行。
被替换的旧实现直接删除,不做兼容实现。
执行完成后的最终数据流必须严格为:
Renderable / Dependency / Layer / Cache
│
▼
render_plan compiler
│
▼
ONE Render DAG
│
▼
Taskflow
│
┌──────┴──────┐
│ │
Capture OFF Capture ON
│ │
正常执行 Frame slots
│
▼
completed Frame
│
▼
triple-buffer publish
│
▼
immutable snapshot
│
┌──────────┴──────────┐
▼ ▼
frame_analysis node_statistics
│ │
└──────────┬──────────┘
▼
Backend API
│
▼
DAG + Worker Timeline
+ Multi-frame Analysis
+ Plan Version Compare
这份计划直接从 Renderable 边界改造一直执行到最终前端性能分析页面。