C/C++性能分析工具

张开发
2026/4/16 19:29:53 15 分钟阅读

分享文章

C/C++性能分析工具
前言之前写过一篇文章C编程技巧 —— 提高时空效率_3857. 休息时间c-CSDN博客关于如何使用C的编程技巧来提升程序性能。有童鞋可能会问那我们如何去定量地测试我们写的代码的性能找到瓶颈所在呢本文给大家推荐一些C/C常用的性能分析工具。目录一、C/C性能分析工具概览1.1 gprof (GNU Profiler)1机制2如何使用3示例报告解析1.2 Valgrind 工具集1Memcheck – 内存检查工具2Callgrind – 性能分析工具1.3 perf – Linux内核性能分析器1机制2如何使用3高级功能1.4 Visual Studio Profiler1机制2如何使用3示例报告解析1.5 Google Performance Tools (gperftools)1CPU Profiler2Heap Profiler二、一些注意事项2.1 编译优化的影响2.2 分析工具本身的开销一、C/C性能分析工具概览C/C性能分析工具种类繁多涵盖了从简单的命令行工具到功能强大的图形化软件工具。这里我们按类别分别介绍一些主流的性能分析工具。1.1 gprof (GNU Profiler)gprof是GNU编译器提供的经典性能分析工具用于分析C/C程序的函数调用与CPU使用时间。1机制它通过在编译时插入统计代码并在程序运行时收集数据从而计算出每个函数的调用次数、自身执行时间以及总执行时间包括调用子函数的时间等信息。gprof生成的报告可以帮助开发者快速定位占用CPU时间最多的“热点函数”从而有针对性地进行优化。2如何使用使用gprof比较简单只需在编译和链接时加入-pg选项然后运行程序即可生成最终的分析数据。操作步骤如下# 编译程序加入gprof分析支持后缀 g -pg -o myCode myCode.cpp # 运行程序程序结束时会在当前目录下生成gmon.out文件 ./myCode # 使用gprof分析gmon.out文件并将结果输出到文本文件 gprof myCode gmon.out gprof.txtgprof报告通常包括一个Flat Profile各函数的自身时间和累计时间和一个Call Graph函数调用关系图3示例报告解析Flat profile: Each sample counts as 0.02 seconds. % cumulative self self total time seconds seconds calls Ts/call Ts/call name 12.34 0.14 0.14 123 0.00 0.14 function_A ...通过上述示例可以看出function_A函数自身占用了0.12秒的CPU时间占程序总运行时间的12.34%。1.2 Valgrind 工具集Valgrind是一套功能强大的开源动态二进制分析和检测工具集主要用于调试和性能分析。它本身包含多个工具其中最经典的是用于内存检查的Memcheck和用于性能分析的Callgrind。通过Valgrind工具开发者可以检测内存泄漏、非法内存访问等问题同时也可以收集程序运行时的详细性能数据。1Memcheck – 内存检查工具Memcheck工具专门用于检测内存相关的错误例如内存泄漏、访问未初始化的内存、读写越界等。机制它通过在模拟的CPU环境中运行程序对每次内存访问进行检查从而发现许多C/C程序中常见的内存问题。当Memcheck发现问题时会输出详细的错误信息包括出错的内存地址、试图执行的非法操作类型以及调用堆栈等帮助开发者快速定位问题。如何使用要使用Memcheck只需在程序前加上valgrind --toolmemcheck即可运行。例如valgrind --toolmemcheck ./myCode如果程序存在内存管理问题Valgrind会在输出中高亮显示。例如对于一段有内存泄漏的代码Memcheck会在程序结束时给出泄漏报告12345 HEAP SUMMARY: 12345 in use at exit: 48 bytes in 1 blocks 12345 total heap usage: 1 allocs, 0 frees, 48 bytes allocated 12345 LEAK SUMMARY: 12345 definitely lost: 48 bytes in 1 blocks 12345 indirectly lost: 0 bytes in 0 blocks 12345 possibly lost: 0 bytes in 0 blocks 12345 still reachable: 0 bytes in 0 blocks 12345 suppressed: 0 bytes in 0 blocks上述输出表明程序在退出时有48字节、1块内存没有被释放。通过Memcheck工具开发者能够轻松发现内存问题。注意事项Memcheck工具非常强大但同时也存在开销。由于它需要对每条指令进行模拟检查程序运行速度会变慢一般只在开发测试阶段使用。2Callgrind – 性能分析工具Callgrind工具用于性能分析它可以记录程序运行时的函数调用信息、每个函数的执行次数、缓存命中率、分支预测失败率等细粒度性能数据。它通过动态分析生成一个名为callgrind.out.pid的输出文件其中包含了丰富的性能统计信息.如何使用valgrind --toolcallgrind ./myCode输出类似如下文件callgrind.out.12345使用callgrind_annotate命令进行查看callgrind_annotate callgrind.out.12345查看结果举例如下-------------------------------------------------------------------------------- Ir file:myCode -------------------------------------------------------------------------------- 1,503,000 myCode.cpp:func2 1,500 myCode.cpp:func1 20,000 myCode.cpp:func3上面例子可以看出func2占了大部分指令或缓存。大家还可借助kcachegrind进行图形化查看函数调用关系非常直观Windows下载kcachegrind.exe运行即可。可视化界面类似下图Linux安装kcachegrind,然后命令行运行kcachegrind#安装 sudo apt-get update sudo apt-get install kcachegrind #运行可视化 kcachegrind callgrind.out.12345注意事项Callgrind与Memcheck一样同样存在运行开销。它模拟了CPU和内存层次结构程序运行时可能比平时慢数十倍一般也只在内部开发测试阶段使用。1.3 perf – Linux内核性能分析器perf是Linux内核自带的一款强大的性能分析工具能够利用CPU的硬件性能计数器来收集各种系统级性能数据。1机制与gprof和Valgrind不同perf不需要对程序进行特殊编译或修改它直接在运行的程序上进行采样开销非常小适合在生产环境中对系统进行实时分析。perf可以分析CPU使用率、缓存命中率、分支预测失败、指令执行数等多种指标从而帮助开发者全面掌握程序的性能特征。2如何使用使用perf分析程序通常包括“记录”和“报告”两个阶段# 1. 使用perf record运行程序并记录性能数据 perf record ./myCode # 2. 程序运行结束后使用perf report查看分析报告 perf reportperf record指令默认情况下perf会以一定的频率对指令指针进行采样记录调用栈等信息。当程序结束时使用perf report可以查看汇总的报告其中列出了热点函数及其占用的CPU时间百分比。3高级功能例如可以使用perf top实时查看当前系统的热点函数类似top命令但针对性能数据。perf annotate可以将采样数据注释到源代码的每条指令上显示每条指令执行的次数帮助定位具体的性能瓶颈行。1.4 Visual Studio ProfilerVisual Studio Profiler是微软Visual Studio集成开发环境IDE中内置的性能分析工具用于Windows平台上的C应用程序。1机制VS Profiler提供了一套完整的性能诊断功能包括CPU使用分析、内存分配分析、线程分析等可以帮助开发者快速定位性能瓶颈。直接集成在IDE中使用Visual Studio Profiler无需离开熟悉的开发环境非常适合Windows开发者使用。2如何使用启用性能分析在Visual Studio中选择“调试”菜单下的“性能探查器”Performance Profiler选项或直接按快捷键AltF2打开进入性能分析模式。选择分析类型在弹出的性能探查器窗口中可以选择要进行的分析类型例如“CPU使用”、“Instrumentation插桩”。可以根据需要勾选或取消勾选某些选项例如同时启用CPU和内存分析或者只关注CPU。运行分析点击启动按钮运行程序。Profiler会自动在后台收集性能数据。开发者可以像平时一样运行程序执行各种操作以触发不同的代码路径。查看结果程序运行结束后Visual Studio会显示性能报告。开发者可以在IDE中直接查看函数调用列表、调用树、时间线等视图。通过这些视图可以找到耗时最长的函数展开调用树查看上下文或者定位到具体的代码行。3示例报告解析Visual Studio Profiler的输出非常直观。例如在CPU使用报告中会列出每个函数的总CPU时间和自身时间。以下输出结果仅展示一个模板例子并不精确NameModuleTotal CPU [ms, %]Self CPU [ms, %]CpuDemo.Program.FuncACpuDemo.exe840 ms, 84.0%210 ms, 21.0%System.Math.SqrtSystem.Private.CoreLib.dll330 ms, 33.0%330 ms, 33.0%System.Math.LogSystem.Private.CoreLib.dll300 ms, 30.0%300 ms, 30.0%CpuDemo.Program.MainCpuDemo.exe850 ms, 85.0%~0 ms, ~0%CpuDemo.Program.FuncBCpuDemo.exe~0 ms, ~0%~0 ms, ~0%1.5 Google Performance Tools (gperftools)Google Performance Tools (gperftools)是Google开源的一套性能分析工具集主要用于C程序的CPU性能和内存使用分析。它包括几个核心工具一个高速的线程缓存malloc实现TCMalloc、一个CPU分析器CPU Profiler和一个内存堆分析器Heap Profiler。gperftools的特点是高性能和易用性特别适合多线程和大型C项目。1CPU ProfilerCPU Profiler可以对程序进行采样式的CPU性能分析。与gprof不同它不需要重新编译程序而是通过链接其库并在运行时启动/停止分析来实现。它会以一定的频率对调用栈进行采样记录程序执行过程中各个函数的运行时间分布。生成的分析数据可以使用pprof工具进行可视化查看类似于火焰图Flame Graph的形式。如何使用使用gperftools的CPU分析器需要在编译和链接时加入gperftools库并在代码中显式启动/停止分析。#include gperftools/profiler.h int main() { // 启动CPU性能分析 ProfilerStart(cpu_profile.prof); // ... 需要分析的代码 ... // 停止CPU性能分析 ProfilerStop(); return 0; }编译时需要链接gperftools的Profiler库g -o myCode myCode.cpp -lprofiler运行后会生成一个名为cpu_profile.prof的文件。使用pprof工具可以查看分析结果pprof --text myCode ./cpu_profile.prof2Heap ProfilerHeap Profiler是gperftools中用于分析堆内存使用的工具。它可以帮助开发者了解程序在运行时的内存分配情况找出内存泄漏和内存热点频繁分配/释放的对象。Heap Profiler通过替换默认的malloc/free实现在每次分配/释放内存时记录调用栈和大小从而生成一份详细的内存使用报告。如何使用使用Heap Profiler需要在代码中包含gperftoos/heap-profiler.h并在分析开始和结束处调用相应的函数。#include gperftools/heap-profiler.h int main() { // 启动内存分析 HeapProfilerStart(heap_profile); // ... 需要分析的代码 ... // 停止内存分析并生成报告 HeapProfilerStop(); return 0; }编译时同样需要链接Heap Profiler库g -o myCode myCode.cpp -ltcmalloc程序运行结束后Heap Profiler会生成一系列以.heap为后缀的文件例如heap_profile.001.heap、heap_profile.002.heap等每个文件对应一个快照。可以使用pprof来汇总这些快照并生成最终报告pprof --text --basemyCode ./heap_profile.*.heap二、一些注意事项在使用上述性能分析工具时开发者可能会遇到一些常见的问题例如2.1 编译优化的影响不同的性能分析工具对编译优化的容忍度不同。例如gprof需要编译时插入统计代码因此如果使用-O2等优化选项编译可能会丢失一些分析信息。相反像perf这样的采样工具在优化代码上才能给出有意义的结果。使用工具时应了解其对编译选项的要求并相应地调整配置。2.2 分析工具本身的开销某些工具如Valgrind本身会显著降低程序运行速度。如果分析过程中程序运行变慢开发者可能误以为是性能问题而浪费时间调试。实际上这是工具开销导致的。因此在分析时还应注意区分真正的性能问题和工具带来的性能影响。

更多文章