如何在C++中计算操作次数?

5

我如何在C++中计算操作次数?我想以比仅计时更好的方式分析代码,因为时间经常被舍入为0毫秒。


请说明“计数操作”是什么意思。有一些工具可以分析代码中的函数调用,例如性能分析器,但您也可以通过添加适当的开关来查看生成的汇编代码。 - friol
11个回答

7

如果你在计时代码,最好在循环中多次运行它,以避免计时器分辨率的影响。因此,你可以运行你要计时的东西10,000次,并测量运行所有迭代所需的时间。这可能只需要几秒钟就能完成,并且你将获得更好的计时数据。


1
唯一的困难在于基准测试会彻底加热“高速缓存”,而代码通常在冷启动状态下运行。但是测量冷缓存性能很困难。 - Jonathan Leffler
是的,除非您正在测量缓存本身的性能,否则您需要禁用缓存以进行正确的性能测试。 - Greg Hewgill
禁用CPU缓存会导致另一个方向上的误导性结果吗?现在你不知道何时通过缓存命中获得性能增益。 - Steve Jessop
哦,我并不是建议禁用CPU缓存。我在想的是应用程序级别的缓存之类的东西。 - Greg Hewgill

5
使用“操作次数”来考虑性能是一个糟糕的想法。它没有考虑到每个操作最佳/最差情况下的循环计数之间的差异,缓存未命中的成本,流水线未命中,潜在(自动)并行化等因素。
正如Greg所说,通常微基准测试更好的方法是运行相同的代码足够多次以获得合理的时间跨度。
更好的方法是使用真实工作负载运行整个应用程序,并测量您真正感兴趣的指标,但这是另一回事...
确定代码的复杂度肯定是有用的——知道何时一个方法将是O(1),O(log n),O(n)等等。通常这不涉及了解C++中各个指令的细节——尽管您确实需要知道调用的任何内容的复杂度。(Joel关于Shlemiel the Painter和strlen的故事就是最明显的例子。)

4

3
生成汇编并计算操作次数。然后查看处理器使用的每个周期/操作数。然后,请记住您正在使用一种抢占式操作系统,因此所有这些都无效。
更加严肃地说,增加您的“n”值并将程序扩展到庞大的规模。这将给您一个关于程序速度的想法。

3
在Linux上使用valgrind。它具有指令级别的时间跟踪功能,包括缓存分析。

3
您可以通过读取CPU的时间戳计数器(tsc)进行精确测量,每次CPU时钟都会增加一次。不幸的是,这个读取过程会在代码中内联一些汇编指令。根据底层架构的不同,读取成本在 ~11(AMD) 和 ~33(Intel) tsc 之间变化。配合1 Ghz CPU,您可以实现纳秒级别的精度。
为了对代码段进行可靠且非侵入性的测量,您可以:
  • 通过禁用CPU功能(例如AMD cool'n quiteIntel SpeedStep)来防止CPU缩放频率。
  • 多次重复测试,将测量结果收集到数组中,然后将数据保存到文件以进行脱机分析。
  • 为测试下面的流程选择实时调度策略,例如SHED_RRSHED_FIFO。实时策略可以减少被阻塞的进程和其他正常进程/内核线程之间的上下文切换次数。
  • 通过mlockall()系统调用将所有进程的虚拟地址空间锁定在RAM中。

这里 你可以找到一个我为Linux编写的准便携式C++类,它源自Linux内核,旨在读取i386、x86_64和ia64架构的tsc。


TSC有时可能不可靠,特别是在多核系统中。更多详情请参见http://en.wikipedia.org/wiki/Time_Stamp_Counter。 - Adam Rosenfield

2
如果您想要从硬件中获得实际的操作计数,那么您可能需要考虑安装类似于PAPI的软件包 - Performance API - 它可以在许多不同的操作系统和处理器组合上使用。它使用实际的硬件计数器,并报告许多不同性能指标的直接或派生值,例如总操作数、FLOPS、高速缓存命中/未命中等。它还可以提供更高分辨率的定时器。

这并不是最简单的软件包,但是它的报告水平确实可以帮助您分析应用程序在硬件上的行为。


0

使用更高分辨率的计时器。


0

为什么不在分析器下运行代码呢?这通常会提供有关函数中花费的时间以及调用次数的数据。

知道函数被调用的次数很有用,因为如果一个函数被调用的次数比您认为应该多得多,它可能会导致潜在的性能问题。

当然,在使用分析器时会使您的代码变慢,但是在添加任何类型的工具时都无法避免这种情况。


0

如果你想在Windows上精确计时(而不使用分析器),可以查看this thread,其中介绍了不同的C++代码分析方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接