首先抱歉,如果我犯了语法错误。我不是英国人。
我正在努力改善在Fortran中使用OpenMP增加线程数时发生的产量损失。
我正在使用两个Intel Xeon X5650(12个物理内核)和96 Gb RAM
我获得的最佳结果如下:
1 proc - > 15.50秒; 2 proc - > 8.10秒; 4 proc - > 4.42秒; 8 proc - > 2.81秒; 12 proc - > 2.43秒
就像你看到的那样,改进减少了我运行的线程越多。
以下是代码:
allocate(SUM(PUNTOST,PUNTOSP,NUM_DATA,2))
allocate(SUMATORIO(1))
allocate(SUMATORIO(1)%REGION(REGIONS))
DO i=1,REGIONES
allocate(SUMATORIO(1)%REGION(i)%VALOR(2,PUNTOSP,PUNTOST))
SUMATORIO(1)%REGION(i)%VALOR= cmplx(0.0,0.0)
END DO
allocate(valor_aux(2,PUNTOSP,PUNTOST))
!...
call SYSTEM_CLOCK(counti,count_rate)
!$OMP PARALLEL NUM_THREADS(THREADS) DEFAULT(PRIVATE) FIRSTPRIVATE(REGIONS) &
!$OMP SHARED(SUMATORIO,SUM,PP,VEC_1,VEC_2,IDENT,TIPO,MUESTRA,PUNTOST,PUNTOSP)
!$OMP DO SCHEDULE(DYNAMIC,8)
DO i=1,REGIONS
INDICE=VEC_1(i)
valor_aux = cmplx(0.0,0.0)
DO j=1,VEC_2(i)
ii=IDENT(INDICE+1)
INDICE=INDICE+1
IF(TIPO(ii).ne.4) THEN
j1=MUESTRA(ii)
DO I1=1,PUNTOST
DO I2=1,PUNTOSP
valor_aux(1,I2,I1)=valor_aux(1,I2,I1)+SUM(I1,I2,J1,1)*PP(ii)
valor_aux(2,I2,I1)=valor_aux(2,I2,I1)+SUM(I1,I2,J1,2)*PP(ii)
END DO
END DO
END IF
END DO
SUMATORIO(1)%REGION(i)%VALOR= valor_aux
END DO
!$OMP END DO
!$OMP END PARALLEL
call SYSTEM_CLOCK(countf)
dt=REAL(countf-counti)/REAL(count_rate)
write(*,*)'FASE_1: Time: ',dt,'seconds'
要知道的一些要点:
我试图改变矩阵的尺寸以避免过度的内存缓存(例如,SUM(2,PUNTOSP,PUNTOST,NUM_DATA))但这是我获得最佳性能的方式(我不喜欢我不知道原因,因为在我读过的大多数文档中,他们都说你必须尝试使内存访问“顺序”,以使CPU为缓存带来最少的内存量。
此外,我已将内存对齐更改为32,64和128字节,但它没有任何改进。
此外,我已将SCHEDULE选项更改为具有不同块大小的STATIC和具有不同块大小的DYNAMIC,但结果相同或更差。
在使用8个或更多内核时,您是否有一些我可以用来改善性能的想法?
非常感谢你的关注和帮助。
答案 0 :(得分:1)
使用12个处理器将CPU时间除以6相当不错。在我的应用程序中,我很少得到超过4或5(但它始终是顺序部分,这可能是其中的原因)。
您可以尝试选项折叠,允许将两个循环合并在一起......但我不知道在您的情况下这是否可行,因为它们是要满足的条件(例如,两个循环之间没有指令)。
答案 1 :(得分:0)
在Fortran中处理多维数组时,最左边的索引应该更快。您可以尝试将valor_aux
和SUM
的索引顺序更改为
valor_aux(PUNTOSP, PUNTOST, 2)
SUM(PUNTOSP, PUNTOST, NUM_DATA, 2)
此外,您应该始终关注Amdahl's law。总会有一些开销,无法实现额外的加速。
另外:在你的两个最里面的循环中,因子PP(ii)
不会改变。您应该尝试在这些循环之后应用它(除了,您知道,您正在使用FMA)。而这些循环只是许多值的SUM。您应该尝试使用内部函数SUM
来删除这些循环。这两件事都需要对你的循环进行大规模的重新设计。