全局变量的意外性能

时间:2015-06-09 09:22:58

标签: c pointers gcc global-variables

我使用全局变量得到一个奇怪的结果。这个问题的灵感来自another question。如果我改变

,请在下面的代码中
int ncols = 4096;

static int ncols = 4096; 

const int ncols = 4096;

代码运行得更快,组装更简单。

//c99 -O3 -Wall -fopenmp foo.c
#include <stdlib.h>
#include <stdio.h>
#include <omp.h>

int nrows = 4096;
int ncols = 4096;
//static int ncols = 4096;
char* buff;

void func(char* pbuff, int * _nrows, int * _ncols) {
    for (int i=0; i<*_nrows; i++) {
        for (int j=0; j<*_ncols; j++) {
            *pbuff += 1;
            pbuff++;
        }
    }
}

int main(void) {
    buff = calloc(ncols*nrows, sizeof*buff);
    double dtime = -omp_get_wtime();
    for(int k=0; k<100; k++) func(buff, &nrows, &ncols);
    dtime += omp_get_wtime();
    printf("time %.16e\n", dtime/100);
    return 0;
}

如果char* buff是自动变量(即不是globalstatic),我也会得到相同的结果。我的意思是:

//c99 -O3 -Wall -fopenmp foo.c
#include <stdlib.h>
#include <stdio.h>
#include <omp.h>

int nrows = 4096;
int ncols = 4096;

void func(char* pbuff, int * _nrows, int * _ncols) {
    for (int i=0; i<*_nrows; i++) {
        for (int j=0; j<*_ncols; j++) {
            *pbuff += 1;
            pbuff++;
        }
    }
}

int main(void) {
    char* buff = calloc(ncols*nrows, sizeof*buff);
    double dtime = -omp_get_wtime();
    for(int k=0; k<100; k++) func(buff, &nrows, &ncols);
    dtime += omp_get_wtime();
    printf("time %.16e\n", dtime/100);
    return 0;
}

如果我将buff更改为短指针,那么性能很快,并且不依赖于ncols是静态还是buff是否为自动的常数。但是,当我buff int*指针时,我会发现与char*相同的效果。

我认为这可能是由于指针别名所以我也尝试了

void func(int * restrict pbuff, int * restrict _nrows, int * restirct _ncols)

但没有区别。

以下是我的问题

  1. buffchar*指针或int*全局指针时,为什么代码 ncols具有文件范围或是否恒定时更快?
  2. 为什么buff是自动变量而不是全局变量或静态变量使代码更快?
  3. 为什么buff是短指针时没有区别?
  4. 如果这是由于指针别名导致restrict为什么没有明显效果?
  5. 请注意,我使用omp_get_wtime()只是因为它方便了时间。

2 个答案:

答案 0 :(得分:2)

有些元素在编写时允许GCC在优化方面采取不同的行为;可能,我们看到的影响最大的优化是循环矢量化。因此,

  

为什么代码更快?

代码更快,因为它的热门部分func中的循环已经使用自动矢量化进行了优化。对于合格的ncols static / const,GCC确实会发出:

  

注意:循环矢量化   注意:循环去皮以进行矢量化以增强对齐

如果您打开-fopt-info-loop-fopt-info-vec或其他-optimized的组合,则可以看到

,因为它具有相同的效果。

  
      
  1. 为什么buff是自动变量而不是全局变量或静态变量   让代码更快?
  2.   

在这种情况下,GCC能够计算应用矢量化时直观需要的迭代次数。这又是由于buf的存储,如果没有另外指定则是外部的。立即跳过整个矢量化,不像buff是本地的,它继续并成功。

  
      
  1. 当buff是一个短指针时,为什么没有区别呢?
  2.   

为什么要这样? func接受一个char*,它可以包含任何内容。

  
      
  1. 如果这是由于指针别名,为什么限制没有明显效果?
  2.   

我不这么认为,因为GCC在调用func时可以看到他们没有别名:restrict不是必需的。

答案 1 :(得分:1)

const很可能总是产生更快或同样快速的代码作为读/写变量,因为编译器知道变量不会被更改,这反过来又会产生大量的优化选项。

声明文件范围变量intstatic int不应该对性能产生太大影响,因为它仍然会在同一个地方分配:.data部分。

但正如评论中所提到的,如果变量是全局变量,则编译器可能必须假设某些其他文件(转换单元)可能会对其进行修改,从而阻止某些优化。我想这就是发生的事情。

但无论如何这不应该是任何问题,因为在C,period中永远没有理由声明一个全局变量。始终将它们声明为static,以防止变量因意大利面编码而被滥用。

总的来说,我也会质疑你的基准测试结果。在Windows中,您应该使用QueryPerformanceCounter和类似的。 https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408%28v=vs.85%29.aspx