Untoon Engine
Trace-Macro-Reference
本页目录
追踪宏速查
这里整理 Unreal 渲染代码里常用的追踪、统计和内存标记宏,方便给 Untoon pass 起统一的观测名字。这些宏只影响可观测性,不该改变渲染结果。
适用场景:
- 在 Unreal Insights 中查看 CPU / RDG / GPU timeline
- 在
stat系统中查看 CPU cycle 或计数 - 在 CSV profiler 中导出性能数据
- 在 Low Level Memory Tracker 中归类内存分配
- 给 RHI breadcrumb / GPU crash marker 提供可读名字
基本原则
优先选择静态名字,避免在高频路径中构造动态字符串。能用 TRACE_CPUPROFILER_EVENT_SCOPE(RenderToonLightPass) 时,不要为了显示同样名字改用动态 FString。
在 Engine/Source/Runtime/Renderer/Private/Untoon 下新增 pass 时,至少放这几个宏:
LLM_SCOPE_BYNAME(TEXT("Untoon.LightPass"));
RDG_CSV_STAT_EXCLUSIVE_SCOPE(GraphBuilder, Toon);
SCOPED_NAMED_EVENT(FDeferredShadingSceneRenderer_RenderToonLightPass, FColor::Turquoise);
SCOPE_CYCLE_COUNTER(STAT_CLP_ToonLightPass);
RDG_EVENT_SCOPE_STAT(GraphBuilder, ToonLightPass, "ToonLightPass");
这些宏分别覆盖 LLM、CSV、CPU named event / CPU trace、stat cycle counter、RDG / GPU stat。
RDG 与 RHI 宏
常用头文件:
Engine/Source/Runtime/RenderCore/Public/RenderGraphEvent.hEngine/Source/Runtime/RHI/Public/RHIBreadcrumbs.hEngine/Source/Runtime/RenderCore/Public/ProfilingDebugging/RealtimeGPUProfiler.h
| 宏 | 用途 | 常见位置 | 备注 |
|---|---|---|---|
RDG_EVENT_NAME("Name") |
给 GraphBuilder.AddPass / AddDispatchPass 提供 pass 名称 |
RDG pass 创建处 | 只是名字对象,通常传给 RDG_EVENT_NAME(...) 参数 |
RDG_EVENT_NAME("Name%d", Index) |
创建带参数的 RDG pass 名称 | per-view / per-stage pass | 动态格式化比静态名字更贵,必要时再用 |
RDG_EVENT_SCOPE(GraphBuilder, "Name") |
在 RDG timeline 中创建作用域 | pass 调度函数顶层或子阶段 | 不绑定 GPU stat |
RDG_EVENT_SCOPE_STAT(GraphBuilder, StatName, "Name") |
创建 RDG 作用域并绑定 GPU stat | 主要渲染 pass 顶层 | StatName 需要先声明 DECLARE_GPU_STAT 或 DECLARE_GPU_DRAWCALL_STAT |
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Condition, "Name") |
条件创建 RDG 作用域 | 多 view、debug-only 或可选阶段 | 常用于 Views.Num() > 1 的 per-view 标记 |
RDG_EVENT_SCOPE_CONDITIONAL_STAT(GraphBuilder, Condition, StatName, "Name") |
条件 RDG 作用域并绑定 GPU stat | 可选 GPU 阶段 | 条件为 false 时不创建 |
RDG_EVENT_SCOPE_FINAL(GraphBuilder, "Name") |
创建 final RDG 作用域 | 需要压住子事件的聚合区域 | 会禁用同类嵌套 scope,谨慎使用 |
RDG_RHI_EVENT_SCOPE(GraphBuilder, Name) |
同时加 RDG scope 和 RHI breadcrumb | RHI 命令明显分段处 | Name 参数会被字符串化 |
RDG_RHI_EVENT_SCOPE_STAT(GraphBuilder, Stat, Name) |
同时加 RDG scope、RHI breadcrumb 和 GPU stat | 重要 GPU 阶段 | 适合 render target 分配、visibility、主要 pass |
RHI_BREADCRUMB_EVENT(RHICmdList, "Name") |
给 RHI command list 加 breadcrumb | 非 RDG 或底层 RHI 代码 | 用于 GPU crash marker / RHI timeline |
RHI_BREADCRUMB_EVENT_STAT(RHICmdList, Stat, "Name") |
RHI breadcrumb 并绑定 GPU stat | 非 RDG GPU 区间 | RDG 代码优先用 RDG_RHI_EVENT_SCOPE_STAT |
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask) |
限定 RDG pass 的 GPU mask | 多 GPU / per-view pass | 常和 per-view scope 一起使用 |
RDG_CSV_STAT_EXCLUSIVE_SCOPE(GraphBuilder, StatName) |
在 RDG scope 生命周期内记录 CSV exclusive stat | RDG pass 顶层 | 依赖 CSV_PROFILER_STATS |
GPU Stat 声明宏
| 宏 | 用途 | 常见位置 | 备注 |
|---|---|---|---|
DECLARE_GPU_STAT(StatName) |
声明一个 GPU stat | .cpp 文件顶层 |
用于 RDG_EVENT_SCOPE_STAT |
DECLARE_GPU_STAT_NAMED(StatName, TEXT("Display Name")) |
声明带显示名的 GPU stat | .cpp 文件顶层 |
显示名需要更友好时使用 |
DECLARE_GPU_STAT_EXTERN(StatName) |
在头文件声明外部 GPU stat | .h 文件 |
与 DEFINE_GPU_STAT 配对 |
DEFINE_GPU_STAT(StatName) |
定义外部 GPU stat | 一个 .cpp 文件 |
避免多重定义 |
DECLARE_GPU_DRAWCALL_STAT(StatName) |
声明带 drawcall 分类的 GPU stat | mesh pass / raster pass .cpp |
适合 BasePass、ShadowDepth、Untoon mesh pass |
DECLARE_GPU_DRAWCALL_STAT_NAMED(StatName, TEXT("Display Name")) |
声明带显示名的 drawcall GPU stat | .cpp 文件顶层 |
名字需要空格或更清晰时使用 |
DECLARE_GPU_DRAWCALL_STAT_EXTERN(StatName) |
头文件外部声明 drawcall GPU stat | .h 文件 |
与 DEFINE_GPU_DRAWCALL_STAT 配对 |
DEFINE_GPU_DRAWCALL_STAT(StatName) |
定义外部 drawcall GPU stat | 一个 .cpp 文件 |
用于跨文件共享 stat |
Unreal 5.8 中旧式 SCOPED_GPU_STAT / RDG_GPU_STAT_SCOPE 已废弃。新代码应优先使用 RDG_EVENT_SCOPE_STAT 或 RHI_BREADCRUMB_EVENT_STAT。
CPU Named Event 宏
常用头文件:
Engine/Source/Runtime/Core/Public/HAL/PlatformMisc.hEngine/Source/Runtime/Core/Public/ProfilingDebugging/CpuProfilerTrace.h
| 宏 | 用途 | 常见位置 | 备注 |
|---|---|---|---|
SCOPED_NAMED_EVENT(Name, Color) |
创建外部 profiler named event,并同步创建 CPU trace scope | 渲染函数顶层 | Name 是 token,会字符串化 |
SCOPED_NAMED_EVENT_TEXT("Name", Color) |
使用静态文本创建 named event | 需要字符串字面量时 | 静态名字开销低 |
SCOPED_NAMED_EVENT_TCHAR(Text, Color) |
使用 TCHAR* 创建 named event |
已有 TCHAR* 名称时 |
比静态 token 更动态 |
SCOPED_NAMED_EVENT_FSTRING(Text, Color) |
使用 FString 创建 named event |
debug 或低频路径 | 会解引用 *Text,高频路径谨慎使用 |
SCOPED_NAMED_EVENT_F(Format, Color, ...) |
格式化 named event | per-view debug 名称 | 格式化有额外成本 |
SCOPED_NAMED_EVENT_TCHAR_CONDITIONAL(Text, Color, Condition) |
条件 named event | 可选阶段 | 条件 false 时不开始 named event |
SCOPED_ENTER_BACKGROUND_EVENT(Name) |
标记进入后台相关任务 | 平台生命周期代码 | 渲染 pass 中少见 |
SCOPED_NAMED_EVENT 在 named event 关闭时仍会退化为 TRACE_CPUPROFILER_EVENT_SCOPE,因此它也是 CPU trace 的常见入口。
CPU Trace 宏
| 宏 | 用途 | 常见位置 | 备注 |
|---|---|---|---|
TRACE_CPUPROFILER_EVENT_SCOPE(Name) |
创建静态 CPU trace 作用域 | 普通 C++ 函数或 lambda 内 | 推荐用于大多数 CPU 区间 |
TRACE_CPUPROFILER_EVENT_SCOPE_CONDITIONAL(Name, Condition) |
条件 CPU trace 作用域 | 可选或 debug 路径 | 条件 false 时不开启 |
TRACE_CPUPROFILER_EVENT_SCOPE_STR("Name") |
使用静态字符串创建 CPU trace | 名字不是合法 token 时 | 字符串指针应稳定 |
TRACE_CPUPROFILER_EVENT_SCOPE_STR_CONDITIONAL("Name", Condition) |
条件静态字符串 trace | 可选阶段 | 比动态字符串更轻 |
TRACE_CPUPROFILER_EVENT_SCOPE_TEXT(Text) |
使用动态字符串创建 CPU trace | 动态 pass 名称 | 开销更高,必要时使用 |
TRACE_CPUPROFILER_EVENT_SCOPE_TEXT_CONDITIONAL(Text, Condition) |
条件动态字符串 trace | 低频动态命名 | 避免高频滥用 |
TRACE_CPUPROFILER_EVENT_SCOPE_ON_CHANNEL(Name, Channel) |
只在指定 trace channel 开启时记录 | 专用 trace channel | 需要同时开启 CpuChannel 和指定 channel |
TRACE_CPUPROFILER_EVENT_SCOPE_TEXT_ON_CHANNEL(Text, Channel) |
动态字符串 + 指定 channel | 专用 trace channel | 高频路径谨慎使用 |
TRACE_CPUPROFILER_EVENT_MANUAL_START(Name) |
手动开始 CPU trace 事件 | 不能用 RAII scope 的代码 | 必须配对 manual end |
TRACE_CPUPROFILER_EVENT_MANUAL_END() |
手动结束 CPU trace 事件 | 与 manual start 配对 | 同线程配对 |
TRACE_CPUPROFILER_EVENT_MANUAL_IS_ENABLED() |
判断 manual trace 是否开启 | 避免只为 trace 计算数据 | 常和 manual start 一起用 |
TRACE_CPUPROFILER_EVENT_FLUSH() |
flush 当前线程 trace buffer | 进入长时间等待前 | 低频使用 |
Stats 宏
常用头文件:
Engine/Source/Runtime/Core/Public/Stats/Stats.h
| 宏 | 用途 | 常见位置 | 备注 |
|---|---|---|---|
DECLARE_STATS_GROUP(TEXT("Desc"), STATGROUP_Name, STATCAT_Advanced) |
声明 stat group | 模块 .cpp 或公共头 |
新建大类时使用 |
DECLARE_STATS_GROUP_VERBOSE(...) |
声明默认关闭的 stat group | 详细/低频统计 | 避免默认污染 stat 输出 |
DECLARE_CYCLE_STAT(TEXT("Desc"), STAT_Name, STATGROUP_Group) |
声明 CPU cycle stat | .cpp 文件顶层 |
与 SCOPE_CYCLE_COUNTER 配对 |
DECLARE_CYCLE_STAT_EXTERN(..., API) |
头文件外部声明 cycle stat | .h 文件 |
与 DEFINE_STAT 相关机制配合 |
DECLARE_DWORD_COUNTER_STAT(TEXT("Desc"), STAT_Name, STATGROUP_Group) |
声明每帧清零整数计数 | 顶层 | 常用于数量统计 |
DECLARE_FLOAT_COUNTER_STAT(TEXT("Desc"), STAT_Name, STATGROUP_Group) |
声明每帧清零浮点计数 | 顶层 | 常用于比例或耗时辅助 |
DECLARE_DWORD_ACCUMULATOR_STAT(TEXT("Desc"), STAT_Name, STATGROUP_Group) |
声明累积整数 | 顶层 | 不会每帧自动清零 |
DECLARE_FLOAT_ACCUMULATOR_STAT(TEXT("Desc"), STAT_Name, STATGROUP_Group) |
声明累积浮点数 | 顶层 | 适合长期累计 |
DECLARE_MEMORY_STAT(TEXT("Desc"), STAT_Name, STATGROUP_Group) |
声明内存 stat | 顶层 | 粗粒度内存统计 |
DECLARE_MEMORY_STAT_POOL(TEXT("Desc"), STAT_Name, STATGROUP_Group, Pool) |
声明指定内存池 stat | 顶层 | 需要指定 FPlatformMemory region |
SCOPE_CYCLE_COUNTER(STAT_Name) |
记录当前作用域 CPU cycle | 函数或代码块内 | 需要先 DECLARE_CYCLE_STAT |
QUICK_SCOPE_CYCLE_COUNTER(STAT_Name) |
快速声明并记录临时 cycle stat | 局部临时分析 | 不适合长期公共命名规范 |
SCOPE_CYCLE_COUNTER_STATID(StatId) |
使用动态 TStatId 记录 cycle |
框架/动态 stat | 普通 pass 少用 |
CONDITIONAL_SCOPE_CYCLE_COUNTER(STAT_Name, Condition) |
条件 CPU cycle scope | 可选路径 | 条件 false 时空 stat id |
SCOPE_SECONDS_ACCUMULATOR(STAT_Name) |
累积秒数 | 长期累计耗时 | 与 accumulator stat 配合 |
SCOPE_MS_ACCUMULATOR(STAT_Name) |
累积毫秒 | 长期累计耗时 | 输出单位是 ms |
INC_DWORD_STAT(STAT_Name) |
计数 +1 | 事件计数 | 每帧或累计取决于 stat 声明 |
INC_DWORD_STAT_BY(STAT_Name, Amount) |
整数计数增加 | 数量统计 | Amount 为 0 时不发送 |
DEC_DWORD_STAT(STAT_Name) |
计数 -1 | 数量统计 | 与 inc 对称 |
DEC_DWORD_STAT_BY(STAT_Name, Amount) |
整数计数减少 | 数量统计 | Amount 为 0 时不发送 |
INC_FLOAT_STAT_BY(STAT_Name, Amount) |
浮点计数增加 | 比例/权重统计 | Amount 为 0 时不发送 |
DEC_FLOAT_STAT_BY(STAT_Name, Amount) |
浮点计数减少 | 比例/权重统计 | Amount 为 0 时不发送 |
SET_DWORD_STAT(STAT_Name, Value) |
设置整数 stat 当前值 | Nanite bins / light count 等 | 适合最终值 |
SET_FLOAT_STAT(STAT_Name, Value) |
设置浮点 stat 当前值 | 比例、时间等 | 适合最终值 |
INC_MEMORY_STAT_BY(STAT_Name, Amount) |
增加内存 stat | 手动内存统计 | 与 LLM 不是同一系统 |
DEC_MEMORY_STAT_BY(STAT_Name, Amount) |
减少内存 stat | 手动内存统计 | 与 inc 配对 |
CSV Profiler 宏
常用头文件:
Engine/Source/Runtime/Core/Public/ProfilingDebugging/CsvProfiler.h
| 宏 | 用途 | 常见位置 | 备注 |
|---|---|---|---|
CSV_DEFINE_CATEGORY(Category, true) |
定义 CSV 分类 | .cpp 顶层 |
true 表示默认开启 |
CSV_DEFINE_CATEGORY_MODULE(API, Category, true) |
模块导出 CSV 分类 | 模块公共统计 | 跨模块时使用 |
CSV_SCOPED_TIMING_STAT_EXCLUSIVE(StatName) |
记录 exclusive CPU 时间 | 非 RDG 代码块 | 直接写入 CSV profiler |
CSV_SCOPED_TIMING_STAT_EXCLUSIVE_CONDITIONAL(StatName, Condition) |
条件 exclusive CPU 时间 | 可选路径 | 条件 false 时不记录 |
RDG_CSV_STAT_EXCLUSIVE_SCOPE(GraphBuilder, StatName) |
RDG 生命周期内 exclusive CSV stat | RDG pass | RDG pass 优先使用这个 |
CSV_CUSTOM_STAT(Category, StatName, Value, Op) |
写入自定义 CSV 数值 | light count、pass count | Op 常用 Set / Accumulate |
CSV_CUSTOM_STAT_GLOBAL(StatName, Value, Op) |
写入全局自定义 CSV 数值 | 全局指标 | 不挂特定 category |
CSV_CUSTOM_STAT_MINIMAL(Category, StatName, Value, Op) |
更轻量的自定义 stat | 高频基础指标 | 功能较少 |
LLM 内存宏
常用头文件:
Engine/Source/Runtime/Core/Public/HAL/LowLevelMemTracker.h
| 宏 | 用途 | 常见位置 | 备注 |
|---|---|---|---|
LLM_SCOPE(ELLMTag::Tag) |
将作用域内分配归类到内置 LLM tag | 系统级代码 | tag 来自 ELLMTag |
LLM_SCOPE_BYNAME(TEXT("Name")) |
使用自定义名字归类内存 | Untoon 自有系统 | 适合 Untoon.LightPass 等 |
LLM_SCOPE_BYTAG(TagDeclName) |
使用声明过的 LLM tag | 有全局 tag 声明的系统 | 依赖 LLM_DECLARE_TAG 系列 |
LLM_SCOPE_DYNAMIC(UniqueName, Tracker, TagSet, Constructor) |
动态 LLM scope | 资产、对象、动态名字 | 成本更高 |
LLM_SCOPE_RENDER_RESOURCE(Tag) |
归类 render resource 内存 | Render resource 创建 | 带 RenderResources. 前缀 |
LLM_PLATFORM_SCOPE(ELLMTag::Tag) |
平台 tracker scope | 底层平台分配 | 和 default tracker 不同 |
LLM_SCOPE_CLEAR() |
清空当前 LLM scope | 需要避免继承外层 tag 时 | 低频使用 |
LLM_SCOPED_PAUSE_TRACKING(AllocType) |
暂停指定分配类型追踪 | LLM 内部或特殊 allocator | 谨慎使用 |
LLM_IF_ENABLED(Code) |
LLM 开启时执行代码 | 避免无谓计算 | 宏参数是代码片段 |
LLM_IS_ENABLED() |
查询 LLM 是否开启 | 条件分支 | 可避免构建昂贵名字 |
LLM_DEFINE_TAG(TagDeclName, DisplayName, ParentTagName) |
定义可跨文件使用的 LLM tag | 一个 .cpp 文件 |
后两个参数可按宏定义省略或继续传 stat 信息 |
LLM_DEFINE_STATIC_TAG(TagDeclName, DisplayName, ParentTagName) |
定义文件内静态 LLM tag | .cpp 文件顶层 |
不需要跨文件引用时使用 |
LLM_DECLARE_TAG(TagDeclName) |
声明由 LLM_DEFINE_TAG 定义的外部 LLM tag |
.h 或使用方 .cpp |
与 LLM_SCOPE_BYTAG 配合 |
LLM_DECLARE_TAG_API(TagDeclName, ModuleAPI) |
声明带模块导出符号的外部 LLM tag | 公共头文件 | 跨模块使用时需要 |
LLM_TAG_NAME(TagDeclName) |
获取声明 tag 的唯一 FName |
需要把 tag name 传给底层接口时 | 普通 scope 代码通常不需要 |
Untoon pass 里一般优先使用 LLM_SCOPE_BYNAME(TEXT("Untoon.X")),除非这个内存分类需要跨文件长期复用,再考虑声明正式 LLM tag。
选择建议
| 目标 | 推荐宏 |
|---|---|
| 想在 RDG / GPU timeline 中看到一个 pass | RDG_EVENT_SCOPE_STAT |
想给 GraphBuilder.AddPass 命名 |
RDG_EVENT_NAME |
| 想在多 view 下区分每个 view | RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex) |
| 想在 CPU timeline 中看到函数耗时 | TRACE_CPUPROFILER_EVENT_SCOPE 或 SCOPED_NAMED_EVENT |
| 想在外部 profiler / GPU marker 中看到名字 | SCOPED_NAMED_EVENT 或 RHI_BREADCRUMB_EVENT |
想在 stat SceneRendering 中看到 CPU cycle |
DECLARE_CYCLE_STAT + SCOPE_CYCLE_COUNTER |
| 想统计数量、bin 数、light 数 | DECLARE_DWORD_COUNTER_STAT + SET_DWORD_STAT |
| 想导出 CSV 性能数据 | RDG_CSV_STAT_EXCLUSIVE_SCOPE 或 CSV_CUSTOM_STAT |
| 想知道内存分配属于哪个 Untoon 系统 | LLM_SCOPE_BYNAME(TEXT("Untoon.X")) |
Untoon 命名建议
Untoon 自有 pass 建议使用稳定、可搜索的名字:
| 子系统 | 建议 RDG / GPU stat 名 | 建议 LLM 名 |
|---|---|---|
| Shadow Mask | ToonShadowMaskPass |
Untoon.ShadowMask |
| Shadow Blur / Bloom | UntoonShadowBloom |
Untoon.ShadowBloom |
| Light Pass | ToonLightPass |
Untoon.LightPass |
| Outline | ToonOutlinePass |
Untoon.Outline |
| Nanite Shadow Mask export | ToonShadowMaskNanite |
继承 Shadow Mask 外层 scope |
| Nanite Light export | ToonLightPassNanite |
继承 Light Pass 外层 scope |
注意事项
- 不要把 Untoon pass 的 cycle counter 归到上游无关 stat,例如 Water、Translucency 或 BasePass。
- 不要在高频 per-pixel、per-primitive 循环中构造动态 profiler 名字。
- 不要继续新增已废弃的
SCOPED_GPU_STAT、RDG_GPU_STAT_SCOPE。 - 不要为了追踪宏改动 shader 或渲染结果。
- 上游文件中新增 Untoon 追踪宏仍然属于 Untoon 改动,必须遵守 marker 规则。
- Untoon 自有目录
Engine/Source/Runtime/Renderer/Private/Untoon内不需要Untoon Engine Start/Endmarker。
参考源码
Engine/Source/Runtime/RenderCore/Public/RenderGraphEvent.hEngine/Source/Runtime/RenderCore/Public/ProfilingDebugging/RealtimeGPUProfiler.hEngine/Source/Runtime/RHI/Public/RHIBreadcrumbs.hEngine/Source/Runtime/Core/Public/HAL/PlatformMisc.hEngine/Source/Runtime/Core/Public/ProfilingDebugging/CpuProfilerTrace.hEngine/Source/Runtime/Core/Public/Stats/Stats.hEngine/Source/Runtime/Core/Public/ProfilingDebugging/CsvProfiler.hEngine/Source/Runtime/Core/Public/HAL/LowLevelMemTracker.h