如何在C++中计算运算

How can I count operations in C++?

本文关键字:计算 运算 C++      更新时间:2023-10-16

如何计算C++中的操作?我想用一种比计时更好的方式来分析代码,因为时间通常四舍五入到0毫秒。

如果您是计时代码,那么值得在循环中多次运行它,以避免计时器分辨率的影响。因此,您可能会将计时的东西运行10000次,并测量运行所有迭代所需的时间。它可能只需要几秒钟的运行时间,你就会得到更好的计时数据。

在考虑性能时,使用"操作数"是个坏主意。它没有考虑每个操作的最佳情况/最坏情况循环计数之间的差异、缓存未命中、管道未命中、潜在(自动)并行化等成本。

正如Greg所说,通常情况下,微基准测试最好只运行相同的代码足够多的时间来获得一段合理的时间。

更好的做法是用实际的工作负载运行整个应用程序,并衡量您真正感兴趣的指标,但这是另一回事。。。

当然有用的是计算代码的复杂性-知道一个方法何时为O(1)、O(logn)、O。(乔尔关于画家Shlemiel和strlen的故事是最明显的例子。)

这里的示例分析器是一个不错的选择。在Windows上,可以使用Visual Studio中内置的探查器,也可以使用Windows组织中的xperf工具。xperf工具是免费的。以下是我自己关于xperf工具的一系列帖子。这是关于评测的。

您可以通过读取CPU的时间戳计数器(tsc)来进行精确测量,该计数器在每个CPU时钟上递增一。

不幸的是,读取是在代码中内联一些汇编指令完成的。根据底层架构的不同,读取成本在~11(AMD)到~33(Intel)之间变化tsc。有了1Ghz的CPU,您几乎可以拥有纳秒级的精度。

为了对代码段进行可靠和非侵入性的测量,您可以:

  • 通过禁用cpu功能(如AMD cool'n pitalIntel SpeedStep)来防止cpu缩放频率
  • 重复测试几次,收集数组中的测量值,然后将数据保存到文件中进行离线分析
  • 为测试中的进程选择实时调度策略,如SHED_RRSHED_FIFO。实时策略减少了被测试进程和其他被阻止的正常进程/内核线程之间的上下文切换次数
  • 通过mlockall()系统调用将进程的所有虚拟地址空间锁定在RAM中

在这里,您可以找到我为Linux编写的一个准可移植C++类,该类源自Linux内核,设计用于读取i386、x86_64和ia64体系结构的tsc。

生成组装和计数操作。然后查看处理器使用的周期/op然后请记住,您正在使用先发制人的操作系统,但这些都无效。

更严重的是,抬高你的n并将你的程序扩展到淫秽的大小。这将让你了解你的程序速度。

在Linux上使用valgrind。它具有指令级计时,包括缓存分析。

如果您希望实际的操作计数来自硬件,那么您可能需要考虑安装PAPI-Performance API这样的软件包,该软件包适用于许多不同的操作系统和处理器组合。它使用实际的硬件计数器,并报告许多不同性能指标的直接或派生值,如Total Ops、FLOPS、缓存命中/未命中等。它还可以访问更高分辨率的计时器。

这不是有史以来最简单的软件包,但报告级别确实可以帮助您分析硬件上应用程序的行为。

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

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

知道一个函数被调用的次数是有用的,因为如果一个函数的调用频率远高于你认为的频率,它可以让你发现潜在的性能问题

当然,使用探查器会使代码变慢,但在添加任何类型的检测时,这是不可避免的。

如果你想在不使用探查器的情况下(在windows上)精确计时,你可以看看这个线程,它提供了分析C++代码的不同方法。

如果您担心让程序运行得尽可能快,而且它是单线程的,并且您使用的是IDE,请查看:如何优化程序的性能