跳转到主要内容

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

所有提交的信息确保安全。

  • 关闭 [x]

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

所有提交的信息确保安全。

  • 关闭 [x]

使用 google-perftools 剖析程序性能瓶颈

冯 文龙, 软件工程师, IBM
冯文龙,IBM WPLC Lotus 软件开发工程师。主要从事 Linux 客户端软件的开发,对 Gtk 相关的桌面技术有一定的研究。

简介: google-perftools 是一款优秀的 Linux C/C++ 程序的性能剖析及优化工具,它提供了将目标程序运行时所消耗的 CPU 时间片进行剖析和图形化输出剖析结果的功能。本文将从零开始,一步一步引导读者搭建并运行一个 google-perftools 的剖析环境,并用一个示例来演示如何使用该工具找到目标程序的性能瓶颈。

发布日期: 2010 年 12 月 16 日
级别: 中级
访问情况 : 15245 次浏览
评论: 


google-perftools 简介

google-perftools 是一款针对 C/C++ 程序的性能分析工具,它是一个遵守 BSD 协议的开源项目。使用该工具可以对 CPU 时间片、内存等系统资源的分配和使用进行分析,本文将重点介绍如何进行 CPU 时间片的剖析。 google-perftools 对一个程序的 CPU 性能剖析包括以下几个步骤。
1. 编译目标程序,加入对 google-perftools 库的依赖。
2. 运行目标程序,并用某种方式启动 / 终止剖析函数并产生剖析结果。
3. 运行剖结果转换工具,将不可读的结果数据转化成某种格式的文档(例如 pdf,txt,gv 等)。

安装

您可以在 google-perftools 的网站 (http://code.google.com/p/google-perftools/downloads/list) 上下载最新版的安装包。为完成步骤 3 的工作,您还需要一个将剖析结果转化为程序员可读文档的工具,例如 gv(http://www.gnu.org/software/gv/)。

编译与运行

您需要在原有的编译选项中加入对 libprofiler.so 的引用,这样在目标程序运行时会加载工具的动态库。例如本例中作者的系统中,libprofiler.so 安装在"/usr/lib"目录下,所以需要在 makefile 文件中的编译选项加入“-L/usr/lib -lprofiler”。

google-perftools 需要在目标代码的开始和结尾点分别调用剖析模块的启动和终止函数,这样在目标程序运行时就可以对这段时间内程序实际占用的 CPU 时间片进行统计和分析。工具的启动和终止可以采用以下两种方式。

a. 使用调试工具 gdb 在程序中手动运行性能工具的启动 / 终止函数。

gdb 是 Linux 上广泛使用的调试工具,它提供了强大的命令行功能,使我们可以在程序运行时插入断点并在断点处执行其他函数。具体的文档请参照 http://www.gnu.org/software/gdb/,本文中将只对用到的几个基本功能进行简单介绍。使用以下几个功能就可以满足我们性能调试的基本需求,具体使用请参见下文示例。

命令功能
ctrl+c暂停程序的运行
c继续程序的运行
b添加函数断点(参数可以是源代码中的行号或者一个函数名)
p打印某个量的值或者执行一个函数调用

b. 在目标代码中直接加入性能工具函数的调用,该方法就是在程序代码中直接加入调试函数的调用。

两种方式都需要对目标程序重新编译,加入对性能工具的库依赖。对于前者,他的好处是使用比较灵活,但工具的启动和终止依赖于程序员的手动操作,常常需要一些暂停函数(比如休眠 sleep)的支持才能达到控制程序的目的,因此精度可能受到影响。对于后者,它需要对目标代码的进行修改,需要处理函数声明等问题,但得到的结果精度较高,缺点是每次重新设置启动点都需要重新编译,灵活度不高,读者可以根据自己的实际需求采用有效的方式。

示例详解

该程序是一个简单的例子,文中有两处耗时的无用操作,并且二者间有一定的调用关系。


清单 1. 示例程序
				
 void consumeSomeCPUTime1(int input){ 
  int i = 0; 
  input++; 
  while(i++ < 10000){ 
    i--;  i++;  i--;  i++; 
  } 
 }; 

 void consumeSomeCPUTime2(int input){ 
  input++; 
  consumeSomeCPUTime1(input); 
  int i = 0; 
  while(i++ < 10000){ 
    i--;  i++;  i--;  i++; 
  } 
 }; 

 int stupidComputing(int a, int b){ 
  int i = 0; 
  while( i++ < 10000){  
    consumeSomeCPUTime1(i); 
  } 
  int j = 0; 
  while(j++ < 5000){ 
    consumeSomeCPUTime2(j); 
  } 
  return a+b; 
 }; 

 int smartComputing(int a, int b){ 
  return a+b; 
 }; 

 void main(){ 
  int i = 0;
  printf("reached the start point of performance bottle neck\n"); 
  sleep(5);
				//ProfilerStart("CPUProfile");
  while( i++ < 10){ 
    printf("Stupid computing return : %d\n",stupidComputing(i, i+1)); 
    printf("Smart computing return %d\n",smartComputing(i+1, i+2)); 
  }
  printf("should teminate profiling now.\n");  
  sleep(5);
				//ProfilerStop();
 } 
			

源代码中粗体的内容(方法 1)和斜体的内容(方法 2)分别代表了上文中提及胡两种执行剖析的方式。采用方法二时将直接产生结果,采用方法 1 时需要配合 GDB 的命令来实现剖析的执行和结束,可用的方法有两种,一种是在程序运行时手动暂停函数的执行,另一种是预设断点,并在断点处执行剖析函数,两种方法(方法 a,方法 b)在命令行中的具体操作如下。
方法 a
gdb YOUR_PROGRAM // 启动 gdb 并选择你的程序为 gdb 的启动目标
(gdb)r // 运行
// 等待你需要的条件满足,此处示例中打印了字符
(gdb)Ctrl + c // 暂停当前函数
(gdb)p ProfilerStart("MyProfile")
(gdb)c // 继续程序运行
// 等待程序打印目标模块结束,此处示例打印了提示
(gdb)Ctrl + c // 暂停当前函数
(gdb)p ProfilerStop()

方法 b
gdb YOUR_PROGRAM // 启动 gdb 并选择你的程序为 gdb 的启动目标
(gdb)b main1.c:47 // 对应于耗时模块的起始点
(gdb)b main1.c:52 // 对应于耗时模块的终止点
(gdb)r // 运行
(gdb)p ProfilerStart("MyProfile")
(gdb)c // 继续程序运行
(gdb)p ProfilerStop()

结果分析

程序执行完毕会在程序的当前工作目录下产生名为 MyProfile 的结果文件。我们可以用以下命令产生可视化的结果文档。
pprof --gv ./codeTest MyProfile
其中 codeTest 对应于用于测试的目标程序文件名,如果您安装了 pdf 相关的软件您还可以尝试生成 pdf 格式的结果文档,其对应的命令为
pprof --pdf ./codeTest MyProfile > MyProfile.pdf
转换后产生的结果文档如下图。图中的数字和框体的大小代表了的某个函数的运行时间占整个剖析时间的比例。由代码的逻辑可知,stupidComputing,stupidComputing2 都是费时操作并且它们和 consumeSomeCPUTime 存在着一定的调用关系。


图 1. 剖析结果
剖析结果

结束语

本文介绍了一个 Linux 平台上的性能剖析工具 google-perftools,并结合实例向读者展示了如何使用该工具配置、使用及分析性能瓶颈。



下载

描述名字大小下载方法
本文用到的示例src.rar4KBHTTP

关于下载方法的信息


参考资料

学习

讨论

关于作者

冯文龙,IBM WPLC Lotus 软件开发工程师。主要从事 Linux 客户端软件的开发,对 Gtk 相关的桌面技术有一定的研究。

关于报告滥用的帮助

报告滥用

谢谢! 此内容已经标识给管理员注意。


关于报告滥用的帮助

报告滥用

报告滥用提交失败。 请稍后重试。


developerWorks:登录


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 使用条款

 


当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

请选择您的昵称:

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

(长度在 3 至 31 个字符之间)


单击提交则表示您同意developerWorks 的条款和条件。 使用条款.

 


为本文评分

评论

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Linux
ArticleID=601984
ArticleTitle=使用 google-perftools 剖析程序性能瓶颈
publish-date=12162010
author1-email=fengwl@cn.ibm.com
author1-email-cc=

标签

Help
使用 搜索 文本框在 My developerWorks 中查找包含该标签的所有内容。

使用 滑动条 调节标签的数量。

热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。

我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。

使用搜索文本框在 My developerWorks 中查找包含该标签的所有内容。热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。