【问题标题】:Get gprof to profile based on wall-clock time?让 gprof 根据挂钟时间进行分析?
【发布时间】:2011-02-17 17:40:51
【问题描述】:

我的理解是默认情况下 gprof 会考虑 CPU 时间。有没有办法让它根据挂钟时间进行分析?

我的程序执行大量磁盘 i/o,因此它使用的 CPU 时间仅代表实际执行时间的一小部分。我需要知道磁盘 i/o 的哪些部分占用的时间最多。

【问题讨论】:

  • 你可能需要 gprof 以外的东西。
  • 查看 dtrace,具体取决于您的架构。
  • 这是一个 Linux 系统上的 C++ 程序,如果有帮助的话。

标签: c++ profiling gprof


【解决方案1】:

gprof 不会这样做。 看at this

And this.

简而言之:在 gdb 下,让它运行并随机执行 Ctrl-Break 或 Ctrl-C 10 次,然后显示调用堆栈。如果您的 I/O 占用(例如)60% 的时间,那么(大约)10 次暂停中的 6 次,您将在 writebuf 或 readbuf 例程中看到它,并且请求 I/O 的代码行将清楚地显示在堆栈上。

您也可以使用 lsstack 来获取相同的信息。

【讨论】:

  • 嗯...这种方法在统计上会不会很不准确?是否有一种自动化的方式来执行此操作,它需要 10 多个样本,比如 1000 个样本,但以均匀的间隔,然后报告最常遇到的函数?
  • @jetwolf:Zoom 是一个使用 10^3 个样本进行分析的分析器示例,但请检查第一个链接,尤其是第 5、2、7 和 9 项。
  • @jetwolf:示例:假设 I/O 正好是 60%。显示它的样本数的标准偏差是 sqrt(NF(1-F))。对于 10 个 +/- 1.55 的样本,对于 1000 个样本,它是 15.5。因此,在 10 个样本中,您会看到大约 4.45 - 7.55 次。在 1000 个样本中,您将看到大约 584.5 - 615.5 次。无论哪种方式,您都会确切地看到导致它的原因,因此如果可以修复,您可以修复它。
  • @jetwolf:另一种说法。假设 I/O 正好是 60%。 10 个样本将测量 60%,给予或接受 15%。对于 1000 个样本,它将是 1.5%。对于 100,000 个样本,它将是 0.15%。所以他们都测量了它,但是如果他们在调用堆栈上的行级别进行汇总,它们只会向您显示问题的原因,并且采集大量样本的分析器往往会丢弃这些信息,因此额外的测量精度来自发现问题的代价。
【解决方案2】:

您可以使用 strace 或 cachegrind 正确分析代码。 strace 将为您提供系统调用所用时间的详细信息,cachegrind 将提供资源利用率的详细分析。

【讨论】:

    【解决方案3】:

    更改 gprof 以进行挂钟分析非常容易。唯一要替换的 8 个字符是:

    ITIMER_PROF -> ITIMER_REAL
    
    SIGPROF -> SIGALRM
    

    在文件glibc/sysdeps/posix/profil.c,函数__profil中,靠近对setitimersigaction的调用(更确切地说是__Setitimer__sigaction

    更改后,任何使用 SIGALRM 的程序都会被破坏,任何没有阻塞系统调用重启代码的程序都会给出错误的结果。

    另外,您可以直接更改 glibc 二进制文件中的 int 值(请不要在系统范围内进行此操作libc.so,制作单独的副本并使用 LD_LIBRARY_PATH 将其提供给程序)

    对于二进制补丁,ITIMER_PROF 为 2; ITIMER_REAL 为 0; SIGPROF 为 27 (0x1b); SIGALRM 为 14 (0x0e)。 glibc 的函数profil 中每个常量都有两个位置。

    另一种方法是编写一个 ptrace-debugger,它将在运行时更改 setitimer 和 sigaction 函数的参数。

    【讨论】:

    • 不幸的是,在更改了 libc 二进制文件后,这种方法失败了。计时器和信号已更改,但是.. profil()(由 gmon 使用,由 -pg 激活)无法分析动态库(大多数阻塞函数所在的位置)。此外,当阻塞系统调用处于活动状态时,从信号处理程序中看到的 eip 对于动态库(指向 glibc,但不在系统调用包装器中)是错误的,对于静态链接是 NULL。
    【解决方案4】:

    您可以使用 google-perftools 中的 profiler 来测量挂钟时间。要将 google profiler 切换到挂钟模式,请设置环境变量 CPUPROFILE_REALTIME=1。

    【讨论】:

    【解决方案5】:

    您可以在 gcc 编译器中使用 -finstrument-functions 选项来执行此操作。这将获得一个在任何函数的入口/出口点调用的自定义函数,只需要提供几个函数回调(__cyg_profile_func_enter__cyg_profile_func_exit)。

    您可以通过查看 gcc 手册中的 -finstrument-functions 选项来找到更多详细信息。

    Balau 的技术博客上也有一篇很好的文章,提供了一个端到端的概述/如何工作的示例:Trace and profile function calls with GCC

    【讨论】:

      猜你喜欢
      • 2019-07-13
      • 2015-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-11
      • 2014-11-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多