【发布时间】:2020-10-22 14:03:57
【问题描述】:
我正在尝试使用 OpenACC 来完成我的期末论文,以提高代码的性能。但是,优化的代码比我尝试了很多东西的串行代码差,但没有一个有效。如果有人可以帮助我,我将不胜感激。
1332 void SOR()
1333 {
1334 iteracoes_solver = 0;
1335
1336
1337 {
1338
1339 #pragma acc data copy(AC_lin[2:nx*ny], Po1_lin[2:nx*ny], AUXW1[2:nx*ny], Qo_lin[2:nx*ny], Tgx[2:nx*ny], Po3_lin[2:nx*ny], Tgy[2:nx*ny], P_auxi[2:nx*ny], vetErro[2:nx*ny]) \
1340 copyin(AC_lin[2:nx*ny], Tgx[2:nx*ny], Tgy[2:nx*ny])
1341 while (iteracoes_solver < 10001)
1342 {
1343
1344
1345 //#pragma acc kernels loop private(n) copyin(P_auxi[0:nxy]) vector(512)
1346 for (n = 1; n <= nxy; n++)
1347 P_auxi[n] = Po3_lin[n];
1348
1349
1350 {
1351
1352 erro = 0.0;
1353
1354 if (total_iter == 10000)
1355 {
1356 printf("---> TEMPO=%g\n---> Numero maximo de iteracoes atingido no solver\n---> Corrigir parametros\n", tempo_atual);//getch();
1357 exit_tool();
1358 }
1359
1360 n = 1;
1361 auxf1 = (AC_lin[n] * Po1_lin[n]) + (AUXW1[n] * Qo_lin[n]) + (Tgx[n] * Po3_lin[n + 1]) + (Tgy[n] * Po3_lin[n + nx]) + ((1 - AUXW1[n]));
1362 Paux = auxf1 / (AC_lin[n] + Tgx[n] + Tgy[n] + (1 - AUXW1[n]));
1363 Paux = (omega * Paux) + ((1.0 - omega) * P_auxi[n]);
1364 vetErro[n] = fabs(Po3_lin[n] - Paux);
1365 Po3_lin[n] = Paux;
1366
1367 n = nx;
1368 auxf1 = (AC_lin[n] * Po1_lin[n]) + (AUXW1[n] * Qo_lin[n]) + (Tgx[n - 1] * Po3_lin[n - 1]) + (Tgy[n] * Po3_lin[n + nx]) + ((1 - AUXW1[n]));
1369 Paux = auxf1 / (AC_lin[n] + Tgx[n - 1] + Tgy[n] + ((1 - AUXW1[n])));
1370 Paux = (omega * Paux) + ((1.0 - omega) * P_auxi[n]);
1371 vetErro[n] = fabs(Po3_lin[n] - Paux);
1372 Po3_lin[n] = Paux;
1373
1374 auxi11 = nxy - nx;
1375
1376 n = auxi11 + 1;
1377 auxf1 = (AC_lin[n] * Po1_lin[n]) + (AUXW1[n] * Qo_lin[n]) + (Tgx[n] * Po3_lin[n + 1]) + (Tgy[n - nx] * Po3_lin[n - nx]) + ((1 - AUXW1[n]));
1378 Paux = auxf1 / (AC_lin[n] + Tgx[n] + Tgy[n - nx] + ((1 - AUXW1[n])));
1379 Paux = (omega * Paux) + ((1.0 - omega) * P_auxi[n]);
1380 vetErro[n] = fabs(Po3_lin[n] - Paux);
1381 Po3_lin[n] = Paux;
1382
1383 n = nxy;
1384 auxf1 = (AC_lin[n] * Po1_lin[n]) + (AUXW1[n] * Qo_lin[n]) + (Tgx[n - 1] * Po3_lin[n - 1]) + (Tgy[n - nx] * Po3_lin[n - nx]) + ((1 - AUXW1[n]));
1385 Paux = auxf1 / (AC_lin[n] + Tgx[n - 1] + Tgy[n - nx] + ((1 - AUXW1[n])));
1386 Paux = (omega * Paux) + ((1.0 - omega) * P_auxi[n]);
1387 vetErro[n] = fabs(Po3_lin[n] - Paux);
1388 Po3_lin[n] = Paux;
1389
1390
1391
1392 #pragma acc parallel loop private(n)
1393 for (n = 2; n < nx; n++)
1394 {
1395 auxf1 = (AC_lin[n] * Po1_lin[n]) + (AUXW1[n] * Qo_lin[n]) + (Tgx[n] * Po3_lin[n + 1]) + (Tgx[n - 1] * Po3_lin[n - 1]) + (Tgy[n] * Po3_lin[n + nx]) + ((1 - AUXW1[n]));
1396 Paux = auxf1 / (AC_lin[n] + Tgx[n] + Tgx[n - 1] + Tgy[n] + ((1 - AUXW1[n])));
1397 Paux = (omega * Paux) + ((1.0 - omega) * P_auxi[n]);
1398 vetErro[n] = fabs(Po3_lin[n] - Paux);
1399 Po3_lin[n] = Paux;
1400 }
1401
1402
1403
1404 #pragma acc parallel loop private(n)
1405 for (j = 2; j < ny; j++)
1406 {
1407 auxi11 = nx * (j - 1);
1408
1409 n = auxi11 + 1;
1410 auxf1 = (AC_lin[n] * Po1_lin[n]) + (AUXW1[n] * Qo_lin[n]) + (Tgx[n] * Po3_lin[n + 1]) + (Tgy[n] * Po3_lin[n + nx]) + (Tgy[n - nx] * Po3_lin[n - nx]) + ((1 - AUXW1[n]));
1411 Paux = auxf1 / (AC_lin[n] + Tgx[n] + Tgy[n] + Tgy[n - nx] + ((1 - AUXW1[n])));
1412 Paux = (omega * Paux) + ((1.0 - omega) * P_auxi[n]);
1413 vetErro[n] = fabs(Po3_lin[n] - Paux);
1414 Po3_lin[n] = Paux;
1415 }
1416
1417
1418
1419 //#pragma acc kernels
1420 for (j = 2; j < ny; j++)
1421 {
1422 auxi11 = nx * (j - 1);
1423
1424 n = auxi11 + nx;
1425 auxf1 = (AC_lin[n] * Po1_lin[n]) + (AUXW1[n] * Qo_lin[n]) + (Tgx[n - 1] * Po3_lin[n - 1]) + (Tgy[n] * Po3_lin[n + nx]) + (Tgy[n - nx] * Po3_lin[n - nx]) + ((1 - AUXW1[n]));
1426 Paux = auxf1 / (AC_lin[n] + Tgx[n - 1] + Tgy[n] + Tgy[n - nx] + ((1 - AUXW1[n])));
1427 Paux = (omega * Paux) + ((1.0 - omega) * P_auxi[n]);
1428 vetErro[n] = fabs(Po3_lin[n] - Paux);
1429 Po3_lin[n] = Paux;
1430
1431 }
1432
1433
1434 auxi11 = nxy - nx;
1435
1436
1437
1438 //#pragma acc kernels
1439 for (i = 2; i < nx; i++)
1440 {
1441 n = auxi11 + i;
1442 auxf1 = (AC_lin[n] * Po1_lin[n]) + (AUXW1[n] * Qo_lin[n]) + (Tgx[n] * Po3_lin[n + 1]) + (Tgx[n - 1] * Po3_lin[n - 1]) + (Tgy[n - nx] * Po3_lin[n - nx]) + ((1 - AUXW1[n]));
1443 Paux = auxf1 / (AC_lin[n] + Tgx[n] + Tgx[n - 1] + Tgy[n - nx] + ((1 - AUXW1[n])));
1444 Paux = (omega * Paux) + ((1.0 - omega) * P_auxi[n]);
1445 vetErro[n] = fabs(Po3_lin[n] - Paux);
1446 Po3_lin[n] = Paux;
1447 }
1448 }
1449
1450
1451
1452
1453 //#pragma acc kernels loop private(auxf1,Paux,i,j,n) vector(512) independent
1454 for (j = 2; j < ny; j++)
1455 {
1456 for (i = 2 + (j % 2); i < nx; i += 2)
1457 {
1458 n = (nx * (j - 1)) + i;
1459 auxf1 = (AC_lin[n] * Po1_lin[n]) + (AUXW1[n] * Qo_lin[n]) + (Tgx[n] * Po3_lin[n + 1]) + (Tgx[n - 1] * Po3_lin[n - 1]) + (Tgy[n] * Po3_lin[n + nx]) + (Tgy[n - nx] * Po3_lin[n - nx]) + ((1 - AUXW1[n]));
1460 Paux = auxf1 / (AC_lin[n] + Tgx[n] + Tgx[n - 1] + Tgy[n] + Tgy[n - nx] + ((1 - AUXW1[n])));
1461 Paux = (omega * Paux) + ((1.0 - omega) * P_auxi[n]);
1462 vetErro[n] = fabs(Po3_lin[n] - Paux);
1463 Po3_lin[n] = Paux;
1464 }
1465 }
1466
1467
1468 //#pragma acc kernels loop private(auxf1,Paux,i,j,n) vector(512) independent
1469 for (j = 2; j < ny; j++)
1470 {
1471 for (i = 3 - (j % 2); i < nx; i += 2)
1472 {
1473 n = (nx * (j - 1)) + i;
1474 auxf1 = (AC_lin[n] * Po1_lin[n]) + (AUXW1[n] * Qo_lin[n]) + (Tgx[n] * Po3_lin[n + 1]) + (Tgx[n - 1] * Po3_lin[n - 1]) + (Tgy[n] * Po3_lin[n + nx]) + (Tgy[n - nx] * Po3_lin[n - nx]) + ((1 - AUXW1[n]));
1475 Paux = auxf1 / (AC_lin[n] + Tgx[n] + Tgx[n - 1] + Tgy[n] + Tgy[n - nx] + ((1 - AUXW1[n])));
1476 Paux = (omega * Paux) + ((1.0 - omega) * P_auxi[n]);
1477 vetErro[n] = fabs(Po3_lin[n] - Paux);
1478 Po3_lin[n] = Paux;
1479 }
1480 }
1481
1482
1483 #pragma acc parallel loop private(n)
1484 for (n = 0; n < nxy; n++) {
1485 erro += vetErro[n];
1486 }
1487
1488
1489 if ((erro / nxy < tol)) {
1490 //#pragma omp cancel parallel
1491 break;
1492 }
1493 iteracoes_solver += 1;
1494 }
1495
1496 }
1497 }
我放不下所有的decode,所以放了一部分代码。我评论了一些编译指示以供测试。当我的 nx=ny >=1000 时,串行代码优于优化代码。我不明白的另一件事是我删除了代码的所有 pragma,然后运行 PGI 编译器来优化代码,串行代码更好,我不知道为什么。最后,我有两个问题:
1 - 我做错了什么? 2 - 为什么没有编译指示的代码比串行代码差?
最好的问候,布雷诺。
更新: 我忘了把编译信息。我运行代码
pgcc -ta=multicore -Minfo=all file.c -o file.exe
并生成
1360, FMA (fused multiply-add) instruction(s) generated
1392, Generating Multicore code
1393, #pragma acc loop gang
1393, FMA (fused multiply-add) instruction(s) generated
1404, Generating Multicore code
1405, #pragma acc loop gang
1405, FMA (fused multiply-add) instruction(s) generated
1420, FMA (fused multiply-add) instruction(s) generated
1439, FMA (fused multiply-add) instruction(s) generated
1456, FMA (fused multiply-add) instruction(s) generated
1471, FMA (fused multiply-add) instruction(s) generated
1483, Generating Multicore code
1484, #pragma acc loop gang
1485, Generating implicit reduction(+:erro)
【问题讨论】:
-
由于代码不完整、出错(如前所述,while 循环不会终止),并且您已注释掉所需的 pragma,因此很难提供任何具体建议。相反,编译器反馈消息 (-Minfo=accel) 告诉您什么?循环是成功并行化还是在设备上串行运行?探查器显示什么?您可以通过设置环境变量“PGI_ACC_TIME=1”来进行快速配置,或者根据您使用的编译器版本使用 pgprof 或 Nsight-Systems。
-
正如 Mat 所说,
-Minfo=accel是你的朋友。另请注意,一种典型的方法是逐步并行化代码并检查性能和正确性,而不是进行大规模转换。如果您在并行化之前和之后对单个循环进行计时,那将为您提供很好的信息。 -
@MatColgrove,感谢您的回答。我用编译器消息更新了这个问题。我尝试更改环境变量 PGI_ACC_TIME,但我不能。我用“export PGI_ACC_TIME=1”替换了许多文件,但没有一个起作用:/
-
@Richard,也感谢您的回答。并感谢您的提示。我现在正在尝试这个。 :)
-
好的,从更新中我看到您的目标是多核。 PGI_ACC_TIME 只会分析设备执行情况,因此解释了为什么没有给出输出。对于多核,请检查您的绑定以及如何使用核心。您是通过批处理作业还是在系统本地运行?如果在本地,打开一个新的 shell 并通过 'top' 监视运行以查看绑定。默认情况下,将使用所有内核,包括超线程,其中一种可能性是超额订阅。您可以通过环境变量 ACC_NUM_CORES 显式设置要使用的内核数。