测量选定循环的执行时间

Posted

技术标签:

【中文标题】测量选定循环的执行时间【英文标题】:Measuring execution time of selected loops 【发布时间】:2010-04-29 18:43:07 【问题描述】:

我想测量 C 程序中选定循环的运行时间,以便查看在这些循环中花费了执行程序(在 linux 上)的总时间的百分比。我应该能够指定应该测量性能的循环。在过去的几天里,我尝试了几种工具(vtune、hpctoolkit、oprofile),但似乎没有一个能做到这一点。他们都发现了性能瓶颈,并只是展示了那些时间。那是因为这些工具只存储高于阈值(~1ms)的时间。因此,如果一个循环花费的时间少于此时间,则不会报告其执行时间。

gprof 的基本块计数功能依赖于旧编译器中现在不支持的功能。

我可以使用gettimeofday 或类似的东西手动编写一个简单的计时器,但在某些情况下它不会给出准确的结果。例如:

for (i = 0; i < 1000; ++i)

    for (j  = 0; j < N; ++j)
    
        //do some work here
    

现在我想测量在内部循环中花费的总时间,我必须在第一个循环中调用gettimeofday。所以gettimeofday 本身会被调用 1000 次,这会引入自己的开销,结果会不准确。

【问题讨论】:

人们经常问如何测量时间,而他们真正想要的是知道如何减少时间。这就是你所追求的吗? 不。我只是想测量时间。我正在根据一些模式来描述程序中的循环,我想知道它们相对于整个程序的执行时间。 【参考方案1】:

除非您的 CPU 周围有电路内仿真器或分线盒,否则不存在对单循环或单指令进行计时这样的事情。您需要将您的测试运行扩大到每个至少需要几秒钟的时间,以减少由于 CPU、操作系统等中发生的其他事情而导致的错误。

如果您想准确了解特定循环执行所需的时间,并且执行时间不到 1 秒,您将需要人为地增加迭代次数以按顺序进行得到一个高于“本底噪声”的数字。然后,您可以将该数字除以人为夸大的迭代次数,得到一个数字,该数字表示通过目标循环需要多长时间。

如果您想比较不同循环样式或技术的性能,同样的道理也成立:您需要增加迭代次数或通过测试代码才能获得测量结果你感兴趣的东西支配着你测量的时间片。

无论您是使用 CPU 提供的亚毫秒高性能计数器、系统日期时间时钟还是挂钟来测量测试经过的时间,这都是正确的。

否则,您只是在测量白噪声。

【讨论】:

【参考方案2】:

通常,如果您想测量在内部循环中花费的时间,您会将时间 get 例程放在外部循环之外,然后除以(外部)循环计数。如果您希望任何j 的内部循环的时间相对恒定,那就是。

任何分析指令都会产生它们自己的开销,但无论插入到哪里,开销都可能相同,因此“一切都在洗礼”。大概您正在寻找两个比较进程的运行时之间存在相当大差异的地方,这样的一对函数调用不会成为问题(因为您也需要一个在“结束”处,以获得时间delta),因为一个例程的成本将是另一个例程的 2 倍或更多。

大多数平台也提供某种更高分辨率的计时器,尽管我们在这里使用的计时器隐藏在 API 后面,因此“客户端”代码是跨平台的。我敢肯定,只要稍微看一下,您就可以打开它。尽管即使在这里,您获得优于 1 毫秒的准确度的可能性也很小,因此最好连续运行代码多次并为整个运行计时(然后除以循环计数,natch)。

【讨论】:

【参考方案3】:

我很高兴您正在寻找百分比,因为这很容易获得。让它运行。如果它运行得很快,请在它周围放置一个外循环,这样它会花费很长时间。这不会影响百分比。在它运行时,获取stackshots。您可以使用 gdb 中的 Ctrl-Break 来执行此操作,也可以使用 pstacklsstack。只需看看有多少百分比的堆栈快照显示了您关心的代码。

假设循环需要一小部分时间,例如 0.2 (20%),并且您需要 N=20 个样本。那么应该显示它们的样本数将平均为 20 * 0.2 = 4,并且样本数的标准差将为 sqrt(20 * 0.2 * 0.8) = sqrt(3.2) = 1.8,所以如果你想要更高的精度,采集更多样本。 (我个人认为精度被高估了。)

【讨论】:

以上是关于测量选定循环的执行时间的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中测量 DispatchQueue 并发异步中的代码块执行时间?

循环内的 Java 执行时间峰值

SwiftUI:Firebase ForEach 列表执行编辑功能无法编辑选定的行项目

循环执行网络调用后,同一项目被删除两次

测量代码执行时间的“快速”方法

测量电子表格内置函数的执行时间