在相同的 C 代码中,对相同作用域内相同类型的变量进行相同的操作所花费的时间不同

And*_*nko 3 c optimization performance

见过类似的问题,但它们与缓存未命中或代码重新排序有关。在我的例子中,这些都没有发生。

代码很简单:

#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);
}
Run Code Online (Sandbox Code Playgroud)

所以有两个变量ab,我用它们做一些事情(做什么并不重要)。第一个循环修改ab,第二个循环a仅修改 。只能是b也好,无所谓。

第二个循环大约花费两倍的时间。

a *= 2和的装配线b *= 2如下所示:

    sal BYTE PTR -1[rbp]
    sal BYTE PTR -2[rbp]
Run Code Online (Sandbox Code Playgroud)

对于第二个循环,它们看起来像这样:

    sal BYTE PTR -2[rbp]
    sal BYTE PTR -2[rbp]
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,操作数量相同,操作相同,内存访问相同,并且不可能存在缓存未命中。唯一的区别在于-1[rbp]和之间-2[rbp]

那么为什么第二个循环需要两倍的时间呢?我只能猜测它与在两个连续操作中访问相同的变量有关。我可以想象,第一个操作需要一些时间才能完成,然后第二个操作才能访问相同的变量。而在第一个循环中,第一个操作是在一个 var 上执行的,第二个操作是在另一个 var 上执行的,因此它们是独立的,不必彼此等待。但这应该意味着 CPU 级别上的一些微并行性。真的吗?

您还可以在此处在线运行该程序: https: //onlinegdb.com/27qixKsWP

Bar*_*mar 5

第一个循环可以是流水线式的,因为两条指令在不同的内存位置上运行。两个乘法可以同时进行。

第二个循环在同一内存位置上运行,因此第二个乘法必须等待第一个乘法完成。

  • 我认为他们的意思是“在同一范围内具有相同类型的变量”。它们实际上不是相同的变量。 (2认同)