Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

性能分析工具Tracy

简介

Tracy 是一个低侵入、超低开销、支持多线程的实时性能分析器(Profiler)。通过这个工具可以把运行的时间结构完整画出来。网址:https://github.com/wolfpld/tracy.git

工作原理

通过在代码里面进行主动标记区间,程序把时间信息通过socket发送给Tracy GUI,通过GUI显示时间线。

配置方法

  1. 拉Tracy代码
git clone https://github.com/wolfpld/tracy.git

主要使用Tray/Tracy.hpp放入到项目中

  1. 在项目中启用Tracy,或者Debug 配置才开。
add_definitions(-DTRACY_ENABLE)

// debug模式
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    add_definitions(-DTRACY_ENABLE)
endif()

  1. 加入头文件
#include "Tracy.hpp"

常用的5种用法

  1. ZoneScoped —— 最常用(代码块计时) 作用域结束 = 自动结束计时
void StepPhysics()
{
    ZoneScoped;
    SolveConstraints();
    Integrate();
}

Tracy GUI 里你会看到:

Thread Main └─ StepPhysics ├─ SolveConstraints └─ Integrate

  1. 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 还是要单独做。