技术博客

Unreal Insights:Trace 通道、采集模式与一次卡顿定位实录

第 93 / 100 篇 · 2025-11-08 · ue5 · 性能分析Unreal Insights工具链

stat 命令家族(下一篇)是性能问题的第一道防线,但它只有聚合数字——告诉你 GameThread 花了 8ms,不告诉你这 8ms 花在哪。要往下钻,得靠 Unreal Insights:独立进程 UnrealInsights.exe,和引擎之间走一条独立的 Trace 流(TraceLog 模块,默认本地通道,不落盘到引擎进程内存里才解码)。架构上分三块:引擎内的 Trace 发射端、独立的 UnrealTraceServer(后台常驻进程,端口 1981)、分析端 Insights UI。这篇讲通道代价、三种采集姿势,最后走一遍真实排查。

通道(Channels):按域开关的探针

Trace 事件按通道分组:cpu(CPU 时间片)、gpu(GPU 时间戳)、frame(帧边界)、log(日志)、bookmark(书签标记)、memory(LLM 内存标签)……每个通道是一组探针的编译期开关(Trace.cpp 里的 channel 注册,运行时可用 Trace.List 控制台命令列出全部)。编辑器默认开 cpu,gpu,frame,log,bookmark,contrast。

代价模型要记住一条:通道开着 ≠ 事件都发。CPU 探针只在执行到埋点代码时才发射事件;但 cpu 通道本身会把 TRACE_CPUPROFILER_EVENT_SCOPE 宏包住的每个作用域变成计时事件,线程一深,事件流本身就有可观体积。所以原则是给诊断开足通道,给长期监控只开 frame + bookmark。stat namedevents 可以把 STAT 宏的组也纳入 cpu 通道的事件流—— stat 命令族那篇的每个 stat 组都能在 Insights 里变成泳道。

三种采集姿势

  1. 编辑器直连:编辑器默认连接本机 TraceServer,开 Insights 直接选活跃会话。适合开发期。
  2. 命令行注入:游戏启动参数 -tracehost=ip -trace=cpu,gpu,frame,log,把 Trace 流推给远端机器上的 TraceServer——真机(主机/手机) profiling 的唯一实用姿势,因为真机磁盘和内存吃不起本地落盘。
  3. 运行时开关:控制台 Trace.Start channel,list / Trace.Stop,随时起停,产物是 Saved/Profiling/<时间戳>.utrace。

.utrace 是流式事件日志,不是采样:每个事件带精确时间戳,UI 里看到的是逐事件的泳道图,可以缩放到微秒级。代价是文件大——一分钟 cpu+gpu 全开轻松几百 MB,长期采集要么砍通道,要么靠 bookmark 分段裁剪。

一次卡顿定位实录

背景:战斗场景每隔约 40 秒一次 120ms 尖峰(正常帧 12ms)。stat unit 确认尖峰在 GameThread(Frame 120ms / Game 120ms / GPU 12ms),排除渲染。下一步是 Insights。

采集:Trace.Start cpu,frame,log,bookmark,复现一次尖峰后 Trace.Stop,得到 90 秒 .utrace。Insights 的 Timing 视图按帧找 Frame 异常长的那个,缩进去看 GameThread 泳道——尖峰帧里 CPU 轨道出现一根 110ms 的条,归属 TaskGraph 工作线程,事件是 FLinkerLoad::Serialize(包二进制反序列化)。

到这里根因已经半坐实:异步加载在尖峰时刻被强制转同步。FlushAsyncLoading 的典型场景——蓝图里某处 LoadObject + LoadPackageAsync 未完成时强制取对象,或者 GetStreamableManager 的同步请求。日志通道在同时间窗里有一条 LogStreaming: Flushing async loading 佐证。

再往上问"为什么偏偏 40 秒一次":查资产引用链,发现是技能特效的 Niagara 系统引用了未常驻的贴图,技能 CD 恰好 40 秒,每次释放触发流送,释放点的等待触发 Flush。修复:把该贴图加进技能包的 PrimaryAsset 预加载列表。尖峰消失。

Insights 架构:Trace 事件流从引擎到分析端 引擎(发射端) TRACE_* 宏埋点 STAT 宏 / 作用域计时 通道编译期注册 UnrealTraceServer 后台常驻进程,端口 1981 收流 → 写 .utrace 真机走 -tracehost 推流 UnrealInsights UI Timing 泳道(逐事件) Loading / Memory 视图 跨进程,不占引擎内存 排查实录的推理链: stat unit 定位线程 → Insights 找异常帧 → 泳道找到长事件 (TaskGraph 线程 110ms Serialize)→ log 通道佐证 Flush → 查引用链定根因

使用纪律

Insights 强大到容易滥用,三条纪律防反噬。一,别常驻全开:通道全开对帧率本身有可测影响(事件编组+写流),"开着 Insights 测性能"的数据要打个问号;对照组必须同通道配置。二,.utrace 是大文件,CI 里做性能门禁时只保留超标片段,按 bookmark 裁剪。三,先 stat 后 Insights——没有聚合数字定位帧段,直接在几百 MB 的泳道里捞针是折磨。Insights 是手术刀,stat 是体检报告,顺序别反。