性能分析工具Tracy
简介
Tracy 是一个低侵入、超低开销、支持多线程的实时性能分析器(Profiler)。通过这个工具可以把运行的时间结构完整画出来。网址:https://github.com/wolfpld/tracy.git
工作原理
通过在代码里面进行主动标记区间,程序把时间信息通过socket发送给Tracy GUI,通过GUI显示时间线。
配置方法
- 拉Tracy代码
git clone https://github.com/wolfpld/tracy.git
主要使用Tray/Tracy.hpp放入到项目中
- 在项目中启用Tracy,或者Debug 配置才开。
add_definitions(-DTRACY_ENABLE)
// debug模式
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DTRACY_ENABLE)
endif()
- 加入头文件
#include "Tracy.hpp"
常用的5种用法
- ZoneScoped —— 最常用(代码块计时) 作用域结束 = 自动结束计时
void StepPhysics()
{
ZoneScoped;
SolveConstraints();
Integrate();
}
Tracy GUI 里你会看到:
Thread Main └─ StepPhysics ├─ SolveConstraints └─ Integrate
- ZoneScopedN(“名字”) —— 给区间起名 ZoneScopedN(“NarrowPhase”);
强烈推荐在:物理阶段
渲染 Pass
Job 执行点
3️⃣ 多线程分析(Tracy 的强项) void WorkerThread() { tracy::SetThreadName(“PhysicsWorker”); ZoneScoped; }
你会在 GUI 里看到:
Main
PhysicsWorker
RenderThread
Job-3 / Job-7 …
👉 这点对你做物理引擎 / Bullet 类系统非常重要
4️⃣ 帧标记(游戏 / 仿真必用) void Tick() { FrameMark; }
GUI 会显示:
FPS
Frame Time
每帧内部结构
📌 没有 FrameMark,你看到的是“时间流”,不是“帧”。
5️⃣ 动态 Zone(循环里区分) for(int i = 0; i < islands; ++i) { ZoneScoped; ZoneName(“Island”, 6); SolveIsland(i); }
用于:
多岛约束
多刚体
多 task
五、物理 / 引擎开发里,Tracy 的正确打开方式
结合你现在在做的 物理引擎 / Bullet 约束研究,我给你一个推荐埋点结构👇
1️⃣ 物理 Step 分层 void PhysicsWorld::Step() { ZoneScopedN(“PhysicsStep”);
{
ZoneScopedN("Broadphase");
RunBroadphase();
}
{
ZoneScopedN("Narrowphase");
RunNarrowphase();
}
{
ZoneScopedN("SolveConstraints");
SolveConstraints();
}
{
ZoneScopedN("Integrate");
IntegrateBodies();
}
}
你能一眼看到:
Broadphase 是否被 DBVT 拖慢
Solver 是不是吃掉 70% 帧时间
2️⃣ Solver 内部(非常关键) void SolveConstraints() { ZoneScopedN(“PGS Solver”);
for(int iter = 0; iter < iterations; ++iter)
{
ZoneScopedN("Iteration");
SolveIteration();
}
}
👉 你会直观看到:
迭代次数 vs 时间
是否 early-out 有意义
3️⃣ Job / 多线程调度 void RunJob(Job& job) { ZoneScopedN(“Job”); job.Execute(); }
Tracy 会告诉你:
线程是否负载均衡
是否有线程空转
Job 粒度是否太小
六、Tracy 的“进阶但非常有用”的功能 1️⃣ 锁竞争分析(神器) std::mutex mtx; TracyLockable(std::mutex, mtx);
GUI 中直接看到:
谁在等锁
等多久
哪个线程卡住全局
👉 对物理世界写锁 / 读锁非常致命的问题,一眼暴露。
2️⃣ 内存分配追踪(查抖动) void* operator new(size_t size) { void* ptr = malloc(size); TracyAlloc(ptr, size); return ptr; }
你可以看到:
每帧 malloc 次数
是否 solver 在疯狂分配临时对象
3️⃣ GPU Profiling(如果你用 OpenGL / Vulkan) TracyGpuZone(“ShadowPass”);
可对齐:
CPU → GPU 提交
GPU Pass 耗时
七、Tracy 使用中的 5 个“经验级”建议 ✅ 1. 不要全函数打点
打“阶段”,不打“每个小函数”
否则 GUI 会炸。
✅ 2. 先粗后细
第一轮:Physics / Render / AI
第二轮:Solver / Narrowphase
第三轮:单个算法
✅ 3. 真实负载下测
Debug + Tracy
Release + Tracy(非常重要)
Tracy 在 Release 下也很好用。
✅ 4. 不要怕“侵入”
Tracy 的宏:
清晰
可控
可全局关
比采样 profiler 更适合引擎开发。
✅ 5. Tracy ≠ Benchmark
Tracy 看的是:
结构
分布
卡顿来源
Benchmark 还是要单独做。