【发布时间】:2014-01-21 09:13:48
【问题描述】:
C++ 向量和普通数组之间的性能差异已被广泛讨论,例如here 和here。通常讨论会得出结论,当使用[] 运算符访问并且编译器启用内联函数时,向量和数组在性能方面是相似的。这就是为什么预期的原因,但我遇到了一个似乎不正确的案例。下面几行的功能非常简单:获取一个 3D 体积,然后交换并应用某种 3D 小蒙版一定次数。根据 VERSION 宏,卷将被声明为向量并通过 at 运算符 (VERSION=2) 访问,声明为向量并通过 [] (VERSION=1) 访问或声明为简单数组。
#include <vector>
#define NX 100
#define NY 100
#define NZ 100
#define H 1
#define C0 1.5f
#define C1 0.25f
#define T 3000
#if !defined(VERSION) || VERSION > 2 || VERSION < 0
#error "Bad version"
#endif
#if VERSION == 2
#define AT(_a_,_b_) (_a_.at(_b_))
typedef std::vector<float> Field;
#endif
#if VERSION == 1
#define AT(_a_,_b_) (_a_[_b_])
typedef std::vector<float> Field;
#endif
#if VERSION == 0
#define AT(_a_,_b_) (_a_[_b_])
typedef float* Field;
#endif
#include <iostream>
#include <omp.h>
int main(void) {
#if VERSION != 0
Field img(NX*NY*NY);
#else
Field img = new float[NX*NY*NY];
#endif
double end, begin;
begin = omp_get_wtime();
const int csize = NZ;
const int psize = NZ * NX;
for(int t = 0; t < T; t++ ) {
/* Swap the 3D volume and apply the "blurring" coefficients */
#pragma omp parallel for
for(int j = H; j < NY-H; j++ ) {
for( int i = H; i < NX-H; i++ ) {
for( int k = H; k < NZ-H; k++ ) {
int eindex = k+i*NZ+j*NX*NZ;
AT(img,eindex) = C0 * AT(img,eindex) +
C1 * (AT(img,eindex - csize) +
AT(img,eindex + csize) +
AT(img,eindex - psize) +
AT(img,eindex + psize) );
}
}
}
}
end = omp_get_wtime();
std::cout << "Elapsed "<< (end-begin) <<" s." << std::endl;
/* Access img field so we force it to be deleted after accouting time */
#define WHATEVER 12.f
if( img[ NZ ] == WHATEVER ) {
std::cout << "Whatever" << std::endl;
}
#if VERSION == 0
delete[] img;
#endif
}
人们会期望代码与VERSION=1 和VERSION=0 执行相同的操作,但输出如下:
- 版本 2:经过 6.94905 秒。
- 版本 1:经过 4.08626 秒
- 版本 0:经过 1.97576 秒。
如果我在没有 OMP 的情况下编译(我只有两个内核),我会得到类似的结果:
- 版本 2:经过 10.9895 秒。
- 版本 1:经过 7.14674 秒
- 版本 0:经过 3.25336 秒。
我总是使用 GCC 4.6.3 和编译选项 -fopenmp -finline-functions -O3 进行编译(当我在没有 omp 的情况下编译时,我当然会删除 -fopenmp)我做错了什么,例如在编译时?或者我们真的应该期待向量和数组之间的差异吗?
PS:我不能使用 std::array 因为我所依赖的编译器不支持 C11 标准。使用 ICC 13.1.2 我得到了类似的行为。
【问题讨论】:
-
不使用omp怎么办?你确定这是合法的吗?
-
好点。在没有 omp 的情况下得到类似的结果:10.9895、7.14674 和 3.25336(分别为 2、1、0 版)。我将它包括在问题中。
-
ideone 对于版本 0 和 1 给出了相同的结果。
-
@Genís 你应该担心,如果你的程序表现出未定义的行为,那么谈论性能是没有意义的。
-
@molbdnilo 我没有手动验证任何东西,但是他在版本 2 中没有得到异常这一事实几乎证明了没有越界访问。