【问题标题】:How to modify a C program so that gprof can profile it?如何修改 C 程序以便 gprof 可以对其进行分析?
【发布时间】:2010-12-19 03:48:40
【问题描述】:

当我在我的 C 程序上运行 gprof 时,它说我的程序没有累积时间,并且所有函数调用都显示 0 时间。但是它确实计算了函数调用。

如何修改我的程序,以便 gprof 能够计算某项运行所需的时间?

【问题讨论】:

  • 你的程序真的消耗CPU时间吗?你是在 Linux 上运行它还是在 cygwin 上运行它?
  • 是的,该程序需要一段时间才能完成。我尝试在 Linux 和 Cygwin 上运行它。

标签: c linux profiling profiler gprof


【解决方案1】:

编译的时候指定-pg了吗?

http://sourceware.org/binutils/docs-2.20/gprof/Compiling.html#Compiling

编译完成后,您运行程序,然后在二进制文件上运行 gprof。

例如:

test.c:

#include <stdio.h>

int main ()
{
    int i;
    for (i = 0; i < 10000; i++) {
        printf ("%d\n", i);
    }
    return 0;
}

编译为cc -pg test.c,然后运行为a.out,然后gprof a.out,给我

粒度:每个样本命中覆盖 4 个字节,时间为 0.03 秒的 1.47% % 累计自我自我总计 时间 秒 秒 呼叫 ms/呼叫 ms/呼叫名称 45.6 0.02 0.02 10000 0.00 0.00 __sys_write [10] 45.6 0.03 0.02 0 100.00% .mcount (26) 2.9 0.03 0.00 20000 0.00 0.00 __sfvwrite [6] 1.5 0.03 0.00 20000 0.00 0.00 内存 [11] 1.5 0.03 0.00 10000 0.00 0.00 __ultoa [12] 1.5 0.03 0.00 10000 0.00 0.00 _swrite [9] 1.5 0.03 0.00 10000 0.00 0.00 vfprintf [2]

你得到了什么?

【讨论】:

  • @Phenom:在这种情况下,根据您选择分享的内容,我没有任何建议。您需要告诉我们的不仅仅是它是一个 C 程序,使用 -pg 编译,并且您得到函数计数但没有 CPU 时间。你确定你是在消耗 CPU 时间,而不是通过 I/O 调用运行挂钟时间吗?
【解决方案2】:

我尝试运行 Kinopiko 的示例,但我将迭代次数增加了 100 倍。

test.c:

#include <stdio.h>

int main ()
{
    int i;
    for (i = 0; i < 1000000; i++) {
        printf ("%d\n", i);
    }
    return 0;
}

然后我取了10个stackshots(在VC下,不过可以用pstack)。以下是堆栈截图:

9 copies of this stack:
NTDLL! 7c90e514()
KERNEL32! 7c81cbfe()
KERNEL32! 7c81cc75()
KERNEL32! 7c81cc89()
_write() line 168 + 57 bytes
_flush() line 162 + 23 bytes
_ftbuf() line 171 + 9 bytes
printf() line 62 + 14 bytes
main() line 7 + 14 bytes
mainCRTStartup() line 206 + 25 bytes
KERNEL32! 7c817077()

1 copy of this stack:
KERNEL32! 7c81cb96()
KERNEL32! 7c81cc75()
KERNEL32! 7c81cc89()
_write() line 168 + 57 bytes
_flush() line 162 + 23 bytes
_ftbuf() line 171 + 9 bytes
printf() line 62 + 14 bytes
main() line 7 + 14 bytes
mainCRTStartup() line 206 + 25 bytes
KERNEL32! 7c817077()

如果不是很明显,这会告诉您:

mainCRTStartup() line 206 + 25 bytes Cost ~100% of the time
main() line 7 + 14 bytes             Cost ~100% of the time
printf() line 62 + 14 bytes          Cost ~100% of the time
_ftbuf() line 171 + 9 bytes          Cost ~100% of the time
_flush() line 162 + 23 bytes         Cost ~100% of the time
_write() line 168 + 57 bytes         Cost ~100% of the time

简而言之,作为第 7 行的 printf 的一部分,程序花费了大约 100% 的时间将输出缓冲区刷新到磁盘(或控制台)。

(我所说的“线路成本”的意思是 - 它是应该线路的请求所花费的总时间的一部分,这大致是包含它的样本的一部分。 如果可以使该行不占用任何时间,例如通过删除它、跳过它或将其工作传递给一个无限快的协处理器,那么该时间分数就是总时间将减少多少。因此,如果可以避免执行任何这些代码行,时间将缩短 95% 到 100%。如果您要问“递归呢?”,答案是 It Makes No Difference.)

现在,也许您想知道其他信息,例如在循环中花费了多少时间。要找出答案,请删除 printf,因为它一直在占用。也许您想知道有多少时间纯粹花在 CPU 时间上,而不是花在系统调用上。要做到这一点,只需丢弃所有未在您的代码中结束的堆栈快照。

我想说的是,如果您正在寻找可以修复的东西以使代码运行得更快,那么即使您理解,gprof 为您提供的数据也差不多无用。相比之下,如果您的某些代码导致花费的挂钟时间超出您的预期,则堆栈快照会查明它。

【讨论】:

    【解决方案3】:

    gprof 的一个问题:它不适用于动态链接库中的代码。为此,您需要使用sprof。看到这个答案:gprof : How to generate call graph for functions in shared library that is linked to main program

    【讨论】:

      【解决方案4】:

      首先使用-g 编译您的应用程序,然后检查您使用的CPU 计数器。 如果您的应用程序运行得非常快,则 gprof 可能会错过所有事件或所需事件更少(减少要读取的事件数量)。

      实际上,分析应该向您显示CPU_CLK_UNHALTEDINST_RETIRED 事件,而无需任何特殊开关。但是有了这样的数据,你只能说你的代码执行得有多好:INST_RETIRED/CPU_CLK_UNHALTED。

      尝试使用英特尔 VTune 分析器 - 它可免费使用 30 天并用于教育。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-04-23
        • 1970-01-01
        • 2010-09-23
        • 2015-06-17
        • 2014-01-23
        • 1970-01-01
        相关资源
        最近更新 更多