From 07c39377795916473ce8d2d1faf3db1637f8a9ca Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Sat, 15 Aug 2026 15:55:51 +0800 Subject: [PATCH] =?UTF-8?q?cmake=20=E5=BC=95=E5=85=A5=20=20oneTBB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Kernel/CMakeLists.txt | 10 +- Kernel/cmake/rely.cmake | 22 ++ todolist.md | 770 ---------------------------------------- 3 files changed, 29 insertions(+), 773 deletions(-) create mode 100644 Kernel/cmake/rely.cmake delete mode 100644 todolist.md diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 2143e72..119696f 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -1,4 +1,5 @@ -set(Renderive_Kernel_dependencies global::taskflow) +include(${CMAKE_CURRENT_LIST_DIR}/cmake/rely.cmake) +set(Renderive_Kernel_dependencies global::taskflow render_kernel::oneTBB) if (RENDERIVE_BUILD_TESTS) set(Renderive_Kernel_test_targets) list(APPEND Renderive_Kernel_dependencies global::GTest) @@ -13,6 +14,7 @@ endif () rcl_load_dependency_environment(${Renderive_Kernel_dependencies}) find_package(Taskflow CONFIG REQUIRED) find_package(Threads REQUIRED) +find_package(TBB CONFIG REQUIRED) if (RENDERIVE_BUILD_TESTS) find_package(GTest CONFIG REQUIRED) endif () @@ -23,7 +25,9 @@ target_include_directories(Renderive_Kernel PUBLIC "$" ) target_compile_features(Renderive_Kernel PUBLIC cxx_std_20) -target_link_libraries(Renderive_Kernel PRIVATE Taskflow::Taskflow Threads::Threads) +target_link_libraries(Renderive_Kernel PRIVATE Taskflow::Taskflow) +target_link_libraries(Renderive_Kernel PRIVATE TBB::tbb) +target_link_libraries(Renderive_Kernel PRIVATE Threads::Threads) if (MSVC) target_compile_options(Renderive_Kernel PRIVATE /utf-8) endif () @@ -53,7 +57,7 @@ if (RENDERIVE_BUILD_TESTS) endforeach () add_custom_target(Renderive_Kernel_check COMMAND "${CMAKE_CTEST_COMMAND}" --test-dir "${CMAKE_BINARY_DIR}" - -C "$" -L "^Renderive_Kernel$" --output-on-failure + -C "$" -L "^Renderive_Kernel$" --output-on-failure DEPENDS ${Renderive_Kernel_test_targets} USES_TERMINAL) endif () diff --git a/Kernel/cmake/rely.cmake b/Kernel/cmake/rely.cmake new file mode 100644 index 0000000..67e7a22 --- /dev/null +++ b/Kernel/cmake/rely.cmake @@ -0,0 +1,22 @@ +include_guard(GLOBAL) +block() + rcl_init(render_kernel) + _register_git_cmake_library(render_kernel::oneTBB + "https://github.com/uxlfoundation/oneTBB.git" + "v2023.1.0" + ) + rcl_get_effective_install_dir(render_kernel::oneTBB ONETBB_ROOT) + set(TBB_CONFIG_DIR "${ONETBB_ROOT}/lib/cmake/TBB") + rcl_cmake_library_set_cmake_options(render_kernel::oneTBB ${oneTBB_option}) + rcl_cmake_library_set_other_use_opt(render_kernel::oneTBB + "-DTBB_DIR=\"${TBB_CONFIG_DIR}\"" + ) + rcl_cmake_library_set_init_script(render_kernel::oneTBB + "set(ONETBB_ROOT \"${ONETBB_ROOT}\")" + "set(TBB_DIR \"${TBB_CONFIG_DIR}\")" + ) + rcl_cmake_library_set_clear_script(render_kernel::oneTBB + "unset(ONETBB_ROOT)" + "unset(TBB_DIR)" + ) +endblock() \ No newline at end of file diff --git a/todolist.md b/todolist.md deleted file mode 100644 index 71ceacb..0000000 --- a/todolist.md +++ /dev/null @@ -1,770 +0,0 @@ -# Renderive 当前架构核实与改造 TODO - -## P0:External Operation 生命周期与失败语义 - -### TODO-01:核实 External Operation 是否存在永久 pending 风险 - -* [ ] 阅读 `Kernel/src/renderive/render_graph/External_Operation.hpp` -* [ ] 明确 `External_Operation_Source` 当前生命周期规则 -* [ ] 核实 Source 被析构但未调用 `complete()` / `fail()` 时,Operation 的最终状态 -* [ ] 编写测试:创建 Operation 后直接销毁 Source -* [ ] 验证 `Render_Graph_Runtime` 是否会永久停留在 `waiting_external` -* [ ] 验证 graph future / frame completion 是否会永久阻塞 -* [ ] 检查 Datoviz GPU completion 所有异常路径是否保证最终 complete/fail - -**核实目标:** - -确认是否存在: - -```text -producer 消失 - ↓ -External_Operation 永久 pending - ↓ -node 永久 waiting_external - ↓ -frame 永久无法完成 -``` - -**如果问题成立,再考虑改造:** - -* [ ] 为 External Operation 定义明确 terminal states - -```text -pending -completed -failed -cancelled / abandoned / broken -``` - -* [ ] Source 析构时处理未完成 Operation -* [ ] 明确 broken producer 应映射为: - - * failure - * cancellation - * abandoned -* [ ] 保证 completion callback 只执行一次 -* [ ] 保证 complete/fail/cancel 与析构竞态安全 -* [ ] 增加 double-complete / complete-after-fail 等测试 -* [ ] 增加 Runtime 等待 external 时 producer 异常退出测试 - ---- - -### TODO-02:核实 Render Graph failure 后是否可能等待无关 External Operation - -重点位置: - -```text -Render_Graph_Runtime.cpp -``` - -特别检查 graph 结束条件中: - -```text -failed -active_tasks -waiting_external -unfinished_nodes -``` - -之间的关系。 - -* [ ] 构造两个并行 async node:A、B -* [ ] A 主动 fail -* [ ] B 永久不回调 -* [ ] 验证整个 graph 是否永久不返回 -* [ ] 构造 A fail、B 正常延迟完成 -* [ ] 验证失败 frame 的 completion 时间是否被 B 强制拖长 -* [ ] 明确当前设计到底是: - - * fail-fast - * drain-before-fail - * cooperative cancellation - -**如果问题成立,再决定语义。** - -推荐先明确 contract,不要直接写代码: - -```text -方案 A:fail-fast -一个节点失败后,frame 尽快失败返回。 - -方案 B:drain -一个节点失败后,已启动外部操作仍全部收尾后再返回。 - -方案 C:cancel + drain -请求其他 operation cancellation, -无法取消的 operation 做后台资源回收, -但 frame logical completion 可以提前结束。 -``` - -* [ ] 根据 Renderive 的资源安全要求确定一种正式语义 -* [ ] 再增加对应 Runtime 状态机和测试 - ---- - -## P1:Render Plan 生命周期与重复编译 - -### TODO-03:核实 Render_Plan_History 是否长期无限增长 - -重点检查: - -```text -Render_Plan.cpp -Render_Plan_History -compile_render_plan() -``` - -当前重点假设: - -```text -只与 plans_.back() 比较 topology -``` - -可能出现: - -```text -Topology A -Topology B -Topology A -Topology B -... -``` - -导致历史: - -```text -A1 B2 A3 B4 A5 B6 ... -``` - -* [ ] 确认 `Render_Plan_History` 是否只 dedupe 相邻 topology -* [ ] 确认旧 Render Plan 是否存在必须永久保存的语义 -* [ ] 检查 Capture 是否持有具体 Plan -* [ ] 检查 Observation / Analysis 是否依赖历史 Plan 对象 -* [ ] 模拟 10 万帧 A/B topology 交替 -* [ ] 观察: - - * plan 数量 - * 内存占用 - * version 增长 -* [ ] 确认长期运行是否确实存在无界增长 - -**如果成立,再选择方案:** - -### 方案 A:Topology Interning - -* [ ] 为 topology 计算稳定 fingerprint/hash -* [ ] 相同 topology 复用已有 immutable Render Plan - -```text -topology fingerprint - ↓ -Render_Plan cache -``` - -### 方案 B:Bounded History - -* [ ] History 保留最近 N 个 plan -* [ ] Capture 对需要长期保存的 Plan 单独持有 shared_ptr - -### 方案 C:二者结合 - -* [ ] topology cache -* [ ] bounded observation history -* [ ] capture 独立 pin - -优先研究方案 C。 - ---- - -### TODO-04:核实 Render Plan 是否每帧重复编译执行拓扑 - -重点检查: - -```text -Scene_Base::compile_render_plan() -Render_Graph_Runtime constructor -``` - -核实每帧是否重复执行: - -```text -node id → index map -successor adjacency -indegree -topological sort -cycle validation -``` - -* [ ] 使用 profiler 测量 Runtime constructor 成本 -* [ ] 分别测试: - - * 10 nodes - * 50 nodes - * 100 nodes - * 500 nodes - * 1000 nodes -* [ ] 测量每帧: - - * Render Plan compile 时间 - * Runtime construction 时间 - * topology validation 时间 -* [ ] 与真实 node execution 时间比较 -* [ ] 判断这部分是否已经进入 critical path - -**只有测量证明值得优化时再改。** - -潜在目标结构: - -```text -Render_Plan -├─ Logical metadata -└─ Compiled Execution Layout - ├─ node execution index - ├─ predecessor count[] - ├─ successor offset[] - ├─ successors[] - └─ static topology metadata -``` - -每帧 Runtime 只生成: - -```text -remaining_predecessors[] -node_status[] -timestamps[] -external state -``` - -* [ ] 尽量避免每帧重新构造 immutable topology -* [ ] 保持 Render Plan 本身 immutable -* [ ] 不把 per-frame execution state 塞回 Render Plan -* [ ] benchmark 改造前后成本 - ---- - -## P1:调度模型规模化核实 - -### TODO-05:统计每个 Scene 实际线程成本 - -当前重点检查: - -```text -Scene_Base worker thread - -3D Point Scene: -Render_Domain thread -Gpu_Completion_Service thread - -Global: -Taskflow Executor workers -``` - -* [ ] 启动 1 个 3D Scene,记录线程数 -* [ ] 启动 10 个 Scene -* [ ] 启动 50 个 Scene -* [ ] 启动 100 个 Scene -* [ ] 测量: - - * OS thread 数量 - * context switches - * idle CPU - * memory/thread stack - * frame latency - * scheduler wait -* [ ] 明确 Renderive 目标部署规模: - - * 单桌面程序 1~4 Scene - * 多窗口 - * Web 多 session - * server-side rendering - -**如果目标只是少量本地 Scene:** - -* [ ] 暂不修改 - -**如果未来需要大量 Scene:** - -* [ ] 研究共享 Render Domain -* [ ] 研究共享 GPU Completion Service -* [ ] Render Domain 按 device/backend 而不是按 Scene 划分 -* [ ] 使用 serial executor / strand 保持 backend affinity - -目标可能演化为: - -```text -Global CPU Executor - -GPU Device 0 -├─ Shared Render Domain -│ ├─ Scene A -│ ├─ Scene B -│ └─ Scene C -│ -└─ Shared Completion Service - ├─ fence A - ├─ fence B - └─ fence C -``` - -**不要在没有多 Scene 压测数据之前重构这一项。** - ---- - -## P2:Frame Pipeline 能力边界确认 - -### TODO-06:确认当前 Scene 是否严格 single-frame-in-flight - -重点检查: - -```text -Scene_Base::submit_render() -Scene_Base::lock_render_idle() -``` - -* [ ] 验证 GPU external operation 未完成时,下一帧 CPU DAG 能否开始 -* [ ] 确认当前行为是否: - -```text -Frame N CPU - ↓ -Frame N GPU - ↓ -Frame N complete - ↓ -Frame N+1 CPU -``` - -而不是: - -```text -Frame N GPU - + -Frame N+1 CPU -``` - -* [ ] 测量这种设计对 interactive latency 的影响 -* [ ] 验证 low-latency 模式下 GPU queue 是否保持浅队列 -* [ ] 验证 frame age 是否优于多帧堆积方案 - -**当前阶段不要默认这是问题。** - -明确记录设计决策: - -```text -Interactive mode: -优先 latency -→ single-frame-in-flight 可以是正确策略 - -Throughput / offline mode: -优先 throughput -→ 未来可能需要 multi-frame-in-flight -``` - -* [ ] 只有出现离线渲染/视频/批处理需求时再设计跨帧流水线 - ---- - -## P2:Scene_Base 职责边界检查 - -### TODO-07:持续监控 Scene_Base 是否演化成 God Object - -盘点当前职责: - -```text -Renderable lifetime -Scene state -Snapshot -Dependency -Render plan compile -Frame submission -Worker control -Edit queue -Exception propagation -Observation -Capture integration -Frame control -Memory domain -``` - -* [ ] 给 Scene_Base 当前职责做一次正式列表 -* [ ] 检查每个职责是否属于 orchestration -* [ ] 新功能进入 Scene_Base 前必须判断能否成为独立 subsystem - -特别避免未来加入: - -```text -GPU fence logic -backend-specific synchronization -generic async continuation internals -capture storage internals -scheduler implementation internals -GPU profiler implementation -``` - -应继续保持: - -```text -Scene_Base - ↓ orchestrate - -Render_Graph_Runtime -External_Operation -Render_Domain -Gpu_Completion_Service -Capture subsystem -Observation subsystem -``` - -**当前不建议仅为了减小文件而拆类。** - -只有当职责本身形成独立生命周期/状态机时再拆。 - ---- - -## P2:Taskflow 依赖边界确认 - -### TODO-08:正式确认 Taskflow 只是 Executor,而不是架构语义的一部分 - -当前目标模型: - -```text -Render_Graph_Runtime - ↓ -CPU Scheduler Adapter - ↓ -tf::Executor::silent_async() -``` - -* [ ] 搜索所有 `tf::` 使用点 -* [ ] 检查 Renderable / Render Plan / External Operation 是否泄漏 Taskflow 类型 -* [ ] 检查 Render_Graph_Runtime 是否依赖 Taskflow DAG API -* [ ] 确认 Taskflow 只承担 CPU function dispatch -* [ ] 做一个最小 mock executor 测试 - -例如: - -```cpp -scheduler([] { - ... -}); -``` - -替换成测试 executor 后 Runtime 仍正常运行。 - -* [ ] 如果成立,记录架构结论: - -```text -Taskflow is an implementation detail of CPU execution, -not Renderive's task graph model. -``` - -**如果已经成立,不需要再额外设计 Scheduler Concept。** - -先保持最小 callable abstraction 即可。 - ---- - -## P2:Datoviz Async 接入完整性核实 - -### TODO-09:逐条核实 GPU completion 所有路径都完成 External Operation - -检查: - -```text -Point_Scene -Render_Domain -Gpu_Completion_Service -Datoviz backend -``` - -覆盖以下路径: - -* [ ] 正常 submit -* [ ] submit 失败 -* [ ] fence 创建失败 -* [ ] fence wait 失败 -* [ ] device lost -* [ ] Render_Domain callback 抛异常 -* [ ] backend.collect() 抛异常 -* [ ] Scene 被销毁 -* [ ] application shutdown -* [ ] completion service shutdown -* [ ] frame 被逻辑取消 -* [ ] GPU operation 已提交但 Scene 生命周期结束 - -每条路径都验证最终发生: - -```text -complete -或 -fail/cancel -``` - -不能: - -```text -silent disappearance -→ External Operation 永久 pending -``` - ---- - -## P2:CPU / GPU 观测数据可信度核实 - -### TODO-10:验证节点时间戳语义 - -针对: - -```text -ready_time -start_time -cpu_end_time -external_start_time -external_end_time -end_time -``` - -逐项明确语义。 - -* [ ] `ready_time` 是否表示所有 dependency 已满足 -* [ ] `start_time - ready_time` 是否能准确代表 scheduler wait -* [ ] `cpu_end_time - start_time` 是否代表 CPU node execution -* [ ] external_start 是否发生在 CPU submit 完成附近 -* [ ] external_end 是否由真正的 external completion 驱动 -* [ ] node end 是否与 dependency unlock 同一语义点 -* [ ] worker_id 是否只表示 CPU execution worker -* [ ] external completion thread 是否不会错误覆盖 worker_id - ---- - -### TODO-11:验证 Critical Path 算法 - -* [ ] 手工构造简单 DAG - -```text -A 10ms ── C 5ms -B 20ms ──┘ -``` - -期望 critical path: - -```text -B → C = 25ms -``` - -* [ ] 增加 external node -* [ ] 增加 scheduler wait -* [ ] 明确 critical path 是否统计: - - * CPU execution - * external wait - * scheduler wait - * dependency wait -* [ ] 明确算法计算的是: - - * DAG theoretical execution critical path - * 还是 observed wall-clock critical path - -两者不能混淆。 - ---- - -### TODO-12:验证 GPU timing 与 fence wait 的区别 - -确保以下数据不会混用: - -```text -GPU timestamp duration -≠ -CPU fence waiting duration -``` - -* [ ] GPU render timestamp -* [ ] transition timestamp -* [ ] copy timestamp -* [ ] total GPU timestamp -* [ ] CPU submit duration -* [ ] completion service fence wait duration -* [ ] readback duration - -输出报告时必须保持这些概念分离。 - ---- - -## P3:Low Latency / Frame Control 回归测试 - -### TODO-13:正式锁定 latest-frame-wins 的行为语义 - -* [ ] 测试 pending frame 被替换 -* [ ] 测试 rendering frame 不会被中断 -* [ ] 测试事件修改模型后,新 snapshot 能看到状态 -* [ ] 测试被替换 frame 不会导致权威模型状态丢失 -* [ ] 测试 burst input: - - * mouse move - * resize - * camera control - * rapid data update -* [ ] 记录: - - * produced frames - * rendered frames - * dropped/replaced frames - * input-to-present latency - -明确: - -```text -丢的是待展示/待处理 frame -不是 authoritative scene state -``` - ---- - -## P3:Runtime 压测 - -### TODO-14:建立标准 DAG benchmark - -固定测试: - -```text -10 nodes -50 nodes -100 nodes -500 nodes -1000 nodes -``` - -分别包含: - -```text -完全串行 -完全并行 -树形 -diamond -随机 DAG -CPU + External 混合 DAG -``` - -记录: - -* [ ] graph compile time -* [ ] runtime setup time -* [ ] scheduler wait -* [ ] total CPU work -* [ ] wall time -* [ ] parallelism -* [ ] Taskflow worker utilization -* [ ] Runtime lock contention -* [ ] completion callback cost - -后续任何 scheduler 改造都与此 benchmark 对比。 - ---- - -### TODO-15:建立 Renderive 实际 workload benchmark - -不要只做 synthetic benchmark。 - -至少保留: - -* [ ] 纯 2D 场景 -* [ ] 小型 3D point scene -* [ ] 大型 3D point scene -* [ ] 多 Renderable dependency -* [ ] frequent update -* [ ] low-latency input -* [ ] GPU-heavy -* [ ] CPU-heavy -* [ ] mixed CPU/GPU - -每次架构改造比较: - -```text -P50 -P95 -P99 - -critical path -scheduler wait -CPU work -GPU duration -frame age -memory -thread count -``` - ---- - -# 暂时不要做的事情 - -下面这些目前没有证据证明值得做: - -* [ ] **不要**再包一层复杂 Taskflow abstraction -* [ ] **不要**给 `Scene_Render_Context` 增加 continuation -* [ ] **不要**为了异步统一而全面 coroutine 化 -* [ ] **不要**现在实现 multi-frame-in-flight -* [ ] **不要**仅为了减少线程数重写整个 Scene scheduler -* [ ] **不要**仅为了“架构漂亮”拆 Scene_Base -* [ ] **不要**重复实现 Taskflow 自己已经能完成的线程池能力 -* [ ] **不要**在没有 profiler 数据时优化 DAG 微小调度开销 - ---- - -# 建议执行顺序 - -```text -第一阶段:正确性 - TODO-01 External Operation 生命周期 - TODO-02 failure / cancellation - TODO-09 Datoviz 异常路径 - -第二阶段:长期运行稳定性 - TODO-03 Render Plan History - TODO-10/11/12 观测数据可信度 - -第三阶段:CPU Runtime 成本 - TODO-04 Render Plan compiled layout - TODO-14 synthetic benchmark - TODO-15 real workload benchmark - -第四阶段:规模化 - TODO-05 多 Scene thread model - TODO-06 multi-frame-in-flight 是否真的需要 - -持续性约束 - TODO-07 Scene_Base 边界 - TODO-08 Taskflow implementation-detail 边界 - TODO-13 Low Latency 回归测试 -``` - -## 最终原则 - -每一项都严格走: - -```text -提出怀疑 - ↓ -写最小复现 / benchmark - ↓ -确认问题是否真实存在 - ↓ -量化严重程度 - ↓ -定义行为 contract - ↓ -再修改实现 - ↓ -回归测试 + benchmark -``` - -不要变成: - -```text -看到一个理论缺陷 - ↓ -立刻重新设计架构 -``` - -现阶段 Renderive 更需要的是**验证和收敛**,而不是继续扩张调度抽象。