You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Tracy中追踪整帧调用栈而无需逐函数添加ZoneScoped?

如何通过插桩让Tracy自动追踪整帧所有函数调用

当然可以,不需要手动给每个函数加ZoneScoped,利用编译器插桩功能结合Tracy的API就能实现整帧全函数调用追踪,以下是具体实现方案:

核心思路

借助编译器的函数插桩特性,在所有函数的入口/出口自动插入回调,再将这些回调与Tracy的Zone追踪API绑定,同时通过帧激活状态过滤,只记录你关心的帧范围内的函数调用。

具体步骤

1. 启用编译器插桩选项

根据你使用的编译器添加对应编译参数:

  • GCC/Clang:添加 -finstrument-functions,该参数会让编译器在每个函数入口插入__cyg_profile_func_enter调用,出口插入__cyg_profile_func_exit调用。
  • MSVC:使用 /Gh(生成函数进入钩子)和 /GH(生成函数退出钩子)参数,对应触发_penter和_pexit函数。

2. 实现Tracy绑定的钩子函数

将编译器生成的钩子与Tracy的Zone API关联,同时通过帧状态控制只追踪目标帧:

#include <tracy/Tracy.hpp>
#include <cstdint>

// 仅在需要追踪的帧范围内启用插桩记录
bool g_isFrameActive = false;

// GCC/Clang 版本钩子
extern "C" void __cyg_profile_func_enter(void* this_fn, void* call_site)
{
    if (g_isFrameActive)
    {
        TracyZoneBegin((uintptr_t)this_fn, (uintptr_t)call_site);
    }
}

extern "C" void __cyg_profile_func_exit(void* this_fn, void* call_site)
{
    if (g_isFrameActive)
    {
        TracyZoneEnd((uintptr_t)this_fn);
    }
}

// MSVC 版本钩子(需单独实现)
#ifdef _MSC_VER
extern "C" void __declspec(naked) _penter()
{
    __asm {
        push ebp
        mov ebp, esp
        push ecx
        push edx
        call _penter_impl
        pop edx
        pop ecx
        pop ebp
        ret
    }
}

extern "C" void _penter_impl(void* this_fn, void* call_site)
{
    if (g_isFrameActive)
    {
        TracyZoneBegin((uintptr_t)this_fn, (uintptr_t)call_site);
    }
}

extern "C" void __declspec(naked) _pexit()
{
    __asm {
        push ebp
        mov ebp, esp
        push ecx
        push edx
        call _pexit_impl
        pop edx
        pop ecx
        pop ebp
        ret
    }
}

extern "C" void _pexit_impl(void* this_fn, void* call_site)
{
    if (g_isFrameActive)
    {
        TracyZoneEnd((uintptr_t)this_fn);
    }
}
#endif

3. 控制帧的追踪范围

在你的帧循环中手动标记追踪的开始和结束:

while (isRunning)
{
    // 开始追踪当前帧
    g_isFrameActive = true;
    TracyFrameMarkStart(); // 可选,用于Tracy中标记帧开始

    // 你的帧逻辑代码...

    // 结束当前帧追踪
    TracyFrameMark(); // 标记帧结束
    g_isFrameActive = false;
}

4. 过滤无关函数(可选)

全量插桩会捕获包括标准库、系统函数在内的所有调用,可能导致追踪数据过载,你可以通过以下方式过滤:

  • GCC/Clang:添加编译参数 -finstrument-functions-exclude-file-list=/usr/include,stdlib.h 排除标准库文件;或者用 -finstrument-functions-exclude-function-list=printf,malloc 排除特定函数。
  • MSVC:通过链接器脚本或在钩子函数中判断函数地址范围,只保留你自己代码段的函数调用。

5. 性能优化建议

全量插桩会带来一定性能损耗,建议:

  • 仅在需要性能分析的构建中启用插桩(比如通过TRACY_ENABLE宏控制)。
  • 对高频调用的小型函数(如getter/setter),可以通过编译器参数或手动过滤排除,减少追踪开销。

内容的提问来源于stack exchange,提问作者Alkyone

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 10:34:51