【问题标题】:yield loss with OpenMP in FortranFortran 中 OpenMP 的产量损失
【发布时间】:2014-02-19 21:41:42
【问题描述】:

如果我犯了语法错误,首先抱歉。我不是英国人。

我正在尝试改善在 Fortran 中使用 OpenMP 增加线程数时发生的产量损失。

我正在使用两个配备 96 Gb RAM 的 Intel Xeon X5650(12 个物理内核)

我获得的最佳结果如下:

1 触发 -> 15.50 秒; 2 过程 -> 8.10 秒; 4 过程 -> 4.42 秒; 8 过程 -> 2.81 秒; 12 次触发 -> 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'

需要了解的几点:

  • 所有数据类型都是 COMPLEX,循环向量除外
  • NUM_DATA = 14000000
  • 地区 = 1000000
  • VEC_2 中包含的值介于 10 到 20 之间
  • PUNTOST = 21
  • PUNTOSP = 20
  • 所有分配的内存消耗大约 60 Gb 的 RAM

我尝试更改矩阵的维度以规避过多的内存缓存(例如 SUM(2,PUNTOSP,PUNTOST,NUM_DATA))但这是我获得最佳性能的方式(我不不知道原因,因为在我读过的大多数文档中,他们都说您必须尝试使内存访问“顺序”以使 CPU 为缓存带来最少的内存量)。

我还将内存对齐方式更改为 32、64 和 128 字节,但没有任何改善。

此外,我已将 SCHEDULE 选项更改为具有不同块大小的 STATIC 和具有不同块大小的 DYNAMIC,但结果相同或更差。

您有什么想法可以用来提高使用 8 个或更多内核时的性能吗?

非常感谢您的关注和帮助。

【问题讨论】:

    标签: multithreading performance fortran openmp


    【解决方案1】:

    使用 12 个处理器的 CPU 时间除以 6 相当不错。在我的应用程序中,我得到的很少超过 4 或 5 个(但它总是保持顺序部分,这可能是原因)。

    您可以尝试选择 collapse 允许将两个循环合并在一起...但我不知道这在您的情况下是否可行,因为它们是要满足的条件(例如两个循环之间没有指令)。

    【讨论】:

    • 我试图将性能提高 6 倍以上,并试图尽可能地达到提高峰值,因为如果用户想要使用 16、32 或更多内核,他会发现那里12个或更多没有太大区别:(
    【解决方案2】:

    在 Fortran 中处理多维数组时,最左边的索引应该变化最快。您可以尝试将valor_auxSUM 的索引顺序更改为

    valor_aux(PUNTOSP, PUNTOST, 2)
    SUM(PUNTOSP, PUNTOST, NUM_DATA, 2)
    

    此外,您应该始终注意Amdahl's law。总是有一些开销,这会产生额外的加速是不可能的。

    另外:在最里面的两个循环中,PP(ii) 因子不会改变。您应该尝试在这些循环之后应用它(除了,您知道,您正在使用 FMA)。这些循环只是许多值的总和。您应该尝试使用内部函数 SUM 来删除这些循环。这两件事都可能需要对循环进行大规模的重新设计。

    【讨论】:

    • 感谢您的回复。我试图改变索引的顺序,但与我的想法相反,使用 12 个内核(+0.40 到时间)性能会降低。另一方面,我重新设计了循环,但时间是一样的。
    猜你喜欢
    • 2018-03-25
    • 1970-01-01
    • 2023-04-01
    • 2013-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-15
    相关资源
    最近更新 更多