如何计算循环次数?

7
我想比较两个C语言小函数的优劣,一个使用循环加法,一个使用显式变量加法。这两个函数本身并不重要,但我希望有人能教我如何计算循环次数以便比较算法。因此,f1需要10个循环周期,而f2只需要8个。这是我想要做的推理方式。目前没有性能测量(例如gprof实验),只是简单的指令计数。

有没有好的方法来做到这一点?有工具或文档吗?我的代码是用gcc在x86架构上编译的。


2
你想要计算指令还是周期?这是两个不同的概念。 - Kevin
@Kevin:感谢你的澄清问题:我需要循环,以便比较性能。 - Dervin Thunk
探索性的。这只是我写论文时提出的纯理论问题。 - Dervin Thunk
2
@Dervin:你要找的不是Clicks这个术语,而是Cycles。Clicks是你用鼠标做的事情 ;) - Goz
8
不行了,你不能再这么做了。很久以前,每个汇编指令执行的时钟数是固定的,你可以把它们加起来以确定代码执行的速度。我很喜欢那种感觉 : - ) 但是现在,由于乱序执行、每个时钟多指令执行和多级缓存等问题,你无法单凭指令来计算执行速度。你必须要进行测量。对不起! - Bo Persson
显示剩余11条评论
9个回答

8

5
汇编指令rdtsc(读取时间戳计数器),将当前CPU自上次重置后的时钟周期计数以EDX:EAX寄存器返回。如果您的CPU运行速度为3GHz,则一个时钟周期为1/3GHz。
编辑: 在MS Windows下,API调用QueryPerformanceFrequency会返回每秒的时钟周期数。

@GJ:这并不是那么简单。现代处理器根据负载来调整速度,因此您永远不知道 CPU 在任何给定时刻的时钟速度。但它确实提供了周期数。 - Goz
@Goz:同意,但时钟计数应该是相同的。 - GJ.
1
@BlackBear:嗯,1/Hz = s。所以1/3GHz = 1/3G s。 - GJ.
@Blackbear:不是这样的。如果处理器已经降频到1Ghz……那么一个周期需要3倍的时间。再加上英特尔的i7 Turbo Boost,你会有更多的问题…… - Goz
@Goz:你没明白。@GJ明白了 :) - BlackBear

4
很遗憾,计时代码与目视计算指令和时钟周期一样容易出错。无论是调试器还是其他工具或重新编译代码并进行10000000次重新运行和计时等操作,都会改变缓存线中的事物位置、缓存命中和未命中的频率等。您可以通过在被测试代码模块上游添加或删除一些代码来缓解这种情况(从而导致添加和删除一些指令,改变程序和数据的对齐方式)。
通过经验,您可以通过查看反汇编代码(以及高级别代码)来培养性能方面的眼光。计时代码没有替代品,问题在于计时代码容易出错。经验来自于许多实验,并尝试充分理解为什么添加或删除一条指令没有或显著差异。为什么在受测试模块完全不相关的另一个区域添加或删除的代码会对受测试模块产生巨大的性能差异。

1
还要了解的是,处理器已不再是性能瓶颈,它经常会在等待内存和其他I/O时空闲。 - old_timer

2
如GJ在另一个答案中所写,我也建议使用“rdtsc”指令(而不是调用某些看起来正确的操作系统函数)。
我已经写了很多关于这个主题的答案。Rdtsc允许您计算代码在“自然”执行环境中经过的时钟周期,而不必求助于调用它一千万次,因为并非所有函数都是黑盒子。
如果您想计算经过的时间,您可能需要关闭CPU上的节能功能。如果只是时钟周期问题,则不需要这样做。

1

如果您想比较性能,最简单的方法是将您的算法放入循环中并运行1000或1000000次。

一旦您运行了足够多的次数以便看到小差异,请运行time ./my_program,这将给出它使用的处理器时间。

多做几次以获取样本并比较结果。

尝试计算指令对于x86架构没有帮助。这是因为不同的指令执行所需的时间可能会有显着差异。


1
我建议使用模拟器。看看PTLsim,它会给你循环次数,除此之外,也许你想看看一些工具来计算每个汇编行执行的次数。

0

使用 gcc -S your_program.c 命令。 -S 参数告诉 gcc 生成汇编代码清单,文件名为 your_program.s


没错,这就是我所做的:然后呢?手动计算点击次数会非常繁琐,至少可以这么说。 - Dervin Thunk
哦,抱歉,我误解了你的问题所在。我曾经使用过Simics工具(请参见http://en.wikipedia.org/wiki/Simics)来计算周期。这是一款商业产品,但如果你在大学里,你可能可以免费获得学术许可证。Simics提供了精确到周期的处理器模拟,并能够收集统计信息。 - ChrisJ

0

有很多高性能的时钟可用。QueryPerformanceCounter是微软的。一般的技巧是运行函数数万次并计算所需时间。然后将所花费的时间除以循环次数。你会发现每个循环所需的时间略有不同,因此通过多次测试才能真正找出所需时间。


0

这并不是一个简单的问题。让我试着解释一下:

在不同操作系统上有几个工具可以做到你想要的,但这些工具通常是更大环境的一部分。每个指令都会被翻译成一定数量的周期,这取决于编译器运行的 CPU 和程序执行的 CPU。

我无法给出明确的答案,因为我没有足够的数据来做出判断,但我在 IBM 数据库领域工作,我们使用工具来测量代码的周期和指令,这些跟踪仅对程序编译和运行的实际 CPU 有效。

根据您的 CPU 管道的内部结构和编译器的效率,生成的代码很可能仍然存在缓存未命中和其他需要关注的区域。(在这种情况下,您可能需要考虑 FDPR...)

如果您想知道您的程序在您的 CPU 上(使用您的编译器编译)需要多少个周期才能运行,您必须了解 CPU 的工作原理以及编译器如何生成代码。

很抱歉,如果答案对解决你手头的问题不够满意。你说你正在使用gcc在x86架构上。我建议你尝试将汇编代码映射到你的CPU上。 我相信你会发现一些地方,gcc可能做得更好...


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