已经看到类似的问题,但它们与缓存未命中或代码重新排序有关。我的案子里没有这种事。
代码非常简单:
#include <stdio.h>
#include <time.h>
void main()
{
unsigned char a, b;
int i;
clock_t before = clock();
for (i = 0; i < 10000000; i++) {
a *= 2;
b *= 2;
}
printf("elapsed: %lu\n", clock() - before);
before = clock();
for (i = 0; i < 10000000; i++) {
a *= 2;
a *= 2;
}
printf("elapsed: %lu\n", clock() - before);
}
所以有两个变量a
和b
,我对它们做了一些事情(做什么并不重要)。第一个循环修改a
和b
,第二个循环只修改a
。也可以是b
,没关系。
第二个循环大约需要两倍的时间。a *= 2
和b *= 2
的装配线如下所示:
sal BYTE PTR -1[rbp]
sal BYTE PTR -2[rbp]
对于第二个循环,它们看起来像这样:
sal BYTE PTR -2[rbp]
sal BYTE PTR -2[rbp]
正如您所看到的,操作的数量是相同的,操作是相同的,内存访问是相同的,并且不可能有缓存未命中。唯一的区别是-1[rbp]
和-2[rbp]
。
为什么第二个循环需要两倍的时间?我只能猜测,它在某种程度上与在两个连续的操作中访问同一个var有关。我可以想象,第一个操作需要一些时间才能完成,然后第二个操作才能访问同一个var。而在第一个循环中,第一个操作是在一个var上执行的,第二个操作是在另一个var上执行的,所以它们是独立的,不必互相等待。但这应该意味着CPU级别上的一些微并行。是真的吗?
您也可以在这里在线运行该程序:https://onlinegdb.com/27qixKsWP
1条答案
按热度按时间gcuhipw91#
第一个循环可以是流水线的,因为这两个指令在不同的存储器位置上操作。这两个乘法可以同时进行。
第二个循环在相同的内存位置上运行,所以第二个乘法必须等待第一个乘法完成。