在相同的C代码中,对同一作用域中具有相同类型的变量执行相同的操作需要不同的时间

ct3nt3jp  于 2023-10-16  发布在  其他
关注(0)|答案(1)|浏览(113)

已经看到类似的问题,但它们与缓存未命中或代码重新排序有关。我的案子里没有这种事。
代码非常简单:

#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);
}

所以有两个变量ab,我对它们做了一些事情(做什么并不重要)。第一个循环修改ab,第二个循环只修改a。也可以是b,没关系。
第二个循环大约需要两倍的时间。
a *= 2b *= 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

gcuhipw9

gcuhipw91#

第一个循环可以是流水线的,因为这两个指令在不同的存储器位置上操作。这两个乘法可以同时进行。
第二个循环在相同的内存位置上运行,所以第二个乘法必须等待第一个乘法完成。

相关问题