有没有一种快速/简单的方法可以做到这一点(至少是粗略估计)?
我是标杆算法,我认为知道我的计算机执行指令的绝对速度,并将它与我的渐近分析相比较是很酷的。
- 型你有什么想法(为什么C/C++)?为什么不组装?)
- 型生成程序集文件并对指令进行计数。然后对同一个文件进行性能度量。
- 型如果您对"每秒指令"感兴趣,请查看您的时钟速度,计算出体系结构上每个指令的平均周期数,然后进行除法。否则,您需要一个更有意义的、不太实际的度量标准。
- 型不,真的没有(一个简单的方法)。问题相当简单:计算机可以执行的指令数量很大程度上取决于这些指令的混合和顺序。得到一个结果,这意味着任何事情通常都涉及到一些著名基准的结果——但是有意义的基准通常相当复杂。即便如此,你也必须小心——这些数字通常意味着低于预期。
- 型"如何实现每周期4次故障"涵盖了达到峰值性能,可作为性能评估基准。
- 型@杰里科芬:更不用说缓存的效果了。最接近"粗略估计"的是一组已知的基准,如Whetstone/Dhrystone。
- 型@根据1970年英国国家物理实验室收集的统计数据,磨刀石基准最初是用algol编写的,但仅使用四元素数组来测试数组访问。然后被翻译成Fortran。Dhrystone是基于相似的原则,用不同的语言,用Ada写的,但翻译成了C。我认为Whetstone在30年前第一次研究它时过时了,不现实。
- 型@帕特里夏:有人一直在浏览维基百科…不管旧与否,现实与否,它仍然存在于现代CPU基准测试应用程序中(一个快速的网络搜索显示了SisoftSandra的例子)。您可能会感到惊讶,但是30年后,4元素数组仍然被广泛使用;我们甚至围绕这一点设计了整个体系结构扩展。年纪大,仍在使用,就可以称为"已知"。
- 型@Danielko的观点是,四个元素数组和访问它们的循环可以以不适用于较大数组的方式进行优化,而这四个元素是Whetstone中唯一的数组大小。虽然我查了维基百科的日期,但我早在维基百科存在之前就知道了磨刀石的历史。
- 型这个30年的基准仍然被广泛使用,因此它是最接近"粗略估计"的基准。我是否错过了一条重要的信息,使这个结论看起来合乎逻辑?:)
- 型如果您使用原始的Dhrystone基准测试并使用gcc-o3编译它(几年前),您会得到一些幻想的数字,因为(至少)其中一个循环会变成空的,因此需要零时间。每秒指令数是指指令数/时间->无限个数。但是Benchmar的总数并不是零,时间,所以你最终会得到一些幻想的数字,在100-1000倍的处理器理论上。有一些技巧可以让编译器相信您需要循环内的代码,但这不再是原始源代码了。此外,Drhystone基于VAX指令。
- 型@JALF的受欢迎程度不足以作为一个基准来使用,即使是作为一个"粗略的估计"。我宁愿选择任何使用一个或多个实际内核的基准,比如一个规范基准。虽然获取代码的成本很高,但是网站对许多系统都有结果。或者使用像linpack1000这样简单的东西。求解1000个线性方程组是一项有意义的任务。用户自己的代码是衡量每秒用户代码指令的最佳基准。
如果你想知道你的CPU能做什么,那么看看文档。CPU供应商指定所有指令的延迟和吞吐量,以及各种其他信息(每个周期可以发出或收回多少指令、缓存延迟等)。基于此,您可以计算理论峰值吞吐量。
如果你想做你的CPU实际正在做的,那么运行你自己的代码并测量它的性能。
然而,请记住,现代CPU是非常复杂的,它们的性能取决于各种各样的因素,而且您很少能够接近最大限度地利用您的CPU,并且理解为什么或什么阻碍了您的代码需要对硬件有一个相当透彻的了解。(我通常的经验法则是,如果理论峰值持续下跌30-40%,你会做得很好)
- + 1。简单而真实。
- 或者只是让内核给你一些冒牌货。它至少和任何理论(即,与任何上下文无关)估计一样有用。
- @除了"文档所说的"与任何上下文都很难"断开"。这是关于你的CPU如何工作和它能做什么的很难的事实信息,如果你试图使你的代码运行良好,这是相当相关的。但是,如果你只是想要一个快速的估计,忽略了很多细微的差别,那么这个数字可能是一个很好的候选人。
- @JALF:指令并不是独立执行的,因此即使对每个指令的执行方式进行了全面的描述,也几乎看不到执行过程中实际会发生什么。缓存未命中、分支预测失误、数据依赖性等,这是我提到的上下文的一部分。
- 丹尼尔科:是的。这与我的回答没有任何矛盾,是吗?但是,如果您想知道CPU能够提供最佳代码的最大理论吞吐量,那么您假设没有缓存未命中、分支预测失误或数据依赖性。所有这些都有助于解释为什么您的代码比理论上的最大值慢得多,这就是全部要点。
这是一个典型的"理论上、理论上和实践上是一样的,实践上却不是"。
现代的CPU有非常复杂的逻辑,这意味着实际执行的操作数量不同于你仅仅看代码或思考问题时的想法(除非你有一个小星球大小的大脑,并且知道特定的CPU是如何工作的)。例如,处理器可能会推测性地在分支的一个或另一个端执行指令,即使它还没有完全到达分支——如果这是"错误的"端,那么它将丢弃这些指令的结果——当然,执行它们需要时间。
指令执行顺序也不正常,这意味着很难准确预测何时执行哪个指令。也有一些例外。
如果您同时通过所有可用的执行单元推送数据和指令,您将只能(接近)获得理论吞吐量——这意味着拥有正确的指令组合,当然还有缓存中的所有代码和数据。
因此,从理论上讲,我们可以通过编写非常聪明的代码,让处理器充满可以使其最大化的指令。实际上,这很快就变成了一项艰巨的任务。
然而,问题在于如何测量指令的吞吐量,而在现代CPU上,使用正确的额外软件是非常可能的。在LinuxPerftool或Oprofile上,对于Windows,有英特尔的vtune和AMD的代码分析师。这些将允许您(受限于足够的特权)获取处理器中的"性能计数器",它具有"指令数"、"浮点运算数"、"缓存未命中数"、"分支预测失误"和许多其他处理器性能度量的计数器。因此,如果有足够长的运行时间(至少几秒钟,最好更长),您可以测量处理器执行的实际计数或时钟周期。
- "……"它转动得非常快。",我们能连接一个发电机并把它用作能源吗?
- @丹妮尔科:添加了缺失的单词…
- 为了"理论上的乐趣";在现代CPU(如Intel Nehalem和更高版本,使用"循环流检测器")上,我考虑尝试使用一个包含单字节NOP指令的循环(这样,指令就被前端丢弃,而不是被放到微操作缓冲区)。我猜这样你可能会超过"理论上每周期100条指令"。
- @布兰登:不,英特尔的CPU至少在整个生产线上都运行着NOP。它们在rob中占了一个位置,但在rs中为零(未使用的域:不需要执行单元)。这对SNB家族来说是绝对正确的,但我还没有测试过Nehalem。在发行前将它们丢弃到后端可能是可行的,但这不是一个非常有价值的优化。可能不值得在nops之后的第一条指令从一个不是前一条指令结束的rip开始,没有跳转。此外,"指令"的性能计数器也会出错。(但不是交易中断。)
在目前的实践中,指令的有效数量主要取决于内存延迟,这是性能的主要瓶颈。等待数据不好。处理器可以通过缓存、流水线和并发等技术稍微缓解这个问题,但是问题仍然存在,并且随着时间的推移只会变得更糟。
正确的实现可以产生巨大的差异。您可能想看看关于缓存友好代码的这个问题。
您可以在Linux中使用性能工具。它很容易使用。
要获取有关CPU周期、每个周期的指令(IPC)、缓存命中/未命中等的统计信息,只需使用perf运行程序。示例命令是
性能统计-d 。
有关详细信息,请访问http://www.brendangregg.com/perf.html或https://perf.wiki.kernel.org/index.php/tutorial。
现代的CPU都是流水线指令处理,因此没有常量。
但是,您可以在算法开始和结束时读取CPU计时周期数。我认为这是最低水平,你可以得到这样的测量。
http://en.wikipedia.org/wiki/time_stamp_counter网站
注意:这里有很多问题,为什么这不能100%准确,我可以说很少,但我相信社区将能够添加到列表中:-操作系统先发制人-缓存未命中(algo第一次运行速度较慢,如果随后运行则更快)-在较旧的CPU上,CPU计时周期与CPU频率无关。
- 除非(实际上)机器上没有其他任何东西在运行,否则这通常根本就不是很准确。时间戳计数器对于在单个时间片中运行的非常短的代码段很有用。对于一个完整的程序来说,从操作系统(如Linux上的times或Windows上的GetProcessTimes)获得时间通常更有意义。
- 在UNIX系统上,EDCOX1×2是最好的方式,因为您可以指定如何测量所测量的时间(如果您真的想要它,它甚至可以映射到RDTSC);C++ 11或多或少将其合并到EDCOX1×3中。