Files
XCEngine/docs/api/_guides/Debug/Profiler-Workflow.md

110 lines
3.1 KiB
Markdown
Raw Normal View History

2026-03-26 17:21:44 +08:00
# Profiler Workflow
## 先说结论
`XCEngine::Debug::Profiler` 当前不是成熟的分析器,而是一个“轻量级 CPU 埋点接口壳”。它已经能表示 profile 区段,但还没有形成完整的数据消费闭环。
这不是坏事,但文档和使用方式必须诚实:
- 它适合做早期埋点。
- 它不适合被描述成 Unity Profiler 那种完整时间线工具。
## 现在真正能做什么
当前实现中,`BeginProfile` / `EndProfile` 会记录:
- 区段名
- 开始时间
- 结束时间
- 线程哈希
这证明设计方向是对的:接口已经在向“作用域埋点”靠拢。
但是同一时间,以下能力还没打通:
- 没有公开的样本读取 API。
- `MarkEvent``SetMarker``ExportChromeTracing` 仍是空实现。
- `EndFrame` 会直接清空样本。
所以当前更合理的定位是:
- 先把埋点位置和调用习惯稳定下来;
- 再逐步补数据导出、可视化和多线程时间线。
## 为什么先做成单例
对调试工具而言,单例有一个现实优势:调用点成本极低。
```cpp
XE_PROFILE_FUNCTION();
```
这种接法非常适合逐步给引擎关键路径加埋点,而不需要把 profiler 对象层层传递。
代价也很明显:
- 当前实现只有一个全局栈。
- 如果多个线程同时写入,栈结构和样本语义都会混乱。
这就是为什么文档必须明确写“当前只适合受控单线程埋点”。
## 推荐工作流
当前阶段推荐把 `Profiler` 用在下面这些场景:
1. 主线程 CPU 热路径粗测。
2. 某个函数或阶段的进入/退出埋点。
3. 为未来时间线导出预留稳定的区段命名。
推荐写法:
```cpp
using namespace XCEngine::Debug;
Profiler::Get().Initialize();
Profiler::Get().BeginFrame();
XE_PROFILE_BEGIN("SceneUpdate");
// ...
XE_PROFILE_END();
Profiler::Get().EndFrame();
```
## 和 Unity Profiler 的差异
可以把它理解为“还在早期形态的引擎内 CPU 埋点接口”,而不是 Unity Profiler 的直接对标物。
Unity Profiler 已经提供:
- 完整的帧时间线
- 多线程可视化
- 统计聚合
- UI 分析工具
XCEngine 当前的 `Profiler` 还没有这些能力。它更像是先把“埋点 API”立住再逐步扩展后端。
## 当前使用时最该注意的事
- `BeginProfile` / `EndProfile` 必须按栈顺序配对。
- 不要跨线程共享同一条 profile 栈。
- 不要指望 `ExportChromeTracing` 现在就会产出文件。
- 如果你在 `EndFrame` 之后再找样本,当前实现里它们已经被清掉了。
## 下一阶段最值得补的能力
如果继续把这个模块做实,最有价值的方向通常是:
1. 暴露只读样本访问接口。
2. 把样本按线程分桶。
3. 实现 Chrome Trace / Perfetto 导出。
4. 在编辑器里增加最小时间线浏览能力。
## 相关 API
- [Debug](../../XCEngine/Debug/Debug.md)
- [Profiler](../../XCEngine/Debug/Profiler/Profiler.md)
- [BeginProfile](../../XCEngine/Debug/Profiler/BeginProfile.md)
- [EndProfile](../../XCEngine/Debug/Profiler/EndProfile.md)
- [ExportChromeTracing](../../XCEngine/Debug/Profiler/ExportChromeTracing.md)