chrome tracing json必须顶层为{"traceevents":[...]},每个事件含name、cat、ph、ts(微秒)、pid、tid字段;漏ph或ts会静默丢弃,ts须用steady_clock差值转微秒,pid/tid需真实区分线程,ph推荐'x',cat建议"frame"或"render"。

Chrome Tracing JSON 格式长什么样,为什么必须严格遵循
Chrome Tracing 要求顶层是 traceEvents 数组,每个事件是对象,至少含 name、cat、ph、ts、pid、tid 字段。漏掉 ph(phase)或 ts(微秒级时间戳)会导致 Chrome DevTools 完全不显示任何事件——不是报错,而是静默丢弃。
常见错误:用 std::chrono::system_clock 时间戳(秒级或毫秒级),但 ts 必须是微秒级整数,且以进程启动时刻为 0 基准(推荐用 steady_clock 差值);pid 和 tid 若写死为 1/1,多线程下会叠成一条线,得按实际线程 ID 分配。
-
ph值必须是单字符:B(begin)、E(end)、X(duration,推荐) - 用
X可省去配对B/E,避免漏写 end 导致火焰图截断 -
cat字段建议设为"frame"或"render",方便在 DevTools 的 Categories 面板过滤
如何在每帧开始/结束时记录 TraceEvent 并写入 JSON 文件
不要在游戏主循环里拼接完整 JSON 字符串(内存暴涨、编码易错)。正确做法是:预分配一个 std::vector<traceevent></traceevent>,每帧调用一次 recordFrameEvent(name, start_us, duration_us) 推入事件;退出前一次性序列化为合法 JSON。
关键点:所有时间字段必须是 int64_t,单位微秒;字符串字段(如 name)需 JSON 转义(双引号、反斜杠、控制字符);整个文件末尾不能有多余逗号。
struct TraceEvent {
std::string name;
std::string cat = "frame";
char ph = 'X';
int64_t ts = 0; // microsecond, relative to process start
int32_t pid = 1;
int32_t tid = 1;
int64_t dur = 0;
};
- 用
std::chrono::steady_clock::now()获取高精度时间,减去首次调用时的基准值再乘 1000000 得微秒 -
tid可用std::this_thread::get_id()哈希后取模 1000,避免负数或过大值 - 写文件前调用
json::serialize(events)(推荐 nlohmann/json 库),而非手写"{...}"
导出后 Chrome 打不开?检查这三处硬性限制
即使 JSON 语法合法,Chrome Tracing 仍可能空白显示。最常踩的坑是:
- 根对象不是对象,而是数组(正确结构:{
"traceEvents": [...] }) -
ts全是 0 或负数(steady_clock差值未初始化就调用) - 同一帧内多个
name相同且ts完全一致(Chrome 合并显示,看起来像没数据)
验证方法:把生成的 JSON 拖进 Chrome 地址栏 chrome://tracing,按 Ctrl+Shift+P 输入 “reload trace”,看右上角是否提示 “Loaded 123 events”。若提示 0,打开浏览器控制台(F12 → Console),通常会打印类似 Failed to parse event: missing 'ts' 的具体错误。
如何让帧事件自动关联成“火焰图层级”而非平铺条形图
Chrome 默认把同 cat 同 name 的 X 事件横向排列。要形成火焰图调用栈效果,必须引入嵌套关系——但这需要 ph 为 B/E + id 字段,且同一 id 的 B/E 事件需严格配对。
对游戏帧来说,更实用的做法是:用 name 表达层级,例如 "Render::ShadowPass"、"Render::MainPass"、"GameLogic::UpdateAI",然后在 Chrome Tracing 界面点击右上角 ⚙️ → “Group by” → 选 name,它会自动按冒号分组折叠。
- 避免空格和特殊符号(如
"Update AI"会被截断为"Update") - 如果某帧耗时突增,可在事件里加
"args": {"frame_number": 1234},方便定位 - 导出前可删掉
dur (100μs)的琐碎事件,减少 JSON 体积和渲染卡顿
真正难的是时间基准对齐——steady_clock 在不同线程间不一定完全同步,跨模块计时(比如 Vulkan fence 时间 + CPU 计时)必须统一采样源,否则火焰图会出现逻辑上不可能的重叠或空隙。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











