文章目录
- 前言
- 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
命令传递信号的方式来启动和关闭分析程序
可能终于有一天 刚好遇见爱情
可能永远在路上 有人奋斗前行
可能一切的可能 相信才有可能
可能拥有过梦想 才能叫做青春