文章目录
- 前言
- gperftools 是什么
- 使用方法
- 安装工具
- 代码插桩引入工具
- 代码修改
- 关键代码
- 完整示例
- 编译链接
- 启动分析程序
 
 
- 数据分析
- 总结
前言
一直想用 gperftools  做一下性能方面的尝试,之前一直忙着开发,目前已经到了后期,忙里抽闲亲自操作一遍,从安装到分析做个简单的记录,以便后续拿来直接用。
gperftools 是什么
gperftools 是Google开发的用来进行代码性能分析工具,其实他是一系列高性能多线程 malloc() 实现的集合,同时添加了一些精巧的性能分析工具。

使用gperftools工具可以通过采样的方式生成上面这种图形化的代码性能分析结果,便于我们分析程序性能瓶颈。
使用方法
C++程序按照代码插桩的方式引入了gperftools工具,不过这个工具需要单独安装,为了生成图形化的分析结果,还需要安装一些依赖库,下面简述以下使用功能步骤。
安装工具
-  安装编译所需基础软件 sudo apt install autoconf automake libtool
-  安装graphviz,用于图形化显示分析结果 sudo apt install graphviz
-  安装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
-  安装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
-  刷新动态装入程序所需的链接和缓存文件 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)
启动分析程序
-  正常启动游戏服务器,通过ps命令查找到要分析的进程id,比如查找到demoserver的进程是 7217$ ps -ef | grep demoserver demo 7217 1 22 21:51 ? 00:00:18 ./demoserver-d
-  通过kill命令传递自定义信号 10的方式启动和关闭分析程序,第一次运行命令是启动,第二次运行相同的命令是关闭,两次命令之间是分析的时间段$ kill -10 7217
-  关闭分析程序之后,会在可执行程序所在目录生成 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)
-  最终生成的 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列数据,依次为:
- 分析样本数量(不包含其他函数调用)
- 分析样本百分比(不包含其他函数调用)
- 目前为止的分析样本百分比(不包含其他函数调用)
- 分析样本数量(包含其他函数调用)
- 分析样本百分比(包含其他函数调用)
- 函数名(或者类名+方法名)
样本数量相当于消耗的CPU时间,整个函数消耗的CPU时间相当于包括函数内部其他函数调用所消耗的CPU时间,如果是分析最上面的pdf图,每个节点代表一个函数,包含2~3行数据:
- 函数名(或者类名+方法名)
- 不包含内部函数调用的样本数 (百分比)
- of 包含内部函数调用的样本数 (百分比) #如果没有内部调用函数则不显示
总结
- gperftools是可以通过采样的方式进行代码性能分析工具,可生成图形化结果便于我们分析程序性能瓶颈
- 待分析程序中引入gperftools非常方便,但是需要单独安装这个工具
- 程序引入时只需要添加头文件,在目标位置插入 ProfilerStart("cpp_demo.prof");和ProfilerStop();语句即可
- 对于服务类程序通常不会直接结束,可以通过 kill命令传递信号的方式来启动和关闭分析程序
可能终于有一天 刚好遇见爱情
可能永远在路上 有人奋斗前行
可能一切的可能 相信才有可能
可能拥有过梦想 才能叫做青春



















