我的理解是,默认情况下 gprof 会考虑 CPU 时间。有没有办法让它根据挂钟时间进行配置?
我的程序做了很多磁盘 i/o,所以它使用的 CPU 时间只代表实际执行时间的一小部分。我需要知道磁盘 i/o 的哪些部分占用的时间最多。
您可以使用来自 google-perftools的分析器来测量挂钟时间。要将 google profiler 切换到挂钟模式,请设置环境变量 CPUPROFILE_REALTIME=1。
您可以使用 strace 或 cachegrind 正确分析代码。strace 将为您提供系统调用所花费时间的详细信息,而 cachegrind 将提供资源利用率的详细分析。
您可以使用-finstrument-functions
gcc 编译器的选项来执行此操作。这将获得一个在任何函数的入口/出口点调用的自定义函数,只需要提供几个函数回调(__cyg_profile_func_enter
和__cyg_profile_func_exit
)。
您可以通过查找-finstrument-functions
gcc 手册中的选项来找到更多详细信息。
Balau 的技术博客上也有一篇很好的文章,提供了一个端到端的概述/示例,说明了它是如何工作的:使用 GCC 进行跟踪和配置文件函数调用
更改 gprof 以进行挂钟分析非常容易。唯一要替换的 8 个字符是:
ITIMER_PROF -> ITIMER_REAL
SIGPROF -> SIGALRM
在 file glibc/sysdeps/posix/profil.c
, function __profil
, 附近调用setitimer
and sigaction
(更准确的__Setitimer
and __sigaction
)
更改后,任何使用 SIGALRM 的程序都会被破坏,任何没有阻塞系统调用重启代码的程序都会给出错误的结果。
此外,您可以直接更改 glibc 二进制文件中的 int 值(请不要在系统范围内执行此操作libc.so
,制作单独的副本并使用 LD_LIBRARY_PATH 将其提供给程序)
对于二进制补丁,ITIMER_PROF 为 2;ITIMER_REAL 为 0;SIGPROF 为 27 (0x1b);SIGALRM 为 14 (0x0e)。profil
glibc函数中的每个常量都有两个位置。
另一种方法是编写一个 ptrace 调试器,它将在运行时更改 setitimer 和 sigaction 函数的参数。