自己动手写一个基于采样的函数热点分析工具

目标:

基于采样的方法,实现一个函数热点分析工具,可以统计函数执行占总时间的百分比,并排序。

采样方法:

  1. 中断定时检测当前执行地址;
  2. 查询符号表得到函数名i;
  3. 在采样计数器H[i]上加1;
  4. 收集每个函数采样次数;
  5. 计算每个函数执行百分比;

实现:

定时:

由于需要的定时精度较高,常用的alarm定时器不能满足要求。这里使用ITIMER_REAL 类型的setitimer定时器,该定时器以系统真实的时间来计算,计时完成后发出SIGALRM信号。然后利用sigaction函数将采样函数与SIGALRM信号相关联,这样当定时时间到时,会自动采样。

检测执行地址:

采样过程利用libunwind库检测执行地址(编译时加入libunwind库,如gcc *.c -o unw -lunwind -lunwind-x86_64),而且该库本身具备查询符号表的功能,可以调用api获得函数名。获得各函数被采样到的次数后,采用冒泡排序将次数从大到小排列。

libunwind安装:

$ git clone https://github.com/libunwind/libunwind.git
$ cd libunwind
$ ./autogen.sh
$ CFLAGS=-fPIC ./configure 
$ make CFLAGS=-fPIC 
$ make CFLAGS=-fPIC install

注意autogen运行需要autoreconf支持,安装方法:

$ sudo apt-get install autoconf automake libtool

程序计时:

同时利用gettimeofday函数记录程序运行时间。在被测程序开始处插入采样函数,在被测程序结尾插入打印采样结果函数。

被测程序包含3个子函数:a()、b()、c(),每个子函数均由一定数量的for循环构成,循环次数依次为:60000000、20000000、80000000,这些子函数在主函数中分布被调用10次,并且主函数包含一个2400000000次的for循环。因此,可以初步判断四个函数的时间比main():a():b():c()大约为6:15:4:20,换算为百分比为13:33: 9:44。

效果:

程序输出结果包含5部分,其中,sample frequency表示采样频率,running time表示被测程序总运行时间,单位为毫秒,rtime表示各函数执行时间占总时间的百分比,atime表示各函数执行的绝对时间,单位为毫秒,以及函数名称。

下图是采样频率为100Hz的结果。


与gprof做对比,一般linux系统都自带gprof工具,使用gprof需要在gcc编译时加入-pg选项,然后正常运行程序会输出一个gmon.out,用gprof查看即可,以名为main的程序为例:

$ gcc main.c -pg -o main 
$ ./main
$ gprof main


除此以外,gprof还提供了调用次数,每次调用的时间等结果,而且还输出了被测程序的函数调用图.



另外,再介绍使用汇编语言获取堆栈指针sp和程序计数器pc的方法:

sp:

uint64_t getsp( void )
{
	__asm__ ("movq %rsp, %rax");
}
printf("program counter : %p\n", *(int*)(getsp()));

"movq %rsp, %rax"将rsp寄存器的内容传入rax寄存器作为返回值,如果查看上一个被压入栈的指令地址,需要返回值加上8。

printf("program counter : %p\n", *(int*)(getsp() + 8));

pc:

void* get_pc()
{
    return __builtin_return_address(0); 
 }
printf("program counter: %p\n", get_pc());

__builtin_return_address用来判断给定函数的调用者。原型为:

void * __builtin_return_address( unsigned int level );

参数LEVEL决定调用栈的偏移位置:0则返回当前函数的返回地址,1返回调用当前函数的函数的返回地址;以此类推,2,3(只有四个常量值)


参考:

[1] linux系统编程之信号(四):信号的捕捉与sigaction函数. https://blog.csdn.net/jnu_simba/article/details/8947410

[2] Linux定时器 使用. http://www.cnblogs.com/youxin/p/4324366.html

[3] 栈调用关系跟踪. http://blog.chinaunix.net/uid-24774106-id-3457205.html


完整代码见:https://github.com/wangshuaizs/tools/tree/master/hotspot%20analysis%20tool

猜你喜欢

转载自blog.csdn.net/u013431916/article/details/79908604