ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

benchmark(microbenchmark)性能计数器实战:用 --benchmark_perf_counters 采集 CPU PMU 计数器

benchmark(microbenchmark)性能计数器实战:用 --benchmark_perf_counters 采集 CPU PMU 计数器 性能测试【免费下载链接】benchmarkA microbenchmark support library项目地址https://gitcode.com/gh_mirrors/benchmark5/benchmark点击查看免费下载本文以docs/perf_counters.md为主体完整讲解 google/benchmark 的用户请求式性能计数器User-Requested Performance Counters功能它的适用前提、Bazel 与 CMake 两种构建系统的开启方式、运行时--benchmark_perf_counters标志的使用方法并结合 src/perf_counters.cc、src/benchmark.cc 等源码剖析计数器从打开、快照到随 User Counters 输出的完整链路。读完后你将能够在基准测试中直接采集CYCLES、INSTRUCTIONS等硬件计数器用于回归定位与性能归因分析。1. 功能定位为什么要在基准测试中采集硬件计数器运行基准测试时用户可以选择同时采集性能计数器performance counters。官方文档明确给出了两类典型使用场景见 docs/perf_counters.md调查场景缩小性能回归regression的原因范围验证场景确认某次性能提升的底层原因是否符合预期例如提升是否真的来自访存减少而非指令减少。这个功能的关键特点是无需修改任何基准测试代码。计数器采集与计时器采集走同一条边界路径——在State计时开始/停止的同一位置顺带读取计数器快照因此对现有基准测试代码零侵入。2. 使用前提PMU 硬件 libpfm 编译支持文档给出了功能可用的两个必要条件运行在具备性能监控单元PMU的架构上基准测试以支持计数器采集的方式编译。当前实现依赖 libpfm在 Bazel 构建中它被作为依赖自动构建。在源码中这两条前提对应明确的开关src/perf_counters.cc 中所有真实实现都包裹在#if defined HAVE_LIBPFM条件编译块内未定义该宏时PerfCounters::kSupported直接为falseCreate()仅打印Performance counters not supported.并返回空对象见 src/perf_counters.cc。也就是说即使运行时传了计数器标志未开启编译支持的构建也只会优雅降级而不会崩溃。3. 构建时开启Bazel 与 CMake 两种路径3.1 Bazel 构建--define pfm1如果使用 Bazel只需在构建参数中加入--define pfm1。仓库的 BUILD.bazel 中可以看到对应的配置config_setting( name perfcounters, define_values { pfm: 1, }, visibility [:__subpackages__], )只有命中该config_setting时perfcounters目标才会链接libpfm依赖BUILD.bazel 中:perfcounters: [libpfm]libpfm 由 Bazel 作为依赖构建无需手动安装。3.2 CMake 构建安装 libpfm4-dev 并打开BENCHMARK_ENABLE_LIBPFM如果使用 CMake文档给出的步骤是# 1. 安装开发包Debian/Ubuntu 示例 apt-get install libpfm4-dev# 2. 在 CMakeLists.txt 中启用选项 option(BENCHMARK_ENABLE_LIBPFM Enable performance counters provided by libpfm OFF)该选项默认关闭定义在 CMakeLists.txt打开后 CMake 会在配置阶段强制寻找 PFM 包找不到则配置失败CMakeLists.txtif (BENCHMARK_ENABLE_LIBPFM) find_package(PFM REQUIRED) endif()REQUIRED的写法意味着选项一旦打开构建系统会替你把关 libpfm 是否存在配置阶段即可暴露缺失的依赖而不是等到链接期。4. 运行时使用--benchmark_perf_counters标志开启编译支持后使用时通过--benchmark_perf_counters传入逗号分隔的计数器名称列表./my_benchmark --benchmark_perf_countersCYCLES,INSTRUCTIONS关于计数器名称文档强调了几个要点这里逐条展开名称由 libpfm 解码。框架把每个名称交给 libpfm 的pfm_get_os_event_encoding()翻译成操作系统的事件编码。源码中该调用见 src/perf_counters.cc。名称是平台相关的因为 PMU 事件编码因微架构而异但部分通用名称如CYCLES或INSTRUCTIONS会被 libpfm 映射到对应平台的具体事件。更多细节可参考 libpfm 官方文档。名称无法识别时会打印Unknown performance counter name: name并跳过该项其余计数器照常工作src/perf_counters.cc。空字符串项会被拒绝并记录A performance counter name was the empty string——这在使用 shell 拼接参数、可能出现尾部多余逗号时是实际会发生的情况。最多 32 个计数器。上限定义在PerfCounterValues::kMaxCounterssrc/perf_counters.h超出部分被忽略并打印错误日志说明已添加数量。4.1 采集只发生在用户态且只针对被测代码源码 src/perf_counters.cc 揭示了两个容易被忽视的约束编码与打开事件均使用PFM_PLM3即user mode only仅用户态perf_event_attr显式设置exclude_kernel true、exclude_hv true、exclude_user false。因此计数器统计的是基准测试进程用户态的 PMU 事件内核开销不会混入读数这使其更适合作为被测代码本身的归因指标。4.2 多组计数器与分组复用group multiplexingPMU 每个周期能同时监听的硬件计数器数量有限。src/perf_counters.cc 的处理策略是将计数器组织成组组内事件通过PERF_FORMAT_GROUP一次read()批量读出组内由一个leader文件描述符代表若perf_event_open返回负值说明当前组硬件资源耗尽把group_id重置为 -1重试并自动开启新组针对被信号打断EINTR的情况内置了最多 5 次重试若连新开组都失败则放弃该计数器并打印***WARNING** Failed to get a file descriptor for performance counter name. Ignoring但继续处理其余计数器——单个计数器的失败不会拖垮整批。5. 采集时机与计时器同边界的快照差分PerfCountersMeasurementsrc/perf_counters.h封装了开始/停止两次快照并取差值BENCHMARK_ALWAYS_INLINE bool Start() { if (num_counters() 0) return true; ClobberMemory(); // 阻止编译器移动快照位置 valid_read_ counters_.Snapshot(start_values_); ClobberMemory(); return valid_read_; } // Stop() 同理输出 end_values_ - start_values_ 的差值两侧各插一次ClobberMemory()内存屏障是为了告诉编译器不要移动快照指令的相对位置保证差值恰好覆盖被测循环区间。这与文档所述Counter collection is handled at the boundaries where timer collection is also handled 一一对应在 src/benchmark.cc 中State::StartTimer()之后紧跟perf_counters_measurement_-Start()在 src/benchmark.cc 中timer_-StopTimer()之后紧跟Stop(measurements)。因此PauseTiming()/ResumeTiming()同样会自然地把暂停区间从计数器读数中扣除。底层读取由PerfCounterValues::Read()完成src/perf_counters.cc逐个组 leader 执行read()由于PERF_FORMAT_GROUP的返回格式在组值前带有一段 8 字节 padding读取后用memmove去掉 padding 再拼接[]操作符即可按 0 基下标直接索引各计数器值。6. 结果输出经由 User Counters 机制文档指出计数器值通过User Counters机制回传因此 User Counters 支持的所有输出格式如 JSON都能直接承载性能计数器。调用链是运行前src/benchmark.cc 在RunBenchmarks中解析标志并构造全局唯一的PerfCountersMeasurement// This perfcounters object needs to be created before the runners vector // below so it outlasts their lifetime. PerfCountersMeasurement perfcounters( StrSplit(FLAGS_benchmark_perf_counters, ,));注意注释说明它必须活得比所有 runner 更久从而整轮基准测试共享同一组已打开的 PMU 事件描述符避免反复开关事件。每次迭代结束后Stop()产生的名称, 差值对作为计数器并入运行结果报告层直接把它当作普通 counters 输出src/benchmark_runner.cc 中report.counters results.counters;随后由 console / JSON / CSV 等 reporter 统一格式化。测试用例 test/perf_counters_test.cc 验证了这一机制它声明了BM_DECLARE_string(benchmark_perf_counters)对BM_Simple、带PauseTiming/ResumeTiming的BM_WithPauseResume等基准分别断言 JSON 输出结构可直接作为编写自己的验证参考。7. 边界情况与注意事项多线程基准测试的警告如果同时存在多线程基准且请求了计数器运行前会打印警告src/benchmark.cc计数器读数将反映所有线程合并后的使用量解读时需自行折算。这与perf_event_open中inherit true的设置一致——子线程/继承上下文的事件会被统计进来。与聚合报告的互斥检查BenchmarkRunner构造函数中有一个BM_CHECKsrc/benchmark_runner.cc当基准显式设置了聚合报告模式aggregation report mode时若请求了计数器却未能成功建立num_counters() 0会直接以 Perf counters were requested but could not be set up. 失败避免输出看起来正常却缺失计数器的聚合报告。Windows 平台PerfCountersMeasurement::Snapshot()在BENCHMARK_OS_WINDOWS下恒返回falsesrc/perf_counters.h即 Windows 构建即使链接成功也不具备该能力当前实现基于 Linux 的perf_event_open系统调用。降级行为单个计数器失败仅告警并跳过但如果某个组 leader 的PERF_EVENT_IOC_ENABLE失败should never happen实现会关闭整批描述符并返回空对象src/perf_counters.cc因为部分激活状态下的恢复会是灾难。libpfm 惰性初始化PerfCounters::Initialize()用函数内静态变量保证pfm_initialize()只执行一次src/perf_counters.cc首次创建计数器时才付出初始化成本。8. 小结benchmark 的性能计数器功能把libpfm 名称 → 事件编码 →perf_event_open分组 → 与计时同边界快照 → User Counters 统一输出整条链路封装成了一个命令行标志环节要点证据位置构建开启Bazel--define pfm1CMake 装libpfm4-devBENCHMARK_ENABLE_LIBPFMBUILD.bazel、CMakeLists.txt运行时--benchmark_perf_countersNAME1,NAME2,...libpfm 解码平台相关上限 32src/benchmark.cc采集仅用户态分组复用与StartTimer/StopTimer同边界受PauseTiming影响src/perf_counters.cc、src/benchmark.cc输出并入 User CountersJSON 等所有格式可用src/benchmark_runner.cc、test/perf_counters_test.cc在回归排查或优化验证时配合--benchmark_formatjson输出即可把CYCLES、INSTRUCTIONS等读数纳入可对比的数据管道用每迭代指令数/周期数的变化直接回答这次改动到底改变了什么。赞分享性能测试【免费下载链接】benchmarkA microbenchmark support library项目地址https://gitcode.com/gh_mirrors/benchmark5/benchmark点击查看免费下载相关推荐Google Benchmark性能计数器完全指南如何利用硬件PMU深度优化代码性能Google Benchmark性能计数器完全指南如何利用硬件PMU深度优化代码性能 在微基准测试领域Google Benchmark库的性能计数器功能是一性能测试Perfetto CPU 性能剖析实战perf 计数器采样、调用栈采样与火焰图分析Perfetto CPU 性能剖析实战perf 计数器采样、调用栈采样与火焰图分析 本指南以 Perfetto 的 linux.perf 数据源为主线讲解如可观测性后端开发工具前端数据可视化Google Benchmark性能计数器与统计功能详解Google Benchmark性能计数器与统计功能详解 本文全面介绍了Google Benchmark框架中的性能计数器与统计功能。首先详细讲解了内置硬件性能性能测试上一篇5个关键特性让Acode成为Android移动开发的终极选择下一篇如何快速清理电脑重复图片AntiDupl.NET免费开源工具终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表