我正在处理的代码是用 C++ 编写的,有点复杂,但下面的示例显示了问题。它来自 Chandrasekaran 和 Juckeland 所著的一本书。如果使用 nvc -acc(或 pgcc -acc,如作者所做的那样)编译并运行,则需要几秒钟才能完成。如果我使用 nvc++ -acc (pgc++ -acc),它会慢几个数量级,甚至比串行版本更慢。我很好奇是否有人注意到类似的问题或知道可能的解释。
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <sys/time.h>
#define WIDTH 1000
#define HEIGHT 1000
#define TEMP_TOLERANCE 0.01
double Temperature[HEIGHT+2][WIDTH+2];
double Temperature_previous[HEIGHT+2][WIDTH+2];
void initialize();
void track_progress(int iter);
int main(int argc, char *argv[]) {
int i, j;
int iteration=1;
double worst_dt=100;
struct timeval start_time, stop_time, elapsed_time;
gettimeofday(&start_time,NULL);
initialize();
#pragma acc data copy(Temperature_previous), create(Temperature)
{
while ( worst_dt > TEMP_TOLERANCE ) {
#pragma acc kernels
for(i = 1; i <= HEIGHT; i++) {
for(j = 1; j <= WIDTH; j++) {
Temperature[i][j] = 0.25 * (Temperature_previous[i+1][j]
+ Temperature_previous[i-1][j]
+ Temperature_previous[i][j+1]
+ Temperature_previous[i][j-1]);
}
}
worst_dt = 0.0;
#pragma acc kernels
for(i = 1; i <= HEIGHT; i++){
for(j = 1; j <= WIDTH; j++){
worst_dt = fmax( fabs(Temperature[i][j]-
Temperature_previous[i][j]),worst_dt);
Temperature_previous[i][j] = Temperature[i][j];
}
}
if((iteration % 100) == 0) {
#pragma acc update host(Temperature)
track_progress(iteration);
}
iteration++;
}
}
gettimeofday(&stop_time,NULL);
timersub(&stop_time, &start_time, &elapsed_time);
printf("\nMax error at iteration %d was %f\n",
iteration-1, worst_dt);
printf("Total time was %f seconds.\n",
elapsed_time.tv_sec+elapsed_time.tv_usec/1000000.0);
}
void initialize(){
int i,j;
for(i = 0; i <= HEIGHT+1; i++){
for (j = 0; j <= WIDTH+1; j++){
Temperature_previous[i][j] = 0.0;
}
}
for(i = 0; i <= HEIGHT+1; i++) {
Temperature_previous[i][0] = 0.0;
Temperature_previous[i][WIDTH+1] = (100.0/HEIGHT)*i;
}
for(j = 0; j <= WIDTH+1; j++) {
Temperature_previous[0][j] = 0.0;
Temperature_previous[HEIGHT+1][j] = (100.0/WIDTH)*j;
}
}
void track_progress(int iteration) {
int i;
printf("---------- Iteration number: %d ------------\n",
iteration);
for(i = HEIGHT-5; i <= HEIGHT; i++) {
printf("[%d,%d]: %5.2f ", i, i, Temperature[i][i]);
}
printf("\n");
}
我在两台Linux机器上测试了它,结果相同。我尝试了各种编译器,但只要我按照 C++ 标准而不是 C 进行编译,问题仍然存在。 -Minfo=all 没有显示任何定性意义。
我看到了同样的事情,如果您将
-Minfo=accel
添加到命令行中,您会看到它在第 37 行停止并行化循环,表示稍后需要最坏的_dt 值,从而导致依赖性。我不知道为什么编译器分析在这里无法正常工作,但是如果将第 36 行更改为以下内容,您将获得性能恢复:#pragma acc kernels loop independent collapse(2) reduction(max:worst_dt)
。我会确保其中一位编译器人员能够看到这一点。
更新: 您还可以尝试将
-std=c++11
或 -std=c++14
添加到编译中,无需修改代码即可获得预期的性能。我不完全确定为什么默认标准存在此问题,但编译器团队已意识到此交换。