使用gprof来对程序的性能分析总结

综述

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

注意事项

  • 程序如果不是从main return或exit()退出,则可能不生成gmon.out。
  • 程序如果崩溃,可能不生成gmon.out。
  • 测试发现在虚拟机上运行,可能不生成gmon.out。
  • 一定不能捕获、忽略SIGPROF信号。man手册对SIGPROF的解释是:profiling timer expired. 如果忽略这个信号,gprof的输出则是:Each sample counts as 0.01 seconds. no time accumulated.
  • 如果程序运行时间非常短,则gprof可能无效。因为受到启动、初始化、退出等函数运行时间的影响。
  • 程序忽略SIGPROF信号!

原理

gcc -pg 在应用程序的每个函数中添加了名为 mcount/mcount/_mcount的函数。 应用程序每个函数执行时都会执行mcount,而mcount则会在内存中保存一张函数调用图, 通过函数调用堆栈的形式,查找子函数、父函数的地址,也保存了与函数相关的调用时间、次数等信息。

多进程

如果用gprof分析多进程程序,则可能一个进程的gmon.out覆盖另一个进程的gmon.out, 解决方法是在执行程序之前执行:export GMON_OUT_PREFIX=x.out 则之后生成的文件名就如x.out.pid,多进程的gmon.out就不会相互覆盖。

多线程

gprof无法分析多线程程序。缘故是gprof使用ITIMER_PROF定时器, 当超时时由内核向应用程序发送信号。但多线程程序只有主线程接收ITIMER_PROF。 这里有一个简单的实现方法:
对pthread_create进行包装,并以动态库的形式在程序运行前加载。 我通过上文的描述,整理了一个gprof分析多线程程序的程序,可供参考。

<span class="pln" style="color: rgb(0, 0, 0);">$ gcc </span><span class="pun" style="color: rgb(102, 102, 0);">-</span><span class="pln" style="color: rgb(0, 0, 0);">shared </span><span class="pun" style="color: rgb(102, 102, 0);">-</span><span class="pln" style="color: rgb(0, 0, 0);">fPIC gprof_helper</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">c </span><span class="pun" style="color: rgb(102, 102, 0);">-</span><span class="pln" style="color: rgb(0, 0, 0);">o ghelper2</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">so </span><span class="pun" style="color: rgb(102, 102, 0);">-</span><span class="pln" style="color: rgb(0, 0, 0);">lpthread </span><span class="pun" style="color: rgb(102, 102, 0);">-</span><span class="pln" style="color: rgb(0, 0, 0);">ldl  </span><span class="com" style="color: rgb(136, 0, 0);"># create ghelp2.so</span><span class="pln" style="color: rgb(0, 0, 0);">
$ gcc test</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">c </span><span class="pun" style="color: rgb(102, 102, 0);">-</span><span class="pln" style="color: rgb(0, 0, 0);">lpthread
$ </span><span class="pun" style="color: rgb(102, 102, 0);">./</span><span class="pln" style="color: rgb(0, 0, 0);">a</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="kwd" style="color: rgb(0, 0, 136);">out</span><span class="pln" style="color: rgb(0, 0, 0);">
    hello gprof     </span><span class="com" style="color: rgb(136, 0, 0);"># output</span><span class="pln" style="color: rgb(0, 0, 0);">
$ LD_PRELOAD</span><span class="pun" style="color: rgb(102, 102, 0);">=./</span><span class="pln" style="color: rgb(0, 0, 0);">ghelper2</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">so </span><span class="pun" style="color: rgb(102, 102, 0);">./</span><span class="pln" style="color: rgb(0, 0, 0);">a</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="kwd" style="color: rgb(0, 0, 136);">out</span><span class="pln" style="color: rgb(0, 0, 0);">
    pthread</span><span class="pun" style="color: rgb(102, 102, 0);">:</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">using</span><span class="pln" style="color: rgb(0, 0, 0);"> profiling hooks </span><span class="kwd" style="color: rgb(0, 0, 136);">for</span><span class="pln" style="color: rgb(0, 0, 0);"> gprof    </span><span class="com" style="color: rgb(136, 0, 0);"># output</span><span class="pln" style="color: rgb(0, 0, 0);">
    hello gprof                                 </span><span class="com" style="color: rgb(136, 0, 0);"># output</span><span class="pln" style="color: rgb(0, 0, 0);">

</span><span class="com" style="color: rgb(136, 0, 0);"># no time accumulated</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="typ" style="color: rgb(102, 0, 102);">Each</span><span class="pln" style="color: rgb(0, 0, 0);"> sample counts </span><span class="kwd" style="color: rgb(0, 0, 136);">as</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="lit" style="color: rgb(0, 102, 102);">0.01</span><span class="pln" style="color: rgb(0, 0, 0);"> seconds</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="kwd" style="color: rgb(0, 0, 136);">no</span><span class="pln" style="color: rgb(0, 0, 0);"> time accumulated</span>

gprof的输出表明没有时间被统计到。虽然函数调用次数是统计正确的,但没有时间(调用次数多未必就最耗时)。 gprof显示每0.01秒采样一次,如果函数执行的时间都非常短,例如低于0.01秒,则统计不到任何时间。

目录

1.    GPROF介绍    4

2.    使用步骤    4

3.    使用举例    4

3.1    测试环境    4

3.2    测试代码    4

3.3    数据分析    5

3.3.1    flat profile模式    6

3.3.2    call graph模式    7

4.    链接库中的函数    7

5.    使用局限    8

6.    分析示例    12

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

1.    gprof介绍

gprof是GNU profile工具,可以运行于linux、AIX、Sun等操作系统进行C、C++、Pascal、Fortran程序的性能分析,用于程序的性能优化以及程序瓶颈问题的查找和解决。通过分

析应用程序运行时产生的“flat profile”,可以得到每个函数的调用次数,每个函数消耗的处理器时间,也可以得到函数的“调用关系图”,包括函数调用的层次关系,每个函

数调用花费了多少时间。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

2.    使用步骤

1)    用gcc、g++、xlC编译程序时,使用-pg参数,如:g++ -pg -o test.exe test.cpp

编译器会自动在目标代码中插入用于性能测试的代码片断,这些代码在程序运行时采集并记录函数的调用关系和调用次数,并记录函数自身执行时间和被调用函数的执行时间。

2)    执行编译后的可执行程序,如:./test.exe。该步骤运行程序的时间会稍慢于正常编译的可执行程序的运行时间。程序运行结束后,会在程序所在路径下生成一个缺省文

件名为gmon.out的文件,这个文件就是记录程序运行的性能、调用关系、调用次数等信息的数据文件。

3)    使用gprof命令来分析记录程序运行信息的gmon.out文件,如:gprof test.exe gmon.out则可以在显示器上看到函数调用相关的统计、分析信息。上述信息也可以采用

gprof test.exe gmon.out> gprofresult.txt重定向到文本文件以便于后续分析。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

3.    使用举例

3.1    测试环境

本文提供的样例的测试环境如下:

?    Linux server164 2.6.9-22.ELsmp #1 SMP Mon Sep 19 18:32:14 EDT 2005 i686 i686 i386 GNU/Linux

?    gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-47.3)

?    GNU gprof 2.15.92.0.2

3.2    测试代码

清单 1. 耗时测试应用程序示例

example1.c

#include

int a(void)

{

int i=0,g=0;

while(i++<100000)

{

g+=i;

}

return g;

}

int b(void)

{

int i=0,g=0;

while(i++<400000)

{

g +=i;

}

return g;

}

int main(int argc, char** argv)

{

int iterations;

if(argc != 2)

{

printf("Usage %s \n", argv[0]);

exit(-1);

}

else

iterations = atoi(argv[1]);

printf("No of iterations = %d\n", iterations);

while(iterations--)

{

a();

b();

}

}

这个应用程序包括两个函数:a 和 b,它们通过运行不同次数的循环来消耗不同的CPU时间。main 函数中采用了一个循环来反复调用这两个函数。函数b中循环的次数是 a 函数的

4 倍,因此我们期望通过gprof的分析结果可以观察到大概有 20% 的时间花在了 a 函数中,而 80% 的时间花在了 b 函数中。

3.3    数据分析

在 gcc 编译命令中加上 –pg参数即可。编译方法如下:

gcc example1.c -pg -o example1 -O2 -lc

在编译好这个应用程序之后,按照普通方式运行这个程序:

./example1 50000

程序运行完之后,应该会看到在当前目录中新创建了一个文件 gmon.out。

3.3.1    flat profile模式

使用 gprof 命令分析gmon.out 文件,如下所示:

gprof example1 gmon.out -p

-p参数标识“flat profile”模式,在分析结果中不显示函数的调用关系,AIX平台默认此参数有效。

输出以下内容:

清单 2. flat profile 的结果

Flat profile:

Each sample counts as 0.01 seconds.

%    cumulative   self              self     total

time   seconds   seconds    calls  ms/call  ms/call  name

80.38    203.27   203.27    50000     4.07     4.07    b

19.61    252.87    49.60    50000     0.99     0.99    a

0.00    252.88     0.01                                  main

上面结果中各个列的含义如下:

%time       函数以及衍生函数(函数内部再次调用的子函数)所占的总运行时间的百分比

cumulative seconds 函数累计执行的时间

self seconds  函数执行占用的时间

calls          函数的调用次数

self   ms/call   每一次调用函数花费的时间microseconds,不包括衍生函数的运行时间

total  ms/call    每一次调用函数花费的时间microseconds,包括衍生函数的运行时间

name           函数名称

列的含义,在gprof的输出结果中都有详细的说明。

从输出结果中可以看到,正如我们期望的一样,b 函数所花费的时间大概是 a 函数所花费的时间的 4倍。

很多函数调用(例如 printf)在上面的输出结果中都没有出现。这是因为大部分函数都是在C链接库(libc.so)中,而链接库并没有使用 -pg 进行编译,因此就没有对链接库中

的函数收集调度信息。

3.3.2    call graph模式

如果希望反映函数之间的调用关系,需要采用如下命令:

gprof example1 gmon.out –q

-q参数标识“call graph”模式,在分析结果中显示函数的调用关系。

输出以下内容:

清单 3. Call graph

granularity: each sample hit covers 4 byte(s) for 0.00% of 252.72 seconds

index % time    self  children    called     name

[1]    100.0    0.00  252.72                 main [1]

201.41    0.00   50000/50000       b [2]

51.31    0.00   50000/50000       a [3]

-----------------------------------------------

201.41    0.00   50000/50000       main [1]

[2]     79.7 201.41    0.00   50000         b [2]

-----------------------------------------------

51.31    0.00   50000/50000       main [1]

[3]     20.3   51.31    0.00   50000         a [3]

-----------------------------------------------

上面结果中各个列的含义如下:

index   每个函数第一次出现时都分配了一个编号,根据编号可以方便的查找函数的具体分析数据

%time  函数以及衍生函数(函数内部再次调用的子函数)所占的总运行时间的百分比

self    函数的总运行时间

children 衍生函数执行的总时间

called   函数被调用的次数,不包括递归调用

name   函数名称

在name列中,可以看出函数之间的调用关系,main函数调用a、b函数,b函数被main函数调用,a函数被main函数调用。通过函数名称后面的数字来标识这个文件中的函数,从而可

以快速定位函数的分析数据的位置,经过一层层的逐步深入的分析就得到各个函数的调用关系以及各个函数的性能数据。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

4.    链接库中的函数

正如在前面曾经介绍的,对于代码剖析的支持是由编译器增加的,因此如果希望从链接库(比如libc.a)中获得剖析信息,就需要使用 -pg 来编译这些库。很多操作系统默认提供

了已经启用代码剖析支持而编译的链接库版本,例如:libc.a对应的采用-pg编译的文件为libc_p.a。对于没有按照标准提供类似libc_p.a链接库的操作系统版本来说,就需要安装

已经编译好的启用代码剖析的链接库版本或者自己下载链接库的源代码进行编译。

使用“启用代码剖析的链接库版本”的应用场景,举例如下:

gcc example1.c -g -pg -o example1 -O2 -lc_p

然后,像普通情况下一样运行gprof对gmon.out进行分析,可以获得 flat profile 或 call graph,而此时的分析结果会非常丰富,包含很多C的标准库函数的调用信息,例如:

printf、write等。

注意:上例的libc_p.a是静态链接库。gprof目前还不支持对动态链接库中的函数进行性能分析。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

5.    使用局限

gprof的特点是它只能分析应用程序在运行过程中所消耗掉的CPU时间,只有当应用程序的函数消耗CPU的时候,gprof才能够获取函数的性能数据。如果应用程序在运行过程中暂时

挂起,并在系统内核唤醒应用程序后进一步执行,那么在应用程序中间暂停的时间性能数据是无法统计的;而且在应用程序等待I/O操作返回的时间,性能数据也是无法统计的。

如果对清单 1 稍加修改,就可以清楚地看出这个问题:

清单 5. 为清单 1 添加sleep()函数调用

example2.c:

#include

int a(void)

{

sleep(1);               /*调用系统函数进行sleep*/

return 0;

}

int b(void)

{

sleep(4);               /*调用系统函数进行sleep*/

return 0;

}

int main(int argc, char** argv)

{

int iterations;

if(argc != 2)

{

printf("Usage %s \n", argv[0]);

exit(-1);

}

else

iterations = atoi(argv[1]);

printf("No of iterations = %d\n", iterations);

while(iterations--)

{

a();

b();

}

}

现在 a 函数和 b 函数不再处理繁忙的循环了,而是分别调用sleep()来挂起1秒和4秒。

使用“启用代码剖析的链接库版本”,编译这个应用程序:

gcc example2.c -g -pg -o example2 -O2 -lc_p

并让这个应用程序循环 30 次:

./example2 30

执行gprof example2 gmon.out –p所生成的结果如下:

清单 6. flat profile 显示了系统调用的结果

Flat profile:

Each sample counts as 0.01 seconds.

no time accumulated

%   cumulative   self              self     total

time   seconds   seconds    calls  Ts/call  Ts/call  name

0.00      0.00     0.00       21     0.00     0.00  _IO_file_overflow

0.00      0.00     0.00       13     0.00     0.00  strncmp

0.00      0.00     0.00        8     0.00     0.00  memset

0.00      0.00     0.00        8     0.00     0.00  sigprocmask

0.00      0.00     0.00        7     0.00     0.00  getenv

0.00      0.00     0.00        6     0.00     0.00  memcpy

0.00      0.00     0.00        5     0.00     0.00  _int_malloc

0.00      0.00     0.00        5     0.00     0.00  malloc

0.00      0.00     0.00        5     0.00     0.00  sigaction

0.00      0.00     0.00        5     0.00     0.00  strsep

0.00      0.00     0.00        4     0.00     0.00  nanosleep

0.00      0.00     0.00        4     0.00     0.00  sleep

0.00      0.00     0.00        4     0.00     0.00  strpbrk

0.00      0.00     0.00        3     0.00     0.00  _IO_new_file_xsputn

0.00      0.00     0.00        3     0.00     0.00  ____strtoul_l_internal

0.00      0.00     0.00        3     0.00     0.00  __cxa_atexit

0.00      0.00     0.00        3     0.00     0.00  __strtoul_internal

0.00      0.00     0.00        2     0.00     0.00  __errno_location

0.00      0.00     0.00        2     0.00     0.00  __find_specmb

0.00      0.00     0.00        2     0.00     0.00  a

0.00      0.00     0.00        2     0.00     0.00  b

0.00      0.00     0.00        2     0.00     0.00  mempcpy

0.00      0.00     0.00        1     0.00     0.00  _IO_default_xsputn

0.00      0.00     0.00        1     0.00     0.00  _IO_doallocbuf

0.00      0.00     0.00        1     0.00     0.00  _IO_file_doallocate

0.00      0.00     0.00        1     0.00     0.00  _IO_file_stat

0.00      0.00     0.00        1     0.00     0.00  _IO_file_write

0.00      0.00     0.00        1     0.00     0.00  _IO_setb

0.00      0.00     0.00        1     0.00     0.00  ____strtol_l_internal

0.00      0.00     0.00        1     0.00     0.00  ___fxstat64

0.00      0.00     0.00        1     0.00     0.00  __init_misc

0.00      0.00     0.00        1     0.00     0.00  __libc_csu_fini

0.00      0.00     0.00        1     0.00     0.00  __libc_csu_init

0.00      0.00     0.00        1     0.00     0.00  __libc_init_first

0.00      0.00     0.00        1     0.00     0.00  __libc_init_secure

0.00      0.00     0.00        1     0.00     0.00  __libc_setup_tls

0.00      0.00     0.00        1     0.00     0.00  __libc_start_main

0.00      0.00     0.00        1     0.00     0.00  __pthread_initialize_minimal

0.00      0.00     0.00        1     0.00     0.00  __setfpucw

0.00      0.00     0.00        1     0.00     0.00  __strtol_internal

0.00      0.00     0.00        1     0.00     0.00  _dl_aux_init

0.00      0.00     0.00        1     0.00     0.00  _dl_important_hwcaps

0.00      0.00     0.00        1     0.00     0.00  _dl_init_paths

0.00      0.00     0.00        1     0.00     0.00  _dl_non_dynamic_init

0.00      0.00     0.00        1     0.00     0.00  _itoa_word

0.00      0.00     0.00        1     0.00     0.00  _mcleanup

0.00      0.00     0.00        1     0.00     0.00  atexit

0.00      0.00     0.00        1     0.00     0.00  atoi

0.00      0.00     0.00        1     0.00     0.00  exit

0.00      0.00     0.00        1     0.00     0.00  fillin_rpath

0.00      0.00     0.00        1     0.00     0.00  fini

0.00      0.00     0.00        1     0.00     0.00  flockfile

0.00      0.00     0.00        1     0.00     0.00  funlockfile

0.00      0.00     0.00        1     0.00     0.00  main

0.00      0.00     0.00        1     0.00     0.00  mmap

0.00      0.00     0.00        1     0.00     0.00  printf

0.00      0.00     0.00        1     0.00     0.00  setitimer

0.00      0.00     0.00        1     0.00     0.00  strrchr

0.00      0.00     0.00        1     0.00     0.00  uname

0.00      0.00     0.00        1     0.00     0.00  vfprintf

0.00      0.00     0.00        1     0.00     0.00  write

对以上输出结果进行分析可见,尽管 profile 已经记录了每个函数被调用的确切次数,但是为这些函数记录的时间(实际上是所有函数)都是 0.00。这是因为 sleep 函数实际上

是执行了一次对内核空间的调用,从而将应用程序的执行挂起了,然后有效地暂停执行,并等待内核再次将其唤醒。由于花在用户空间执行的时间与花在内核中睡眠的时间相比非

常小,因此就被取整成零了。其原因是 gprof 以固定的周期对程序运行时间进行采样测量,当程序挂起时,gprof就不会对程序进行采样测量。

Gprof的特性使得有些程序非常难以进行优化,例如花费大部分时间睡眠等待内核唤醒的程序,或者由于外部因素(例如操作系统的 I/O 子系统过载)而运行得非常慢的程序。

通常,有一个很好的基准测试可以用来查看 gprof 对于应用程序的优化能起多大作用,方法是在 time 命令下面执行应用程序。此命令会显示一个应用程序运行完成需要多少时间

,并且在用户空间和内核空间各花费了多少时间。

例如:time ./example2 30

输出结果如下所示:

清单 7. time 命令的输出结果

No of iterations = 30

real    2m30.295s

user    0m0.000s

sys     0m0.004s

我们可以看出应用程序整体运行150秒左右,但大部分时间在睡眠状态,几乎没有多少时间被花费在执行用户空间和内核空间的代码上,此时gprof的分析结果无法体现函数的实际

运行时间。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

6.    分析示例

在新疆联通进行综合入库程序上线前的测试过程中,测试人员发现程序运行效率低下。下面以整个调优的过程来举例说明基于gprof的性能分析方法。

性能分析前的准备阶段,性能分析数据的生成步骤如下:

1)    首先更改makefile文件中的CC=g++ -g –pg 行,添加-pg参数。

2)    执行make clean删除所有的目标文件、可执行文件

3)    重新编译

4)    在命令行执行可执行程序,并通过控制台发送启动命令

5)    程序退出后在fileindb执行程序目录下生成gmon.out(不是控制台目录)

6)    执行gprof fileindb > gsmindb_mon_result.txt把分析结果重定向到gsmindb_mon_result.txt文件

下面就是从gsmindb_mon_result.txt文件中截取的部分内容:

打开gsmindb_mon_result.txt文件后,可以看到127行:

[3]     37.2    0.00       41.90       1         .main [3]

0.00       41.88       1/1       .CMainManager::Run(int&) [4]

可见main函数中的CMainManager::Run运行时间(41.88)几乎占据了所有的运行时间(41.90),再查CMainManager::Run的分析数据在148行:

[4]     37.2    0.00       41.88       1         .CMainManager::Run(int&) [4]

0.00       41.81       1/1       .CBaseBillFile::DoEveryBill() [5]

可见CMainManager::Run 函数中CBaseBillFile::DoEveryBill执行占了几乎所有的时间,对于占用时间比重很小的函数可以忽略。采用上面的方法一步一步向下查找,最终确定289

行:

0.56       11.98  849922/849922      .CMobileFavour::CheckAllCondition(int,int) [11]

[12] 11.1    0.56       11.98  849922             .CGsmFavourCheck::CheckAllCondition() [12]

0.06        5.82  849922/849922      .CGsmFavourCheck::CheckCallKind() [14]

在CGsmFavourCheck::CheckAllCondition()所调用的函数中CGsmFavourCheck::CheckCallKind()占用时间的比重过大,几乎达到50%;CGsmFavourCheck::CheckAllCondition总共用

时11.98,而CGsmFavourCheck::CheckCallKind()函数就占用了5.82,从而说明CGsmFavourCheck::CheckCallKind()函数需要作进一步优化,以提高整体的运行效率。

时间: 2024-10-16 03:56:08

使用gprof来对程序的性能分析总结的相关文章

PHP程序的性能分析与调优基础

1.xdebug xdebug是一个开发源代码的PHP程序调试器(即一个debug工具),可以用来跟踪.调试和分析PHP程序的运行状况. 安装与配置: 1)安装phpize: yum -y install  php-devel 2)安装xdebug: 下载(http://xdebug.org/).解压.上传到linux.执行: cd phpize ./configure  --enable-xdebug make && make install 3)配置: vi  /etc/php.ini

使用gprof对应用程序做性能评测

1,包含头文件gperftools/profiler.h 2,代码结构如下: int main() { // codes ProfilerStart("./profile"); // working... ProfilerStop(); } 3,程序运行完之后,会在本地生成一个名为profile的文件 4,运行下面的命令即可看出简单的评测图 pprof --text programeName profile 更复杂的操作看pprof的help信息.

三种Linux性能分析工具的比较

无论是在CPU设计.服务器研发还是存储系统开发的过程中,性能总是一个绕不过去的硬指标.很多时候,我们发现系统功能完备,但就是性能不尽如意,这时候就需要找到性能瓶颈.进行优化.首先我们需要结合硬件特点.操作系统和应用程序的特点深入了解系统内部的运行机制.数据流图和关键路径,最好找出核心模块.建立起抽象模型:接着需要利用各种性能分析工具,探测相关模块的热点路径.耗时统计和占比.在这方面,Linux操作系统自带了多种灵活又具有专对性的工具,此外一些厂家也开源了不少优秀的性能分析工具.下面就结合笔者最近

性能分析神器VisualVM

VisualVM 是一款免费的,集成了多个 JDK 命令行工具的可视化工具,它能为您提供强大的分析能力,对 Java 应用程序做性能分析和调优.这些功能包括生成和分析海量数据.跟踪内存泄漏.监控垃圾回收器.执行内存和 CPU 分析,同时它还支持在 MBeans 上进行浏览和操作.本文主要介绍如何使用 VisualVM 进行性能分析及调优. 目录: 准备工作 内存分析篇 内存堆Heap 永久保留区域PermGen CPU分析篇 线程分析篇 参考文献 准备工作 自从 JDK 6 Update 7 以

Java 性能分析工具 , 第 2 部分:Java 内置监控工具

引言 本文为 Java 性能分析工具系列文章第二篇,第一篇:操作系统工具.在本文中将介绍如何使用 Java 内置监控工具更加深入的了解 Java 应用程序和 JVM 本身.在 JDK 中有许多内置的工具,其中包括: jcmd:打印一个 Java 进程的类,线程以及虚拟机信息.适合用在脚本中.使用 jcmd - h 来查看使用方法. jconsole:提供 JVM 活动的图形化展示,包括线程使用,类使用以及垃圾回收(GC)信息. jhat:帮助分析内存堆存储. jmap:提供 JVM 内存使用信息

性能和性能分析

性能分析是指观察和记录有关应用程序行为的度量的过程.常见的性能问题源于运行速度慢或低效的代码,或者导致内存浪费的代码. 大多数性能分析工具都可以归为: 采样式:采样式性能分析器通过获取运行应用程序的周期性快照(称为采样),记录每个时间间隔内的应用程序运行状态,包括正在执行的代码行.通常情况下,不会修改被测系统代码,而倾向于采用外部透视方法. 插装式:采用侵入式方案. 两者的主要区别在于,采样式分析器在运行任何代码时都会检查应用程序,包括对外部库的调用.而插装式分析器则只从插装代码收集数据. Vi

程序员修炼之路-(1)基础(中):性能分析

3 算法分析 "分析"二字的含义很广泛,在算法分析的领域,指的就是算法的效率,包括运行时间效率(时间复杂度)和内存空间使用效率(空间复杂度)两方面.同时,研究表明,通常时间方面比空间能取得更大的进展,因此我们进一步将分析的重点放在时间复杂度上. 3.1 算法分析 - 科学实验方法 科学家用来理解自然世界的方法对分析程序的运行时间来说同样有效: 1)     观察:观察自然世界的一些特性,并用准确的度量表示. 2)     假设:假设一个能与观察保持一致的模型. 3)     预测:用上

程序调试和性能分析常用技巧

程序调试和性能分析通常需要设计到多种工具,有时甚至需要跨越用户态和内核态.本文总结了在程序调试和性能分析过程中常碰到三个问题,既是为了方便自己后面温习,也是为了和碰到同样问题的朋友一起分享. 1.如何调试多线程的程序? 多线程程序运行的时候如果出现崩溃或者产生core的时候,最困难的是很难定位到底是哪个线程导致的问题.为此,可以利用gdb工具中的thread apply命令来指定在某个ID的线程上运行gdb命令,比如下面的命令就是在fuse进程的1至250号线程上运行bt命令,然后把所有线程的"

VS2010自带的性能分析工具分析.NET程序的性能

这篇博文给大家分享的是,如何使用VS自带的性能分析工具来分析我们编写的.NET程序,一边找出程序性能的瓶颈,改善代码的质量.在实际开发中,性能真的很重要,往往决定一个产品的生死~良好的用户体验的基础之一也是程序要有好的性能~ 下面以一个大家熟悉比较极端的例子,来说明编写代码时考虑性能的重要性.这里DebugLZQ用的是10.0版本的VS. 示例程序代码如下: using System;using System.Collections.Generic;using System.Linq;using