使用 callgrind 在 Linux 进行局部代码性能分析

发布时间 2024-01-01 01:14:21作者: drink_crow

VS 的性能剖析器可以很方便在选定的代码之间(用断点或者别的什么控制)进行性能剖析,这个功能在大型项目里是十分重要的。linux 有比 win 下更强的,更深入的性能剖析器,但是很遗憾,pref 之类的这些剖析器都是输出整个程序运行的信息的,反而会让你找不到需要关键信息。

找了很久,最后在 VisualGDB 的相关手册中找到了实现类似功能的方法,参考链接。里提到了其实使用 valgrind 实现类似的功能的,而且很重要的一点是不需要特制的 valgrind,也就意味我不用插件,仅用 valgrind 也能做到类似的功能。

经过在 valgrind 的手册里查找,发现是 callgrind 提供了类似的功能。参考链接 , 从

6.2.1. Multiple profiling dumps from one program run

开始看

一般步骤

相关操作代码和功能可以在手册里进一步了解。这里大致的说一下步骤

  • 编译好你的程序

  • 起一个 valgrind 的进程

    valgrind --tool=callgrind --vgdb-error=0 /your/progam/path
    

    valgrind 初始化成功后会有类似提示

    ==103479== TO DEBUG THIS PROCESS USING GDB: start GDB like this
    ==103479==   /path/to/gdb ./main
    ==103479== and then give GDB the following command
    ==103479==   target remote | /usr/bin/vgdb --pid=103479
    ==103479== --pid is optional if only one valgrind process is running
    

    103479 是 valgrind 当前的进程id,每次都会不同,它也会提示你在 gdb 里输入 target remote | /usr/bin/vgdb --pid=103479 链接到 valgrind 的 gdbserver

    工具使用callgrind, '--vgdb-error=0'意思是 valgrind 在遇到0个错误的时候停下运行程序,也就是一开始就停止运行程序,因为后面需要把 gdb 挂上去

  • 另起一个进程 gdb, 链接进 valgrind 的 gdbserver

    gdb /your/progam/path
    

    可以看到 gdb 启动后就在等待指令了

    .....
    Reading symbols from ./main...
    (gdb) 
    

    这时候往 gdb 里输入 target remote | /usr/bin/vgdb --pid=103479 就能看到 gdb 提示进入远程调试了(进入 valgrind 的 gdbserver)

    Remote debugging using | /usr/bin/vgdb --pid=103479
    relaying data between gdb and process 103479
    

    也可以在启动 gdb 的时候直接一步到位

    gdb ./main -ex "target remote | /usr/bin/vgdb --pid=103479"
    
  • 打好断点,把程序停在想要开始进行性能测量的地方。怎么操作 gdb 这部分就跳过了

  • gdb 里清空 callgrind 之前的统计信息, gdb 里输入

    monitor zero
    
  • 恢复程序运行,然后停在想要结束性能测量的地方,并输出统计信息,在 gdb 里输入

    monitor dump
    

    进行 callgrind 的输出。可以在 valgrind 的运行目录看到 callgrind.out.pid.part-threadID, 例如 callgrind.out.102345.1。接下来就可以在 kcachegrind 以图形界面查看结果,win 下可以用 qcachegrind 查看。

在 vs code 调试中使用 valgrind

在一般的 launsh.json 的 gdb 配置增加 valgrind 内容就好,例如

        {
          "name": "valgrind custom",
          "type": "cppdbg",
          "request": "launch",
          "program": "${command:cmake.launchTargetPath}",
          // "preLaunchTask": "valgrind-debug: custom",
          "args": [],
          "stopAtEntry": true,
          "cwd": "${workspaceFolder}",
          "environment": [
            {
              "name": "PATH",
              "value": "$PATH:${command:cmake.launchTargetDirectory}"
            }
          ],
          "externalConsole": false,
          "MIMode": "gdb",
          "setupCommands": [
            {
                "description": "Enable pretty-printing for gdb",
                "text": "-enable-pretty-printing",
                "ignoreFailures": true
            },
            {
                "description": "Set Disassembly Flavor to Intel",
                "text": "-gdb-set disassembly-flavor intel",
                "ignoreFailures": true
            },
            {
              "description": "Connect to valgrind",
              "text": "target remote | vgdb --pid=103479",
              "ignoreFailures": true
            },
          ]
        }

注意修改为对应的 pid , 这里还搭配了 CMake Tool 插件使用,不使用的话将相关指令替换就可以了。

还有一些插件 Valgrind Task Integration 可以提供整合命令,但是卡在等待了 preLaunchTask 的返回,不知道为啥插件预设的设置无效。目前还是手动启动和输入 pid 吧。

在 vs code 的 Debug Console 窗口里则是输入指令需要额外加上前缀 -exec

-exec monitor zero