免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

Perfetto GPU 追踪完全指南:从 Android 移动图形到多 GPU 高性能计算

Perfetto GPU 追踪完全指南:从 Android 移动图形到多 GPU 高性能计算 Perfetto GPU 追踪完全指南从 Android 移动图形到多 GPU 高性能计算【免费下载链接】perfettoProduction-grade client-side tracing, profiling, and analysis for complex software systems.项目地址: https://gitcode.com/GitHub_Trending/pe/perfetto导读GPU 是复杂软件系统中性能瓶颈的高发地带从 Android 移动图形渲染到数据中心的多 GPU 计算集群都需要精准的可观测性支撑。本文以 Perfetto 官方文档 docs/data-sources/gpu.md 为骨架系统讲解 Perfetto 的 GPU 追踪能力如何配置gpu.counters、gpu.renderstages、vulkan.memory_tracker等数据源如何在 Android 上采集 GPU 频率、计数器、显存与渲染阶段以及如何面向 CUDA/OpenCL/HIP 等 GPGPU 场景做多 GPU、多机、按提交采样的深度分析。读完本文你将能够独立编写完整的 GPU 追踪配置、理解计数器描述符两种工作模式并用 Perfetto SQL 与 UI 插件完成内核级性能归因。一、GPU 追踪全景数据源与配置速查Perfetto 通过一组独立的数据源覆盖 GPU 活动的各个方面每个数据源都有对应的 trace 配置 proto。下表汇总了官方文档给出的全部 GPU 相关数据源数据源配置用途gpu.countersgpu_counter_config.proto周期性或插桩式instrumentedGPU 计数器采样gpu.renderstagesgpu_renderstages_config.protoGPU 渲染阶段与计算提交时间线vulkan.memory_trackervulkan_memory_config.protoVulkan 内存分配与绑定追踪gpu.log无配置GPU 调试日志消息linux.ftraceftrace_config.protoGPU 频率、显存总量、DRM scheduler 事件1.1 数据源命名硬件厂商后缀与精确匹配GPU 生产者producer在注册数据源时通常会带上硬件相关的后缀例如gpu.counters.adreno高通 Adreno或gpu.renderstages.maliARM Mali。这带来一个关键约束追踪服务tracing service使用精确名称匹配因此 trace 配置里的name必须与被注册的数据源完全一致含后缀trace processor 按 proto 字段类型解析 GPU 数据因此所有带后缀的变体在解析层是完全等价的——无论数据源叫什么名字最终都会统一落入 GPU 相关的数据表。在针对特定 GPU 厂商的生产者时请在 trace 配置中使用带后缀的名称。最基础的计数器采样配置如下data_sources: { config { name: gpu.counters gpu_counter_config { counter_period_ns: 1000000 counter_ids: 1 } } }1.2 多 GPU 与多机标识gpu_id 与 machine_id所有 GPU 追踪数据都携带两类标识字段gpu_id区分系统内不同的 GPU。在 gpu_counter_event.proto 中GpuCounterEvent.gpu_id用于多 GPU 设备中标识计数器属于哪块 GPUGpuRenderStageEvent.gpu_id同理。machine_id在多机部署架构中区分 GPU 所属的机器。GPU 硬件元数据名称、厂商、架构、UUID、PCI BDF通过 GpuInfo trace packet 记录。从 gpu_info.proto 的源码可以看到每条Gpu记录包含nameGPU 名称如 NVIDIA A100、Adreno 740UI 用它作为 GPU track 的显示标签多块同型号 GPU 建议追加索引区分如 NVIDIA A100 #0vendor、model、architecture厂商、型号与架构如 Ampere、RDNA 3uuid16 字节设备 UUIDpci_bdfPCI 总线位置如 0000:01:00.0extra_info任意键值对用于驱动版本、显存大小、计算能力等厂商自定义信息。GpuInfo.gpus列表的索引即对应全 trace 中使用的gpu_id这是 UI 正确把 track 挂到对应 GPU 下的前提。二、Android GPU 追踪实践Android 是 Perfetto GPU 追踪最成熟的平台官方文档按频率、计数器、显存、渲染阶段、Vulkan 内存、GPU 日志六个维度给出了可直接落地的配置。2.1 GPU 频率ftraceGPU 频率通过 ftrace 事件power/gpu_frequency采集data_sources: { config { name: linux.ftrace ftrace_config { ftrace_events: power/gpu_frequency } } }2.2 GPU 计数器counter descriptor mode 1Android GPU 生产者必须使用计数器描述符模式 1counter descriptor mode 1GpuCounterDescriptor直接嵌入在会话的第一个GpuCounterEventpacket 中且 counter ID 是全局的。这是 CDD/CTS 合规的硬性要求——从 gpu_counter_event.proto 的注释可见mode 1 要求 counter id 全局唯一因此只能由单个生产者发出或需要不同生产者之间协调这正是 Android OEM 为满足 CDD/CTS 测试必须采用的机制。计数器按设备相关的 ID 采样可用的 counter ID 由数据源描述符中的GpuCounterSpec描述。示例data_sources: { config { name: gpu.counters gpu_counter_config { counter_period_ns: 1000000 counter_ids: 1 counter_ids: 3 counter_ids: 106 counter_ids: 107 counter_ids: 109 } } }其中counter_period_ns设置期望的采样间隔。从 gpu_counter_config.proto 源码看该配置还支持一个容易被忽略的字段fix_gpu_clock在 trace 会话期间固定 GPU 时钟频率用于保证采样数据可比性。按名称选择计数器除了counter_ids还可以用counter_names按名称选计数器配置语义上两者互斥只用其一。注意并非所有生产者都支持按名称选择——需要检查数据源描述符中GpuCounterDescriptor.supports_counter_namescounter_names支持 glob 通配模式批量匹配但同样需要检查supports_counter_name_globs支持标志。从 gpu_counter_descriptor.proto 源码可以看到这两个能力标志以及 Android GPU 生产者通常不支持按名称选择注释明确写道 Android GPU producers typically do not。2.3 GPU 显存ftrace每个进程的 GPU 显存总用量通过 ftrace 事件gpu_mem/gpu_mem_total采集data_sources: { config { name: linux.ftrace ftrace_config { ftrace_events: gpu_mem/gpu_mem_total } } }2.4 GPU 渲染阶段render stages渲染阶段追踪提供 GPU 活动时间线图形与计算提交data_sources: { config { name: gpu.renderstages } }若需要更精细的控制gpu_renderstages_config.proto 还提供三个可选字段full_loadstore把颜色与深度/模板depth/stencil的 load 与 store 阶段拆分为独立阶段关闭时二者合并。默认关闭且在低开销模式下无效low_overhead低开销模式所有渲染阶段合并为单一 workload 阶段数据粒度变粗但 GPU 开销最小。默认关闭trace_metrics要为每个渲染阶段采集的指标列表。2.5 Vulkan 内存追踪Vulkan 内存分配与绑定事件可通过vulkan.memory_tracker追踪data_sources: { config { name: vulkan.memory_tracker vulkan_memory_config { track_driver_memory_usage: true track_device_memory_usage: true } } }vulkan_memory_config.proto 定义了两个开关track_driver_memory_usage追踪驱动侧内存host 内存使用事件track_device_memory_usage追踪设备侧显存内存使用事件。2.6 GPU 日志GPU 调试日志消息可直接启用数据源采集无需额外配置data_sources: { config { name: gpu.log } }三、高端 GPGPU多 GPU 与多机追踪针对高性能与数据中心 GPU 负载CUDA、OpenCL、HIPPerfetto 支持多 GPU、多机追踪与插桩式计数器采样。文档中明确说明Perfetto 的定位是客户端侧追踪见 docs/README.md 中对使用边界的描述GPU 渲染阶段与计数器记录在 Android 上已有成熟支持而游戏领域更专业的 GPU 分析工具是 Android GPU Inspector其底层也以 Perfetto 作为数据源之一。3.1 插桩式计数器采样Instrumented Counter Sampling与全局周期采样不同插桩式采样通过改写 GPU 命令缓冲区来采集计数器能够获得**每次提交per-submission**的计数器值data_sources: { config { name: gpu.counters gpu_counter_config { counter_ids: 1 counter_ids: 2 instrumented_sampling: true } } }instrumented_sampling是布尔开关与instrumented_sampling_config构成 oneof 二选一见 gpu_counter_config.proto 中的instrumented_sampling_mode。需要精确控制插桩哪些 GPU 活动时使用instrumented_sampling_config它定义了一个按顺序执行的三级过滤管线第 1 步活动名称过滤Activity name filtering。若activity_name_filters非空则活动必须至少匹配一个过滤器。每个过滤器由name_glob必需glob 模式与name_base可选决定匹配基准组成。name_base的三种取值定义在 proto 的ActivityNameFilter.NameBase枚举中取值匹配对象示例MANGLED_KERNEL_NAME默认编译期编码的mangled内核名_Z6matmulPfiiDEMANGLED_KERNEL_NAME完整反修饰内核名含参数、模板、限定符matmul(float*,int,int)FUNCTION_NAME仅反修饰后的裸函数名matmul若activity_name_filters为空所有活动直接通过本步骤。第 2 步TX 范围过滤TX range filtering。TX 范围是进程内的注解用于标记 GPU 工作区段如 CUDA 的 NVTX range。若activity_tx_include_globs非空活动必须落在匹配某个 include glob 的 TX 范围内落在匹配activity_tx_exclude_globs范围内的活动被排除exclude 优先于 include。TX 范围可嵌套只要活动嵌套层级中的任一范围匹配即视为匹配。两者都为空时所有活动通过。第 3 步范围采样Range-based sampling。若activity_ranges非空只插桩指定 skip/count 范围内的活动。skip默认 0count默认UINT32_MAX即剩余全部活动。为空时通过前两步的所有活动都会被插桩。官方给出的综合示例——只插桩反修饰内核名匹配myKernel*、且位于匹配training*的 TX 范围内、跳过前 10 个活动再插桩 5 个data_sources: { config { name: gpu.counters gpu_counter_config { counter_names: sm__cycles_elapsed.avg counter_names: sm__cycles_active.avg instrumented_sampling_config { activity_name_filters { name_glob: myKernel* name_base: DEMANGLED_KERNEL_NAME } activity_tx_include_globs: training* activity_ranges { skip: 10 count: 5 } } } } }3.2 计数器描述符模式 2GPGPU 场景的推荐选择对 GPGPU 用例官方推荐计数器描述符模式 2生产者发出由 IID 引用的InternedGpuCounterDescriptor使每个可信序列trusted sequence拥有自己作用域内的 counter ID。这与模式 1 形成鲜明对比模式 1GpuCounterDescriptor内嵌在首个GpuCounterEvent中counter ID 全局唯一要求单生产者或跨生产者协调多生产者、多 GPU 场景难以扩展模式 2GpuCounterEvent通过counter_descriptor_iid引用InternedData中的InternedGpuCounterDescriptor天然支持多生产者与多 GPU。两种模式的完整字段定义见 gpu_counter_event.proto。特别地InternedGpuCounterDescriptor中也有自己的gpu_id且其优先级高于GpuCounterEvent.gpu_id字段。计数器的名称与 ID 由 GPU 生产者通过数据源描述符中的GpuCounterSpec对外发布。gpu_counter_descriptor.proto 显示GpuCounterSpec还携带丰富的元数据description、numerator_units/denominator_units测量单位如 HERTZ、BYTE、PERCENT、WATT、CELSIUS 等MeasureUnit枚举、int_peak_value/double_peak_value峰值、select_by_default以及value_direction——该字段告知 trace processor 采样值作用于时间戳的哪一侧区间VALUE_DIRECTION_BACKWARDS_LOOKING表示值覆盖到该时间戳为止的区间VALUE_DIRECTION_FORWARDS_LOOKING表示从该时间戳开始的区间直接影响 UI 中计数器的绘制位置。3.3 计数器分组Counter Groups计数器分组用于让 Perfetto UI 把计数器轨道组织成组。计数器可以归属内置分组SYSTEM、VERTICES、FRAGMENTS、PRIMITIVES、MEMORY、COMPUTE、RAY_TRACING即GpuCounterGroup枚举见 gpu_counter_descriptor.proto通过GpuCounterSpec.groups指定。生产者还可以用GpuCounterDescriptor中的GpuCounterGroupSpec消息定义自定义分组message GpuCounterGroupSpec { optional uint32 group_id 1; optional string name 2; optional string description 3; repeated uint32 counter_ids 4; }自定义分组有两个用途定义硬件相关的自定义分组如 Compute Core、L2 CacheUI 据此在Counters下生成可折叠子分组为固定的GpuCounterGroup枚举值提供显示名称与描述——将group_id设为枚举值并提供name和/或description即可。计数器的分组归属是并集GpuCounterSpec.groups固定枚举与GpuCounterGroupSpec.counter_ids自定义分组指派的分组共同生效。例如配置了自定义分组 Compute Core 与 L2 Cache 后UI 中的轨道组织方式为GPU Counters Compute Core Counter A GPU Counters Compute Core Counter B GPU Counters L2 Cache Counter C3.4 多 GPUMulti-GPU系统中的每块 GPU 都被分配一个gpu_id。计数器事件、渲染阶段等 GPU 追踪数据都携带该 IDUI 据此按 GPU 分组轨道。GPU 硬件细节通过 GpuInfo 记录包含前文所述的name、vendor、model、architecture、uuid16 字节与pci_bdfPCI 总线/设备/功能号。3.5 多机Multi-Machine跨机器追踪时每个 GPU 追踪事件还携带machine_id以区分 GPU 所属机器Perfetto UI 会在 GPU 轨道旁显示机器标签。多机架构的完整方案见多机部署架构文档。3.6 渲染阶段事件关联Render Stage Event CorrelationGPU 渲染阶段事件可以通过GpuRenderStageEvent上的event_wait_ids字段声明对其他渲染阶段事件的依赖。gpu_render_stage_event.proto 将event_wait_ids定义为该事件运行前必须等待的其他GpuRenderStageEvent的event_id列表。trace processor 会利用这些依赖在被关联的 GPU slice 之间创建 flow 箭头。官方示例一个 matmul 内核依赖一次异步 memcpygpu_render_stage_event { event_id: 1 duration: 50000 hw_queue_iid: 1 stage_iid: 2 context: 0 name: Memcpy HtoD } gpu_render_stage_event { event_id: 2 duration: 40000 hw_queue_iid: 3 stage_iid: 4 context: 0 name: matmul_kernel event_wait_ids: 1 }这会在 memcpy 事件event_id 1与 matmul 内核event_id 2之间创建一条 flow在 Perfetto UI 中直观呈现依赖关系。此外gpu_render_stage_event.proto 中还定义了面向计算场景的丰富字段kernel_iid引用 interned 的计算内核描述InternedComputeKernel含demangled_name、arch与类型化属性、launchComputeKernelLaunch记录 grid/workgroup 三维尺寸与寄存器数、共享内存等类型化启动参数、extra_data用户自定义键值对可携带资源 ID、着色器等。InternedGpuRenderStageSpecification.category枚举OTHER/GRAPHICS/COMPUTE则是后续 SQL 查询中区分计算内核与图形事件的基础。3.7 主机到 GPU 关联Host-to-GPU Correlation主机侧 track event 可以使用GpuCorrelationTrackEvent 扩展与 GPU 渲染阶段事件关联用于把主机 API 调用如cudaLaunchKernel、cudaMemcpyAsync与对应的 GPU 工作连接起来。扩展定义在 gpu_track_event.proto 中提供两个字段render_stage_submission_event_ids该主机事件提交的 GPU 渲染阶段事件的 event IDrender_stage_wait_event_ids该主机事件等待其完成的 GPU 渲染阶段事件的 event ID。官方示例——主机内核启动与 GPU 计算内核的关联track_event { type: TYPE_SLICE_BEGIN name: cudaLaunchKernel [perfetto.protos.GpuTrackEvent.gpu_correlation] { render_stage_submission_event_ids: 1 } } gpu_render_stage_event { event_id: 1 duration: 50000 hw_queue_iid: 1 stage_iid: 2 context: 0 name: matmul_kernel }同一 proto 还定义了GpuApi枚举GPU_API_OPEN_GL、GPU_API_VULKAN、GPU_API_OPEN_CL、GPU_API_CUDA、GPU_API_HIP其取值与InternedGraphicsContext.Api刻意保持一致可用于标记 track event 对应的 GPU APIUI 据此按 API 组织轨道。四、UI 插件GPU 数据的可视化层Perfetto UI 内置了多个消费 GPU 追踪数据的插件。它们在 workspace 树的GPU分组下注册轨道、分组与详情面板per-process 插件则注册到各进程分组下。源码位置在 ui/src/plugins 目录默认插件清单见 ui/src/core/embedder/default_plugins.ts。4.1 dev.perfetto.Gpu基础插件为每块 GPU 布局一个GPU分组并为gpu_counter_track、gpu_render_stage、gpu_log、vulkan_events、graphics_frame_event各族的全部内容填充叶子轨道与汇总轨道多 GPU/多机拆分为按 GPU 的子分组存在多台机器时附加机器标签自定义计数器分组GpuCounterDescriptor/GpuCounterGroupSpec声明的自定义分组在Counters下显示为可折叠子分组。4.2 dev.perfetto.GpuByProcess该插件展示仅作用于单个进程、没有全局意义的 GPU 概念。典型例子是 CUDA stream它是进程级句柄两个进程里相同的数值streamID 指向两个互不相关的流因此把所有流堆在共享的GPU分组下会产生误导。此插件将这些轨道放到各自所属进程之下。对携带device与stream启动参数如 CUDA、HIP的 GPU slice插件按API → Device #N → Context #N → Stream #N在进程下嵌套组织gpu_render_stageslice只有单一取值的层级会被折叠不带这些参数的 slice 回退为按hw_queue_id每个硬件队列一条轨道通常命名为Channel #N。当进程跨多块 GPU 时叶子轨道再按 GPU 子分组嵌套。4.3 com.meta.GpuCompute计算内核深度分析插件对应源码目录 ui/src/plugins/com.meta.GpuCompute。当选中计算类gpu_render_stageslice即gpu_slice.render_stage_category COMPUTE时提供三个标签页Summary汇总trace 中每次内核启动的表格可按耗时、占用率occupancy等硬件指标排序双击跳转到该内核的详情视图Details详情分节指标表Speed-of-Light、Launch Statistics、Occupancy、Compute Workload Analysis支持两个内核之间的基线对比Toolbar工具栏内核选择器、基线固定、术语切换CUDA / OpenCL / 厂商自定义以及自动单位换算bytes → KB、ns → s 等。核心插件自带 CUDA 与 AMD 支持其他厂商通过配套插件注册术语、指标分节、知名指标 ID 与分析提供者来扩展扩展 API 见该插件目录下的 README。五、示例查询用 Perfetto SQL 做 GPU 分析GPU 追踪数据最终落在 trace processor 的 SQL 表中gpu_counter_track、gpu_slice、gpu_track、gpu等可以用 Perfetto SQL 分析文档 描述的标准 SQL 语法做深度分析。官方文档给出一个非常实用的查询示例找出耗时最长的 5 个内核并计算每个内核执行窗口内的时间加权 GPU 利用率。查询的核心技巧在于两个 Perfetto 标准库模块counters.intervals 相关模块在src/trace_processor/perfetto_sql/stdlib目录下可查仓库中android/gpu/frequency.sql等大量 SQL 均使用了counter_leading_intervalscounter_leading_intervals把稀疏的计数器采样展开为(ts, dur, value)区间每个采样值持续到下一个采样_interval_intersect把这些区间与每个内核的[ts, ts dur)窗口求交集从而让平均值真正按每个计数器值在内核期间实际生效的时长加权。INCLUDE PERFETTO MODULE counters.intervals; INCLUDE PERFETTO MODULE intervals.intersect; WITH -- The GPU Utilization counter, expanded into (ts, dur, value) intervals. -- Carries ugpu so the intersect can match each kernel to its own GPU. utilization AS ( SELECT u.id, u.ts, u.dur, u.value, gct.ugpu FROM counter_leading_intervals!(( SELECT c.id, c.ts, c.track_id, c.value FROM counter c JOIN gpu_counter_track gct ON gct.id c.track_id WHERE gct.name Utilization )) u JOIN gpu_counter_track gct ON gct.id u.track_id ), -- The 5 longest compute kernels (render_stage_category 2 COMPUTE). top_kernels AS ( SELECT s.id, s.ts, s.dur, s.name, extract_arg(t.dimension_arg_set_id, ugpu) AS ugpu FROM gpu_slice s JOIN gpu_track t ON s.track_id t.id WHERE s.render_stage_category 2 AND s.dur 0 ORDER BY s.dur DESC LIMIT 5 ) SELECT k.name AS kernel, g.name AS gpu_name, k.dur AS dur_ns, -- Time-weighted average: sum(value * overlap_dur) / kernel_dur. SUM(u.value * ii.dur) / k.dur AS avg_utilization FROM top_kernels k LEFT JOIN gpu g ON g.id k.ugpu JOIN _interval_intersect!((top_kernels, utilization), (ugpu)) ii ON ii.id_0 k.id JOIN utilization u ON u.id ii.id_1 GROUP BY k.id, k.name, g.name, k.dur ORDER BY k.dur DESC;几个值得注意的实现细节内核的ugpu通过extract_arg(t.dimension_arg_set_id, ugpu)从 GPU track 的维度参数中取出用于在 intersect 时把每个内核只与它自己的 GPU的利用率计数器匹配_interval_intersect的第二个参数(ugpu)就是关联键render_stage_category 2对应InternedGpuRenderStageSpecification.RenderStageCategory.COMPUTEOTHER0、GRAPHICS1、COMPUTE2见 gpu_render_stage_event.proto时间加权平均的计算方式是SUM(值 × 区间重叠时长) / 内核总时长。示例输出双 GPU 训练 tracekernelgpu_namedur_nsavg_utilizationmatmul_bwd_kernelNVIDIA A100-SXM4-80GB #118000078.27matmul_bwd_kernelNVIDIA A100-SXM4-80GB #218000077.25matmul_kernelNVIDIA A100-SXM4-80GB #112500078.70matmul_kernelNVIDIA A100-SXM4-80GB #212500078.83softmax_bwd_kernelNVIDIA A100-SXM4-80GB #111000073.76这个查询直观展示了如何把计数器采样与内核 slice两类异构数据在 SQL 层对齐进而量化每个内核的 GPU 利用率是排查计算内核性能瓶颈的起点。六、进一步阅读在 Android 上采集系统 trace 的完整流程Android 系统追踪入门GPU 数据的底层 proto 定义gpu_counter_event.proto、gpu_render_stage_event.proto、gpu_track_event.proto计数器描述符与能力协商gpu_counter_descriptor.proto多机追踪架构多机部署架构Perfetto SQL 语法与标准库Perfetto SQL 语法、Perfetto SQL 快速上手【免费下载链接】perfettoProduction-grade client-side tracing, profiling, and analysis for complex software systems.项目地址: https://gitcode.com/GitHub_Trending/pe/perfetto创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表