如何使用 Dtrace 计算任意 C 语句之间的时间

Posted

技术标签:

【中文标题】如何使用 Dtrace 计算任意 C 语句之间的时间【英文标题】:How can I use Dtrace to calculate the time taken between arbitrary C statements 【发布时间】:2018-12-25 12:21:39 【问题描述】:

我正在使用 ImageMagick(通过 php imagick 扩展)生成一个简单的 gif 动画,就像这个。

我发现WriteGIFImage()(https://github.com/ImageMagick/ImageMagick/blob/c807b69de68a33b42fc8725486d5ac81688afd16/coders/gif.c#L1506) 函数按照 D 脚本写入 gif 数据需要很长时间。

pid$target::WriteGIFImage:entry

    self->start_WriteGIFImage = timestamp;
    printf("     -> WriteGIFImage\n");


pid$target::WriteGIFImage:return

    this->delta = (timestamp - self->start_WriteGIFImage) / 1000 / 1000;
    @deltas["WriteGIFImage"] = sum(this->delta);
    printf("     <- WriteGIFImage elapsed %d ms\n", this->delta);


// Output
ImagesToBlob
 -> WriteImage
     -> WriteGIFImage
     <- WriteGIFImage elapsed 821 ms
 <- WriteImage elapsed 821 ms
ImagesToBlob elapsed 821 ms

Total (ms):
  RelinquishMagickMemory                                            0
  WriteBlobByte                                                     0
  ImagesToBlob                                                    821
  WriteGIFImage                                                   821
  WriteImage                                                      821

WriteGIFImage() 是一个很大的函数,我想知道 2 个语句之间花费的时间,以便找到最慢的代码块。例如我怀疑这个 for 循环需要很长时间,所以我需要 Dtrace 告诉我第 1673 行和第 1678 行之间的时间差异。如何使用 D 脚本来完成它?

1673    for (i=0; i < (ssize_t) image->colors; i++)
1674    
1675      *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red));
1676      *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green));
1677      *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue));
1678    

顺便说一句,我发现ScaleQuantumToChar()ClampToQuantum() 都是inline 函数,而pid*::ScaleQuantumToChar:entry/return 探针无法工作。如何用 D 跟踪内联函数?

【问题讨论】:

强烈建议使用调用clock()来获取需要测量时间的两个点的当前CPU时间,那么经过的时间是ValueReturnedFromSecondCallToClock - ValueReturnedFromFirstCallToClock。您可以将结果除以 CLOCKS_PER_SECOND 以获得(更具可读性)经过的秒数 【参考方案1】:

除了entryreturn 探测器之外,pid 提供程序还具有针对每个指令偏移量的探测器。如果您执行sudo dtrace -l -n 'pid$target::WriteGIFImage:*' -p &lt;pid&gt;,它将列出它们。然后,您必须反汇编代码以确定哪个偏移量对应于哪一行代码。而且,当一个程序是在打开优化的情况下构建的,这种对应关系可能不干净。 (相对于代码行,指令可能是乱序的。)

您还可以定义自己的用户定义的静态跟踪 (USDT) 提供程序,并使用它们检测您的代码。 dtrace 手册页解释了如何操作。

尽管如此,DTrace 可能不是最好的工具。使用 Instruments 的 Time Profiler 模板,它会告诉您程序将时间花在哪里,一直到行(甚至是指令)。

【讨论】:

以上是关于如何使用 Dtrace 计算任意 C 语句之间的时间的主要内容,如果未能解决你的问题,请参考以下文章

Dtrace 中的局部变量

c语言中应用switch语句编程:输入1-7之间的任意数字,程序按照用户的输入输出相应的星期值!!

使用 dtrace 分析 C 代码

用 C 编写一个 DTrace 消费者

从 DTrace 脚本调用 C 函数

当包是最新的时,如何修复具有任意文件覆盖高漏洞的 NPM 包 Tar?