代码花费更多时间来完成超过1个线程

时间:2016-07-15 11:35:45

标签: multithreading fortran openmp benchmarking

我想使用具有临界区的OpenMP线程对一些Fortran代码进行基准测试。为了模拟一个真实的环境,我试图在这个关键部分之前产生一些负载。

!Kompileraufruf: gfortran -fopenmp -o minExample.x minExample.f90

  PROGRAM minExample
     USE omp_lib
     IMPLICIT NONE
     INTEGER                        :: n_chars, real_alloced
     INTEGER                        :: nx,ny,nz,ix,iy,iz, idx
     INTEGER                        :: nthreads, lasteinstellung,i 
     INTEGER, PARAMETER             :: dp = kind(1.0d0)
     REAL (KIND = dp)               :: j
     CHARACTER(LEN=32)              :: arg

     nx             = 2
     ny             = 2
     nz             = 2
     lasteinstellung= 10000
     CALL getarg(1, arg)
     READ(arg,*) nthreads
     CALL OMP_SET_NUM_THREADS(nthreads)
!$omp parallel
!$omp master
     nthreads=omp_get_num_threads()
!$omp end master
!$omp end parallel
     WRITE(*,*) "Running OpenMP benchmark on ",nthreads," thread(s)"

    n_chars = 0
    idx = 0
!$omp parallel do default(none) collapse(3) &
!$omp   shared(nx,ny,nz,n_chars) &
!$omp   private(ix,iy,iz, idx) &
!$omp   private(lasteinstellung,j) !&  
    DO iz=-nz,nz
       DO iy=-ny,ny
          DO ix=-nx,nx
!                  WRITE(*,*) ix,iy,iz
             j = 0.0d0
             DO i=1,lasteinstellung
                j = j + real(i)
             END DO
!$omp critical
             n_chars = n_chars + 1               
            idx = n_chars                       
!$omp end critical
          END DO
       END DO
    END DO
  END PROGRAM

我使用gfortran -fopenmp -o test.x test.f90编译了此代码,并使用time ./test.x THREAD执行了该代码 执行此代码会产生一些奇怪的行为,具体取决于线程计数(使用OMP_SET_NUM_THREADS设置):与一个线程(6ms)相比,使用更多线程执行会在我的多核上花费更多时间(2个线程:16000ms,4个线程:9000ms)机。 什么可能导致这种行为?是否有更好(但仍然很简单)的方法来生成负载而不运行某些缓存效果或相关的东西?

编辑:奇怪的行为:如果我在嵌套循环中写入,则执行速度会急剧增加2个线程。如果它被注释掉,那么2或3个线程的执行将永远占用(写入显示循环变量的非常缓慢的增量)...但不是1或4个线程。我在另一台多核计算机上也尝试了这个代码。它永远需要1个和3个线程,但不适用于2个或4个线程。

1 个答案:

答案 0 :(得分:2)

如果您展示的代码确实完整,那么您在loadSet的并行部分中缺少private的定义。它未定义并循环

                 DO i=1,loadSet
                    j = j + real(i)
                 END DO

可以进行完全任意数量的迭代。

如果在代码之前某处定义了值,则表示您可能不希望firstprivate代替private