首页 > 解决方案 > Fortran 中大型数组的 OpenMP 缩减

问题描述

我知道有时会问到与此类似的问题:Openmp array reductions with FortranReducing on array in OpenMP,甚至在英特尔论坛(https://software.intel.com/en-us/forums/intel-moderncode-for -parallel-architectures/topic/345415)但我想知道您的意见,因为我得到的可扩展性不是我所期望的。

所以我需要填充一个非常大的复数数组,我想与 OpenMP 并行化。我们的第一种方法是这样的:

COMPLEX(KIND=DBL), ALLOCATABLE :: huge_array(:)
COMPLEX(KIND=DBL), ALLOCATABLE :: thread_huge_array(:)
INTEGER :: huge_number, index1, index2, index3, index4, index5, bignumber1, bignumber2, smallnumber, depending_index

ALLOCATE(huge_array(huge_number))

!$OMP PARALLEL FIRSTPRIVATE(thread_huge_array)
      ALLOCATE(thread_huge_array(SIZE(huge_array)))
      thread_huge_array = ZERO
!$OMP DO
      DO index1=1,bignumber1
         ! Some calculations
         DO index2=1,bignumber2
            ! Some calculations
            DO index3=1,6
               DO index4=1,6
                  DO index5=1,smallnumber
                     depending_index = function(index1, index2, index3, index4, index5)
                     thread_huge_array(depending_index) = thread_huge_array(depending_index)
                  ENDDO
               ENDDO 
            ENDDO
         ENDDO 
      ENDDO 
!$OMP END DO
!$OMP BARRIER
!$OMP MASTER
      huge_array = ZERO
!$OMP END MASTER
!$OMP CRITICAL
      huge_array = huge_array + thread_huge_array
!$OMP END CRITICAL
      DEALLOCATE(thread_huge_array)
!$OMP END PARALLEL

因此,通过这种方法,我们可以在 8 核之前获得良好的可扩展性,在 32 核之前获得合理的可扩展性,从 40 核开始,它比 16 核慢(我们有一台具有 80 个物理核的机器)。当然,我们不能使用 REDUCTION 子句,因为数组的大小太大以至于无法放入堆栈(甚至将 ulimit 增加到机器允许的最大值)。

我们尝试了一种不同的方法:

COMPLEX(KIND=DBL), ALLOCATABLE :: huge_array(:)
COMPLEX(KIND=DBL), POINTER:: thread_huge_array(:)
INTEGER :: huge_number

ALLOCATE(huge_array(huge_number))

ALLOCATE(thread_huge_array(SIZE(huge_array),omp_get_max_threads()))
thread_huge_array = ZERO

!$OMP PARALLEL PRIVATE (num_thread)

      num_thread = omp_get_thread_num()+1
!$OMP DO
      DO index1=1,bignumber1
         ! Some calculations
         DO index2=1,bignumber2
            ! Some calculations
            DO index3=1,6
               DO index4=1,num_weights_sp
                  DO index5=1,smallnumber
                     depending_index = function(index1, index2, index3, index4, index5)
                     thread_huge_array(depending_index, omp_get_thread_num()) = thread_huge_array(depending_index, omp_get_thread_num())
                  ENDDO
               ENDDO 
            ENDDO
         ENDDO 
      ENDDO 
!$OMP END DO
!$OMP END PARALLEL

huge_array = ZERO

DO index_ii = 1,omp_get_max_threads()
   huge_array = huge_array + thread_huge_array(:,index_ii)
ENDDO

DEALLOCATE(thread_huge_array)

DEALLOCATE(huge_array)

在最后一种情况下,我们为该方法获得了更长的时间(由于分配了更大的内存)和更差的相对加速度。

您能否提供一些提示以实现更好的加速?或者用 OpenMP 来处理这些巨大的数组是不可能的?

标签: arraysfortranopenmpfortran90reduction

解决方案


推荐阅读