全局变量带来意想不到的表现

我使用全局变量得到了一个奇怪的结果。 这个问题受到另一个问题的启发。 在下面的代码中,如果我改变了

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 %.16en", 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 %.16en", dtime/100);
    return 0;
}

如果我将buff改为一个短指针,那么性能很快,并且不依赖于如果ncols是静态的,或者如果buff是自动的,则不变。 但是,当我使用buff作为int*指针时,我观察到与char*相同的效果。

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

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

但它没有区别。

这是我的问题

  • buffchar*指针或int*全局指针时,为什么当ncols具有文件范围或常量时代码更快?
  • 为什么buff是一个自动变量而不是全局或静态代码更快?
  • 为什么buff不是一个简短的指针?
  • 如果这是由于指针别名,为什么restrict没有明显的影响?
  • 请注意,我使用omp_get_wtime()仅仅是因为它便于计时。


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

    为什么代码更快?

    代码更快,因为它的热门部分func的循环已经通过自动矢量化进行了优化。 在使用static / const的合格ncols的情况下,的确,GCC发出:

    注意:向量化循环
    注意:为了增强对齐,矢量化循环去皮

    如果您打开-fopt-info-loop-fopt-info-vec或那些进一步-optimized组合,因为它具有相同的效果,这是可见的。


  • 为什么buff是一个自动变量而不是全局或静态代码更快?
  • 在这种情况下,GCC能够计算应用矢量化所需的直观迭代次数。 这也是由于buf的存储,如果没有另外指定,它是外部的。 整个矢量化会立即跳过,不像buff在本地进行并成功。

  • 为什么buff不是一个简短的指针?
  • 为什么要这样? func接受一个char* ,它可以替代任何东西。

  • 如果这是由于指针别名,为什么限制没有明显的影响?
  • 我不认为,因为GCC在调用func时可以看到它们没有别名:不需要restrict


    一个const很可能会一直产生更快或等同快速的代码作为读/写变量,因为编译器知道变量将不会改变,这又使得一大堆的优化选项。

    声明一个文件范围变量intstatic int不应该影响性能,因为它仍然会被分配在相同的地方: .data节。

    但正如在注释中提到的那样,如果变量是全局变量,编译器可能不得不假定某个其他文件(翻译单元)可能会修改它并因此阻止某些优化。 我想这是发生了什么。

    但是这不应该成为任何关注的问题,因为从来没有理由在C语言中声明全局变量。 总是声明它们是static以防止该变量被滥用以进行意大利面条编码。

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

    链接地址: http://www.djcxy.com/p/27029.html

    上一篇: Unexpected performance with global variables

    下一篇: change url while scrolling