Google的gperftools套件中包含有CPU Profiler(以下简称:pprof),原生支持C/C++多线程程序的性能剖析。相比GNU Profiler无法原生支持多线程性能剖析,pprof更具实用价值。
gperftools:https://googledrive.com/host/0B6NtGsLhIcf7MWxMMF9JdTN3UVk/gperftools-2.2.tar.gz
cmake:http://www.cmake.org/download/
The KDE Software Development Kit(kdesdk):内含kcachegrind工具,系统盘中包含该rpm包。
完整项目见:https://github.com/lostaway/Woody-Ye-s-Code-Share/tree/master/CpuProfilerExample
// main.cpp #include <cstdio> #include <pthread.h> void *FastFunc(void *_arg) { double sum = 0; for(int i = 0; i < 100000000; i++) { sum += 1; } return (NULL); } void *SlowFunc(void *_arg) { double sum = 0; for(int i = 0; i < 100000000; i++) { sum *= 3; sum /= 3; sum += 1; } return (NULL); } void *AllFunc(void *_arg) { FastFunc(NULL); SlowFunc(NULL); return (NULL); } int main(int argc, char *argv[]) { pthread_t tidFast = 0, tidSlow = 0, tidAll = 0; pthread_create(&tidFast, NULL, FastFunc, NULL); pthread_create(&tidSlow, NULL, SlowFunc, NULL); pthread_create(&tidAll, NULL, AllFunc, NULL); pthread_join(tidFast, NULL); pthread_join(tidSlow, NULL); pthread_join(tidAll, NULL); return (0); }
# CMake compile script PROJECT(CpuProfilerExample) CMAKE_MINIMUM_REQUIRED(VERSION 2.8) # usage "cmake -DUSE_CPU_PROFILER=ON .." or "cmake -DUSE_CPU_PROFILER=OFF .." MESSAGE(STATUS USE_CPU_PROFILER=${USE_CPU_PROFILER}) SET(SRC main.cpp) INCLUDE_DIRECTORIES() LINK_DIRECTORIES($ENV{GPERFTOOLS_ROOT}/lib) ADD_EXECUTABLE(CpuProfilerExample ${SRC}) TARGET_LINK_LIBRARIES(CpuProfilerExample pthread) IF(USE_CPU_PROFILER) TARGET_LINK_LIBRARIES(CpuProfilerExample profiler) ENDIF() SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
#!/bin/sh echo "start CpuProfilerExample CPU profile" env CPUPROFILE=CpuProfilerExample.prof ./CpuProfilerExample exit 1
#!/bin/sh echo "Display CpuProfilerExample CPU profile in Kcachegrind" pprof --callgrind CpuProfilerExample CpuProfilerExample.prof > CpuProfilerExample.callgrind nohup kcachegrind CpuProfilerExample.callgrind > /dev/null & exit 1
pprof可以在不修改源码的情况下,通过在编译时链接profiler库,程序启动前设置特定的环境变量来开启CPU剖析功能。进入CpuProfilerExample项目根目录:
$ mkdir build $ cmake -DUSE_CPU_PROFILER=ON .. $ gmake $ cd ../bin $ ./startCpuProfile.sh
程序运行结束后,在bin目录下会生成“CpuProfilerExample.prof”性能剖析文件。执行:
$ ./displayProfileInKcachegrind.sh
启动KCacheGrind程序,显示出性能剖析结果:
调用图中,每个矩形框表示一个函数,上部是函数名,下部表示该函数及其调用的函数占程序总运行时间的百分比。仅从百分比来看,执行了浮点数乘除加操作的SlowFunc函数,占了总运行时间的85.39%,与实际代码相符。执行了浮点数加的FastFunc函数,占总运行时间的14.61%。
剖析结果中还有“时间片”的概念。见左侧函数列表,start_thread的Called字段“527”,表示start_thread函数调用的函数共消耗了527个时间片。具体每个调用的函数消耗的时间片数量,标示在调用图的箭头上。所以,从占用百分比和占用时间片来看,SlowFunc函数是示例程序的性能瓶颈。
程序性能优化,本是慢工细活,有了pprof可以很快速的定位到程序的性能瓶颈,针对性的做优化。在熟悉了pprof的基本用法之后,进一步学习的目标应该是分析工作中复杂程序的性能瓶颈、第三方库的性能瓶颈和系统调用的性能瓶颈。
[1] Google CPU Profiler Manuals,http://gperftools.googlecode.com/svn/trunk/doc/cpuprofile.html