使用Google CPU Profiler对C/C++多线程程序做性能剖析

       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程序,显示出性能剖析结果:

使用Google CPU Profiler对C/C++多线程程序做性能剖析_第1张图片

       调用图中,每个矩形框表示一个函数,上部是函数名,下部表示该函数及其调用的函数占程序总运行时间的百分比。仅从百分比来看,执行了浮点数乘除加操作的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

你可能感兴趣的:(使用Google CPU Profiler对C/C++多线程程序做性能剖析)