gprof 在postgresql中的使用

gprof 在postgresql中的使用

 

gprof简介:

1.gprof是GNU profiler工具。可以显示程序运行的“flat profile”,包括每个函数的调用次数,每个函数消耗的处理器时间。也可以显示“Call graph (调用图)”,包括函数的调用关系,每个函数调用花费了多少时间。

2.gprof只能在程序正常结束退出之后才能生成程序测评报告,原因是gprof通过在atexit()里注册了一个函数来产生结果信息,任何非正常退出都不会执行atexit()的动作,所以不会产生gmon.out文件。如果你的程序是一个不会退出的服务程序,那就只有修改代码来达到目的。如果不想改变程序的运行方式,可以添加一个信号处理函数解决问题(这样对代码修改最少)。

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

 

gprof使用方法:

1、在编译选项中加-pg

2、执行编译的二进制程序

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

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

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

 

PG中使用gprof:

在PG中,可以在configure中添加--enable-profiling

PS:不要直接在文件 src/Makefile.global 中的CFLAGS添加-pg

原因:修改 src/Makefile.global,在程序目录下(PGDATA)下会生成 gmon.out,但是PG不同的进程生成的 gmon.out会相互覆盖,最终只剩一个,无法得到其余进程的 gmon.out文件。

使用--enable-profiling,configure之后, src/Makefile.global 中的CFLAGS会添加-pg,且会在PG代码中定义宏PROFILE_PID_DIR,标记会在PGDATA/gprof下 为每个进程创建一个pid命名的文件夹,该进程的gmon.out文件生成在此。

 

使用gprof分析gmon.out

gprof 命令使用方法:

gprof  二进制程序  gmon.out >report.txt

gprof后也可以加以下参数:

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命令生成的report.txt 文件说明(不加参数):

Gprof 产生的信息解释:

%timeCumulative secondsSelf SecondsCallsSelf TS/callTotal TS/callname
该函数消耗时间占程序所有时间百分比程序的累积执行时间 (只是包括gprof能够监控到的函数)该函数本身执行时间 (所有被调用次数的合共时间,不包含子函数)函数被调用次数函数平均执行时间 (不包含子函数)函数平均执行时间 (包含子函数)函数名

Call Graph 的字段含义:

Index%timeSelfChildrenCalledName
索引值函数消耗时间占所有时间百分比函数本身执行时间执行子函数所用时间被调用次数函数名

PS: gprof只能监控 添加-pg之后编译到的部分代码中函数,对于工作在内核态的函数(如内核系统调用sleep() )、外部的函数库(libc库,so)

若想要监控普通动态链接库,可以添加-pg重新编译so.

若想要监控libc中的函数,需要启用代码剖析支持而编译的 C 库版本(libc_p.a/libc_p.so )。用 –lc_p替换-lc,这样程序会链接libc_p.so或libc_p.a。

比如

gcc example1.c –pg -lc_p -o example1

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

 

函数分析:

Flat profile部分:

统计函数的调用情况,按照所有函数总运行时间进行排序(不包含子函数)

Flat profile:
​
Each sample counts as 0.01 seconds.
​
  %   cumulative   self              self     total           
​
 time   seconds   seconds    calls  ms/call  ms/call  name    
​
  8.39      6.23     6.23 182558812     0.00     0.00  SearchCatCache
​
  7.19     11.57     5.34 980839114     0.00     0.00  AllocSetAlloc
​
  4.89     15.20     3.63 528673804     0.00     0.00  copyObject
​
  3.50     17.80     2.60  1942314     0.00     0.00  base_yyparse
​
  2.19     19.43     1.63 117492872     0.00     0.00  expression_tree_walker
  .....
​

从以上数据可知,运行总时间最长的函数为SearchCatCache,被调用了182558812次,总时间为6.23(不包含其子函数)

 

Call graph部分:

对每个函数进行分析,并按照总运行时间排序(包含子函数)

以下 分别对三种常见的函数的分析情况进行说明

1、一般函数(没有递归的函数)

Call graph
​
​
granularity: each sample hit covers 2 byte(s) for 0.01% of 74.27 seconds
​
index % time    self  children    called     name
​
.......
-----------------------------------------------
                0.00(A2)    0.00(B2)       2(C2)/6310643     PostgresMain [118] 表示PostgresMain的index为118
                0.08(A1)   26.27(B1) 6310641(C1)/6310643     BuildCachedPlan [3]
[5]     35.5    0.08(A)    26.27(B)  6310643(C)         pg_plan_queries [5]
                0.09(A3)   26.07(B3) 6310643/6310643         pg_plan_query [6]
                0.02(A4)    0.09(B4) 6310643/85468457        lappend [58]
-----------------------------------------------
......

以上为函数pg_plan_queries的调用情况(index [5]正对的一行),该函数和他的子函数总运行时间为程序运行时间的35.5 。

pg_plan_queries 行:

self列为该函数本身的运行时间;children为该函数的子函数们运行的总时间(包含子函数的子函数。。。。);

called列表上该函数被调用的总次数。

pg_plan_queries 被调用6310643次(记为C),pg_plan_queries 函数本身运行总时间为0.08s(记为A),pg_plan_queries 中的子函数运行时间为26.27(记为B)。

pg_plan_queries 上面的函数为调用pg_plan_queries的函数,下面的函数为pg_plan_queries调用的函数(子函数)

调用pg_plan_queries 的函数有PostgresMain、BuildCachedPlan。

called:在pg_plan_queries被调用的6310643次中,BuildCachedPlan调用了6310641次(记为C1),PostgresMain调用了2次(记为C2)

self&children:

pg_plan_queries在被BuildCachedPlan调用的6310641次中,共运行0.08s(记为A1),子函数运行26.27s(记为B1)

pg_plan_queries在被PostgresMain调用的2次中,共运行0.00s(记为A2),子函数运行0.00s(记为B2)

(由于PostgresMain调用pg_plan_queries次数太少,总时间在1ms之下,统计不到,

实际上,A=A1+A2,B = B1+B2,C= C1+C2)

(时间都是pg_plan_queries的运行时间。)

pg_plan_queries 下面的函数为pg_plan_queries 调用的子函数

pg_plan_queries 调用的函数有pg_plan_query和lappend

called:pg_plan_query一共被调用6310643次,全部在此处被调用;lappend共被调用85468457次,在此处被调用了6310643次。

self&children:

pg_plan_query在此处的调用中,函数本身运行时间为0.09s(记为A3),子函数运行总时间为26.07s(记为B3)

lappend在此处的调用中,函数本身运行时间为0.02s(记为A4),子函数运行总时间为0.09s(记为B4)

A3+B3+A4+B4 = B

(时间都是子函数在pg_plan_queries中的运行时间。)

2、递归函数

index % time    self  children    called     name
-----------------------------------------------
                             3886192             expression_tree_mutator <cycle 4> [75]
                             16021340(a1)             simplify_function <cycle 4> [19]
                             16023420(a2)             eval_const_expressions_mutator <cycle 4> [49]
                0.00    0.00       1(a3)/6311976(s)     flatten_join_alias_vars [1059]
                0.00    0.00       2(a4)/6311976     create_indexscan_plan [663]
                0.00    0.00       2(a5)/6311976     replace_rte_variables [1032]
                0.00    0.00      98(a6)/6311976     set_plan_refs [77]
                0.00    0.00     295(a7)/6311976     set_upper_references [554]
[75]     1.7    0.41    0.85 32045158(a)+3886192 expression_tree_mutator <cycle 4> [75]
                0.13    0.48 33499624/85468457     lappend [58]
                0.01    0.08 13598206/452086227     palloc [40]
                0.05    0.00 35931349/650254937     check_stack_depth [83]
                0.00    0.03    2425/3012        fix_upper_expr_mutator [485]
                0.03    0.00       6/8           replace_nestloop_params_mutator [468]
                0.02    0.00 7769088/9711360     substitute_actual_parameters_mutator [548]
                0.00    0.02     648/844         fix_join_expr_mutator [552]
                0.00    0.00     203/207         replace_rte_variables_mutator [1038]
                0.00    0.00 3884544/5828433     list_nth [1338]
                0.00    0.00     208/209         flatten_join_alias_vars_mutator [1570]
                             35926889             eval_const_expressions_mutator <cycle 4> [49]
                             3886192             expression_tree_mutator <cycle 4> [75]
-----------------------------------------------

expression_tree_mutator为递归函数

called:递归函数有两个数字,用加号“+“分隔, 第一个数字计数非递归调用,第二个计数递归调用。

递归调用有3886192次(首行和末行)

非递归调用有32045158(a)次。

非递归调用中:a = a1+a2+a3+a4+a5+a6+a7。

 

<cycle 4> :循环编号为4

如果两个函数互相调用,则他们是一个cycle

如果 a 和b 互相调用,b和c 相互调用,则他们是一个cycle。

eval_const_expressions_mutator、expression_tree_mutator、simplify_function函数都属于<cycle 4>。

 

后面有<cycle 4>的都属于这个cycle,且在此处没有统计时间。

原因:a calls b, b calls a,a统计子函数时间时包含了b和b的子函数的运行时间,而a又是b的子函数,统计会出现矛盾。

所以对每个cycle单独统计:

3、cycle(多个函数相互调用)

index % time    self  children    called     name
-----------------------------------------------
[13]    23.1    1.36(t)   15.82(T) 6311976(a)+83992989(b) <cycle 4 as a whole> [13]
                0.43(t1)   13.02(T1) 14079068(c)             simplify_function <cycle 4> [19]
                0.52(t1)   1.94(T2) 44180739(d)+3397819(e)  eval_const_expressions_mutator<cycle 4>[49]
                0.41(t1)    0.85(T3) 32045158(f)+3886192(g)   expression_tree_mutator <cycle 4> [75]
-----------------------------------------------

cycle时间:

t = t1+t2+t3:cycle中的函数们本身运行的时间。

T= T1+T2+T3:cycle中 函数的子函数(cycle外的)的总时间。

 

<cycle 4 as a whole>:调用次数 = 本cycle内的函数总调用次数。

a + b = c+d+f

a:非本cycle的函数调用 本cycle内部函数的次数(每个函数的entry中,caller的 x/y中的y都是a,比如【2、递归函数】中的s)

b:本cycle内部函数 互相调用的次数,递归次数不算

d,f:非递归调用的次数,包含本cycle中的函数调用和外部调用次数。

e,g:递归调用次数

 

关于cycle:

https://sourceware.org/binutils/docs-2.17/gprof/Cycles.html#Cycles

转载于:https://my.oschina.net/ashnah/blog/2243558

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值