C++代码使用 gperftools 工具进行性能分析

前言

一直想用 gperftools 做一下性能方面的尝试,之前一直忙着开发,目前已经到了后期,忙里抽闲亲自操作一遍,从安装到分析做个简单的记录,以便后续拿来直接用。

gperftools 是什么

gperftools 是Google开发的用来进行代码性能分析工具,其实他是一系列高性能多线程 malloc() 实现的集合,同时添加了一些精巧的性能分析工具。

gperftools

使用gperftools工具可以通过采样的方式生成上面这种图形化的代码性能分析结果,便于我们分析程序性能瓶颈。

使用方法

C++程序按照代码插桩的方式引入了gperftools工具,不过这个工具需要单独安装,为了生成图形化的分析结果,还需要安装一些依赖库,下面简述以下使用功能步骤。

安装工具

  1. 安装编译所需基础软件

    sudo apt install autoconf automake libtool
    
  2. 安装graphviz,用于图形化显示分析结果

    sudo apt install graphviz
    
  3. 安装libunwind, 这个库提供了可用于分析程序调用栈的 API

    cd /tmp
    wget https://github.com/libunwind/libunwind/releases/download/v1.6.2/libunwind-1.6.2.tar.gz
    tar -zxvf libunwind-1.6.2.tar.gz
    cd libunwind-1.6.2
    ./configure
    make -j4
    sudo make install
    cd /tmp
    rm -rf libunwind-1.6.2.tar.gz libunwind-1.6.2
    
  4. 安装gperftools

    cd /tmp
    wget https://github.com/gperftools/gperftools/releases/download/gperftools-2.10/gperftools-2.10.tar.gz
    tar -zxvf gperftools-2.10.tar.gz
    cd gperftools-2.10
    ./configure
    make -j4
    sudo make install
    cd ~
    rm -rf gperftools-2.10.tar.gz gperftools-2.10
    
  5. 刷新动态装入程序所需的链接和缓存文件

    sudo ldconfig
    

代码插桩引入工具

代码修改

主要在源程序中引入头文件,并且在待测试逻辑前后添加启动分析和结束分析的语句就行了,对于服务类程序,因为要一直运行,可以通过kill信号通知来开启和关闭性能分析。

关键代码

	#include <gperftools/profiler.h> // 引入头文件
	...
	ProfilerStart("cpp_demo.prof");  // 启动分析
	...
	ProfilerStop();                  // 结束分析
	...

完整示例

	#include <iostream>
	#include <gperftools/profiler.h>
	
	static void sig(int sig) // kill -10 pid to trigger
	{
    
    
	    static bool b = false;
	    if (!b)
	        ProfilerStart("cpp_demo.prof");
	    else
	        ProfilerStop();
	
	    b= !b;
	}
	
	int main(int argc, char* argv[])
	{
    
    
	    signal(SIGUSR1, sig);
	
	    while (true)
	    {
    
    
	        std::this_thread::sleep_for(std::chrono::milliseconds(1));
	        //..
	        std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(
	                std::chrono::system_clock::now().time_since_epoch()).count() << std::endl;
	    }
	
	    return 0;
	}

编译链接

编译时我们需要将 profiler 库和 libunwind 库链接到可执行程序,如果使用 cmake来构建,那么 CMakeLists 文件中的语句为:

	target_link_libraries(${
    
    PROJECT_NAME} profiler unwind)

启动分析程序

  1. 正常启动游戏服务器,通过ps命令查找到要分析的进程id,比如查找到demoserver的进程是 7217

    $ ps -ef | grep demoserver
    demo        7217       1 22 21:51 ?        00:00:18 ./demoserver-d
    
  2. 通过kill命令传递自定义信号10的方式启动和关闭分析程序,第一次运行命令是启动,第二次运行相同的命令是关闭,两次命令之间是分析的时间段

    $ kill -10 7217
    
  3. 关闭分析程序之后,会在可执行程序所在目录生成 cpp_demo.porf 文件,可以使用下面命令将结果图形化

    $ pprof --pdf demoserver cpp_demo.prof > demoserver.pdf
    Using local file demoserver.
    Using local file cpp_demo.prof.
    Dropping nodes with <= 1 samples; edges with <= 0 abs(samples)
    
  4. 最终生成的 demoserver.pdf 文件就是我们要用的分析结果,如文章开头所示。

数据分析

上面提到了生成pdf图,其实可以生成txt文本的,只要修改生成选项就可以,比如像这样:

# pprof --text demoserver cpp_demo.prof
Using local file demoserver.
Using local file cpp_demo.prof.
Total: 13 samples
       3  21.4%  21.4%        3  21.4% SpinLock::Unlock (inline)
       3  21.4%  42.9%        3  21.4% __GI_madvise
       2  14.3%  57.1%        2  14.3% SpinLock::Lock (inline)
       1   7.1%  64.3%        1   7.1% TCMalloc_PageMap2::get (inline)
       ...

上述文本数据每行包含6列数据,依次为:

  1. 分析样本数量(不包含其他函数调用)
  2. 分析样本百分比(不包含其他函数调用)
  3. 目前为止的分析样本百分比(不包含其他函数调用)
  4. 分析样本数量(包含其他函数调用)
  5. 分析样本百分比(包含其他函数调用)
  6. 函数名(或者类名+方法名)

样本数量相当于消耗的CPU时间,整个函数消耗的CPU时间相当于包括函数内部其他函数调用所消耗的CPU时间,如果是分析最上面的pdf图,每个节点代表一个函数,包含2~3行数据:

  1. 函数名(或者类名+方法名)
  2. 不包含内部函数调用的样本数 (百分比)
  3. of 包含内部函数调用的样本数 (百分比) #如果没有内部调用函数则不显示

总结

  • gperftools 是可以通过采样的方式进行代码性能分析工具,可生成图形化结果便于我们分析程序性能瓶颈
  • 待分析程序中引入gperftools非常方便,但是需要单独安装这个工具
  • 程序引入时只需要添加头文件,在目标位置插入 ProfilerStart("cpp_demo.prof");ProfilerStop(); 语句即可
  • 对于服务类程序通常不会直接结束,可以通过 kill 命令传递信号的方式来启动和关闭分析程序
==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

可能终于有一天 刚好遇见爱情
可能永远在路上 有人奋斗前行
可能一切的可能 相信才有可能
可能拥有过梦想 才能叫做青春

猜你喜欢

转载自blog.csdn.net/shihengzhen101/article/details/130095406
今日推荐