• gprof用于分析函数调用耗时,可用之抓出最耗时的函数,以便优化程序。
  • gcc链接时也一定要加-pg参数,以使程序运行结束后生成gmon.out文件,供gprof分析。
  • gprof默认不支持多线程程序,默认不支持共享库程序。
  1. gcc -pg 编译程序
  2. 运行程序,程序退出时生成 gmon.out
  3. gprof ./prog gmon.out -b 查看输出

要想产生gmon.out文件,必须在编译和链接时,都加上-pg  -g选项。

1 简介

改进应用程序的性能是一项非常耗时耗力的工作,但是究竟程序中是哪些函数消耗掉了大部分执行时间,这通常都不是非常明显的。GNU 编译器工具包所提供了一种剖析工具 GNU profiler(gprof)。gprof 可以为 Linux平台上的程序精确分析性能瓶颈。gprof精确地给出函数被调用的时间和次数,给出函数调用关系。

gprof 用户手册网站 http://sourceware.org/binutils/docs-2.17/gprof/index.html

2 功能

Gprof 是GNU gnu binutils工具之一,默认情况下linux系统当中都带有这个工具。

1. 可以显示“flat profile”,包括每个函数的调用次数,每个函数消耗的处理器时间,

2. 可以显示“Call graph”,包括函数的调用关系,每个函数调用花费了多少时间。

3. 可以显示“注释的源代码”--是程序源代码的一个复本,标记有程序中每行代码的执行次数。

3 原理

通过在编译和链接程序的时候(使用 -pg 编译和链接选项),gcc 在你应用程序的每个函数中都加入了一个名为mcount ( or  “_mcount”  , or  “__mcount” , 依赖于编译器或操作系统)的函数,也就是说你的应用程序里的每一个函数都会调用mcount, 而mcount 会在内存中保存一张函数调用图,并通过函数调用堆栈的形式查找子函数和父函数的地址。这张调用图也保存了所有与函数相关的调用时间,调用次数等等的所有信息。

4 使用流程

1. 在编译和链接时 加上-pg选项。一般我们可以加在 makefile 中。

2. 执行编译的二进制程序。执行参数和方式同以前。

3. 在程序运行目录下 生成 gmon.out 文件。如果原来有gmon.out 文件,将会被重写。

4. 结束进程。这时 gmon.out 会再次被刷新。

5. 用 gprof 工具分析 gmon.out 文件。

5 参数说明

l -b 不再输出统计图表中每个字段的详细描述。

l -p 只输出函数的调用图(Call graph的那部分信息)。

l -q 只输出函数的时间消耗列表。

l -e Name 不再输出函数Name 及其子函数的调用图(除非它们有未被限制的其它父函数)。可以给定多个 -e 标志。一个 -e 标志只能指定一个函数。

l -E Name 不再输出函数Name 及其子函数的调用图,此标志类似于 -e 标志,但它在总时间和百分比时间的计算中排除了由函数Name 及其子函数所用的时间。

l -f Name 输出函数Name 及其子函数的调用图。可以指定多个 -f 标志。一个 -f 标志只能指定一个函数。

l -F Name 输出函数Name 及其子函数的调用图,它类似于 -f 标志,但它在总时间和百分比时间计算中仅使用所打印的例程的时间。可以指定多个 -F 标志。一个 -F 标志只能指定一个函数。-F 标志覆盖 -E 标志。

l -z 显示使用次数为零的例程(按照调用计数和累积时间计算)。

一般用法: gprof –b 二进制程序 gmon.out >report.txt

6 报告说明

Gprof 产生的信息解释:

%time

Cumulative

seconds

Self

Seconds

Calls

Self

TS/call

Total

TS/call

name

该函数消耗时间占程序所有时间百分比

程序的累积执行时间

(只是包括gprof能够监控到的函数)

该函数本身执行时间

(所有被调用次数的合共时间)

函数被调用次数

函数平均执行时间

(不包括被调用时间)

(函数的单次执行时间)

函数平均执行时间

(包括被调用时间)

(函数的单次执行时间)

函数名

Call Graph 的字段含义:

Index

%time

Self

Children

Called

Name

索引值

函数消耗时间占所有时间百分比

函数本身执行时间

执行子函数所用时间

被调用次数

函数名

注意:

程序的累积执行时间只是包括gprof能够监控到的函数。工作在内核态的函数和没有加-pg编译的第三方库函数是无法被gprof能够监控到的,(如sleep()等)

Gprof 的具体参数可以 通过 man gprof 查询。

7 共享库的支持

对于代码剖析的支持是由编译器增加的,因此如果希望从共享库中获得剖析信息,就需要使用 -pg 来编译这些库。提供已经启用代码剖析支持而编译的 C 库版本(libc_p.a)。

如果需要分析系统函数(如libc库),可以用 –lc_p替换-lc。这样程序会链接libc_p.so或libc_p.a。这非常重要,因为只有这样才能监控到底层的c库函数的执行时间,(例如memcpy(),memset(),sprintf()等)。

gcc example1.c –pg -lc_p -o example1

注意要用ldd ./example | grep libc来查看程序链接的是libc.so还是libc_p.so

8 用户时间与内核时间

gprof 的最大缺陷:它只能分析应用程序在运行过程中所消耗掉的用户时间,无法得到程序内核空间的运行时间。通常来说,应用程序在运行时既要花费一些时间来运行用户代码,也要花费一些时间来运行 “系统代码”,例如内核系统调用sleep()。

有一个方法可以查看应用程序的运行时间组成,在 time 命令下面执行程序。这个命令会显示一个应用程序的实际运行时间、用户空间运行时间、内核空间运行时间。

如 time ./program

输出:

real    2m30.295s

user    0m0.000s

sys     0m0.004s

9 注意事项

1. g++在编译和链接两个过程,都要使用-pg选项。

2. 只能使用静态连接libc库,否则在初始化*.so之前就调用profile代码会引起“segmentation fault”,解决办法是编译时加上-static-libgcc或-static。

3. 如果不用g++而使用ld直接链接程序,要加上链接文件/lib/gcrt0.o,如ld -o myprog /lib/gcrt0.o myprog.o utils.o -lc_p。也可能是gcrt1.o

4. 要监控到第三方库函数的执行时间,第三方库也必须是添加 –pg 选项编译的。

5. gprof只能分析应用程序所消耗掉的用户时间.

6. 程序不能以demon方式运行。否则采集不到时间。(可采集到调用次数)

7. 首先使用 time 来运行程序从而判断 gprof 是否能产生有用信息是个好方法。

8. 如果 gprof 不适合您的剖析需要,那么还有其他一些工具可以克服 gprof 部分缺陷,包括 OProfile 和 Sysprof。

9. gprof对于代码大部分是用户空间的CPU密集型的程序用处明显。对于大部分时间运行在内核空间或者由于外部因素(例如操作系统的 I/O 子系统过载)而运行得非常慢的程序难以进行优化。

10. gprof 不支持多线程应用,多线程下只能采集主线程性能数据。原因是gprof采用ITIMER_PROF信号,在多线程内只有主线程才能响应该信号。但是有一个简单的方法可以解决这一问题:http://sam.zoy.org/writings/programming/gprof.html

11. gprof只能在程序正常结束退出之后才能生成报告(gmon.out)。

a) 原因: gprof通过在atexit()里注册了一个函数来产生结果信息,任何非正常退出都不会执行atexit()的动作,所以不会产生gmon.out文件。

b) 程序可从main函数中正常退出,或者通过系统调用exit()函数退出。

10 多线程应用

gprof 不支持多线程应用,多线程下只能采集主线程性能数据。原因是gprof采用ITIMER_PROF信号,在多线程内只有主线程才能响应该信号。

采用什么方法才能够分析所有线程呢?关键是能够让各个线程都响应ITIMER_PROF信号。可以通过桩子函数来实现,重写pthread_create函数。

 gprof-helper.c#define _GNU_SOURCE#include <sys/time.h>#include <stdio.h>#include <stdlib.h>#include <dlfcn.h>#include <pthread.h>static void * wrapper_routine(void *);/* Original pthread function */static int (*pthread_create_orig)(pthread_t *__restrict,__const pthread_attr_t *__restrict,void *(*)(void *),void *__restrict) = NULL;/* Library initialization function */void wooinit(void) __attribute__((constructor));void wooinit(void){pthread_create_orig = dlsym(RTLD_NEXT, "pthread_create");fprintf(stderr, "pthreads: using profiling hooks for gprof/n");if(pthread_create_orig == NULL){char *error = dlerror();if(error == NULL){error = "pthread_create is NULL";}fprintf(stderr, "%s/n", error);exit(EXIT_FAILURE);}}/* Our data structure passed to the wrapper */typedef struct wrapper_s{void * (*start_routine)(void *);void * arg;pthread_mutex_t lock;pthread_cond_t  wait;struct itimerval itimer;} wrapper_t;/* The wrapper function in charge for setting the itimer value */static void * wrapper_routine(void * data){/* Put user data in thread-local variables */void * (*start_routine)(void *) = ((wrapper_t*)data)->;start_routine;void * arg = ((wrapper_t*)data)->;arg;/* Set the profile timer value */setitimer(ITIMER_PROF, &((wrapper_t*)data)->;itimer, NULL);/* Tell the calling thread that we don't need its data anymore */pthread_mutex_lock(&((wrapper_t*)data)->;lock);pthread_cond_signal(&((wrapper_t*)data)->;wait);pthread_mutex_unlock(&((wrapper_t*)data)->;lock);/* Call the real function */return start_routine(arg);}/* Our wrapper function for the real pthread_create() */int pthread_create(pthread_t *__restrict thread,__const pthread_attr_t *__restrict attr,void * (*start_routine)(void *),void *__restrict arg){wrapper_t wrapper_data;int i_return;/* Initialize the wrapper structure */wrapper_data.start_routine = start_routine;wrapper_data.arg = arg;getitimer(ITIMER_PROF, &wrapper_data.itimer);pthread_cond_init(&wrapper_data.wait, NULL);pthread_mutex_init(&wrapper_data.lock, NULL);pthread_mutex_lock(&wrapper_data.lock);/* The real pthread_create call */i_return = pthread_create_orig(thread,attr,&wrapper_routine,&wrapper_data);/* If the thread was successfully spawned, wait for the data* to be released */if(i_return == 0){pthread_cond_wait(&wrapper_data.wait, &wrapper_data.lock);}pthread_mutex_unlock(&wrapper_data.lock);pthread_mutex_destroy(&wrapper_data.lock);pthread_cond_destroy(&wrapper_data.wait);return i_return;}///然后编译成动态库 gcc -shared -fPIC gprof-helper.c -o gprof-helper.so -lpthread -ldl 使用例子:/a.c/#include <stdio.h>;#include <stdlib.h>;#include <unistd.h>;#include <pthread.h>;#include <string.h>;void fun1();void fun2();void* fun(void * argv);int main(){int i =0;int id;pthread_t    thread[100];for(i =0 ;i< 100; i++){id = pthread_create(&thread[i], NULL, fun, NULL);printf("thread =%d/n",i);}printf("dsfsd/n");return 0;}void*  fun(void * argv){fun1();fun2();return NULL;}void fun1(){int i = 0;while(i<100){i++;        printf("fun1/n");}        }void fun2(){int i = 0;int b;while(i<50){i++;printf("fun2/n");//b+=i;        }        }///gcc -pg a.c  gprof-helper.so运行程序:./a.out分析gmon.out:gprof -b a.out gmon.out

Linux性能优化gprof使用相关推荐

  1. 开发人员如何解决Linux性能优化之痛?

    这些问题或者场景,你是否曾经遇到过? •  流量高峰期,服务器CPU使用率过高报警,你登录Linux上去top完之后,却不知道怎么进一步定位,到底是系统CPU资源太少,还是程序并发部分写的有问题? • ...

  2. 如何学习Linux性能优化?

    如何学习Linux性能优化? 你是否也曾跟我一样,看了很多书.学了很多 Linux 性能工具,但在面对 Linux 性能问题时,还是束手无策?实际上,性能分析和优化始终是大多数软件工程师的一个痛点.但 ...

  3. linux性能优化--cpu篇

    linux性能优化--cpu篇 前言 负载 CPU使用率 proc perf 一些链接 `perf list` 比较有用的event `perf stat` `perf record` Profili ...

  4. linux下缓存命中测试,Linux 性能优化实战(倪朋飞)---查看缓存命中情况

    cachestat 提供了整个操作系统缓存的读写命中情况. cachetop 提供了每个进程的缓存命中情况.但是,cachetop 并不把直接 I/O 算进来. 安装 cachestat.cachet ...

  5. Linux性能优化方向及相关工具

    1. 考察性能的指标 从应用负载的角度 吞吐 延时 从系统资源的角度 CPU使用率 内存饱和度 2. 定位性能问题的步骤 选择指标评估性能 设置性能优化的目标 进行性能基准测试 分析和定位性能瓶颈 对 ...

  6. 查看linux内存优化,Linux性能优化和监控系列(三) 分析Memory使用状况

    Linux性能优化和监控系列(三) 分析Mem 分析Memory使用状况 内存是影响服务器性能的一个主要因素, 当进程已经驻留内存或者系能够分配给进程足够的内存给它, CPU能顺利自如的运行. 如果发 ...

  7. 10个问题带你全面理解Linux性能优化

    10个问题带你全面理解Linux性能优化 • Feiskyhttps://feisky.xyz/posts/2020-06-06-linux-perf/本文整理自极客时间"10个问题带你全面 ...

  8. 推荐学习-Linux性能优化实战

    学习交流加(可免费帮忙下载CSDN资源): 个人微信: liu1126137994 学习交流资源分享qq群1(已满): 962535112 学习交流资源分享qq群2: 780902027 推荐一个学习 ...

  9. Linux 性能优化全景指南

    大家好 我是坤哥 之前一些朋友觉得奇怪,说你主要做 Java 的,公号怎么时不时地也推送一些 Linux 文章,其实不管你是哪个 xx 语言的工程师,要想进阶,Linux 性能优化是必备知识,举个例子 ...

最新文章

  1. 5分钟教程,手把手带你安装使用抓包神器:Whistle ,内含精选爬虫资料
  2. jQuery操作Select
  3. [原创]WildPackets Omnipeek介绍
  4. 教程:一起学习Hystrix--服务(依赖)失败场景的表象
  5. 通过options探测服务器信息,OPTIONS 方法在跨域请求(CORS)中的应用
  6. Ubuntu 中设置源的几种方法
  7. 锁屏快捷键_全面屏 iPhone 锁屏快捷键美化,让你的 iPhone 更特别
  8. 作者:李冰(1989-),女,中国电子技术标准化研究院工程师。
  9. rsync软件配置和使用教程
  10. 进程和线程的关系与区别是什么?如何创建多线程?
  11. Python 06 编码
  12. 基于LabVIEW的个性化打地鼠游戏设计
  13. 三菱PLC 闪烁动作 ST语言
  14. 2018年最有前景的十大行业
  15. 计算机量子化学计算实验报告物化实验,量子化学计算方试验.doc
  16. 图benchmark
  17. 【windows查看电脑属性配置 dxdiag】
  18. 浅析智慧消防应用中多设备联动火灾报警系统
  19. 狄拉克δ函数的数学迷思
  20. HTTP POST 请求工具类

热门文章

  1. 卸载Docker方法
  2. 视频教程-Python全栈工程师特训班第十一期-直播回放-Python
  3. 同舟康泰,我心中的香巴拉!
  4. 备忘录中可以打开表格吗?
  5. C语言题目:5-10 求最大值 (25 分)(求赞呀)
  6. java责任链模式_java中责任链模式详解和使用方法
  7. mysql索引添加缓慢_mysql 中 创建索引很慢,怎么解决
  8. win11右键显示更多选项关闭的四种方法
  9. Mysql 12 复制1
  10. 您不是文件所有者_如何解决您的连接不是私人错误(网站所有者指南)