我使用全局变量得到一个奇怪的结果。这个问题的灵感来自另一个问题。在下面的代码中,如果我更改
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
是自动变量(即不是global
或static
(,我也得到相同的结果。我的意思是:
//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)
但这没有什么区别。
这是我的问题
- 当
buff
是char*
指针或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
很可能总是产生更快或同样快的代码作为读/写变量,因为编译器知道变量不会被更改,这反过来又启用了大量的优化选项。
声明文件范围变量int
或static int
应该不会对性能产生太大影响,因为它仍将分配给同一位置:.data
部分。
但如注释中所述,如果变量是全局变量,编译器可能必须假设其他文件(翻译单元(可能会修改它,从而阻止某些优化。我想这就是正在发生的事情。
但无论如何,这不应该引起任何关注,因为永远没有理由在 C, period 中声明全局变量。始终将它们声明为 static
,以防止变量被滥用于意大利面条编码目的。
总的来说,我也会质疑你的基准测试结果。在Windows中,您应该使用QueryPerformanceCounter和类似功能。https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408%28v=vs.85%29.aspx