Parallel processing 使用OpenMP,并行嵌套循环运行缓慢
我有一个fortran程序的一部分,它由一些嵌套循环组成,我想用OpenMP并行化Parallel processing 使用OpenMP,并行嵌套循环运行缓慢,parallel-processing,fortran,openmp,Parallel Processing,Fortran,Openmp,我有一个fortran程序的一部分,它由一些嵌套循环组成,我想用OpenMP并行化 integer :: nstates , N, i, dima, dimb, dimc, a_row, b_row, b_col, c_row, row, col double complex, dimension(4,4):: mat double complex, dimension(:), allocatable :: vecin,vecout nstates = 2 N = 24 allocate(
integer :: nstates , N, i, dima, dimb, dimc, a_row, b_row, b_col, c_row, row, col
double complex, dimension(4,4):: mat
double complex, dimension(:), allocatable :: vecin,vecout
nstates = 2
N = 24
allocate(vecin(nstates**N), vecout(nstates**N))
vecin = ...some data
vecout = 0
mat = reshape([...some data...],[4,4])
dimb=nstates**2
!$OMP PARALLEL DO PRIVATE(dima,dimc,row,col,a_row,b_row,c_row,b_col)
do i=1,N-1
dima=nstates**(i-1)
dimc=nstates**(N-i-1)
do a_row = 1, dima
do b_row = 1,dimb
do c_row = 1,dimc
row = ((a_row-1)*dimb + b_row - 1)*dimc + c_row
do b_col = 1,dimb
col = ((a_row-1)*dimb + b_col - 1)*dimc + c_row
!$OMP ATOMIC
vecout(row) = vecout(row) + vecin(col)*mat(b_row,b_col)
end do
end do
end do
end do
end do
!$OMP END PARALLEL DO
程序运行了,我得到的结果也是正确的,速度简直太慢了。比没有OpenMP要慢得多。我对OpenMP了解不多。我是否在使用私有或OMP原子时犯了错误?对于如何提高代码性能的每一条建议,我将不胜感激。如果您的数组太大,并且通过自动缩减得到堆栈溢出,您可以使用可分配的临时数组自己实现缩减 正如Francois Jacq所指出的,您还存在由
dima
和dimb
引起的竞态条件,这应该是私有的
double complex, dimension(:), allocatable :: tmp
!$OMP PARALLEL PRIVATE(dima,dimb,row,col,a_row,b_row,c_row,b_col,tmp)
allocate(tmp(size(vecout)))
tmp = 0
!$OMP DO
do i=1,N-1
dima=nstates**(i-1)
dimc=nstates**(N-i-1)
do a_row = 1, dima
do b_row = 1,dimb
do c_row = 1,dimc
row = ((a_row-1)*dimb + b_row - 1)*dimc + c_row
do b_col = 1,dimb
col = ((a_row-1)*dimb + b_col - 1)*dimc + c_row
tmp(row) = tmp(row) + vecin(col)*mat(b_row,b_col)
end do
end do
end do
end do
end do
!$OMP END DO
!$OMP CRITICAL
vecout = vecout + tmp
!$OMP END CRITICAL
!$OMP END PARALLEL
你能试试这样的东西吗
do b_col=1,dimb
do i=1,N-1
dima=nstates**(i-1)
dimc=nstates**(N-i-1)
!$OMP PARALLEL DO COLLAPSE(3) PRIVATE(row,col,a_row,b_row,c_row)
do a_row = 1, dima
do b_row = 1,dimb
do c_row = 1,dimc
row = ((a_row-1)*dimb + b_row - 1)*dimc + c_row
col = ((a_row-1)*dimb + b_col - 1)*dimc + c_row
vecout(row) = vecout(row) + vecin(col)*mat(b_row,b_col)
enddo
enddo
enddo
enddo
enddo
优点是//循环现在不会导致冲突:所有索引行都不同。您应该查看
vecout
的reduce
子句。这应该会加快速度;-)在最内部的循环中使用原子指令不是一个好主意!谢谢你的回答。为什么原子指令是个坏主意?我删除了原子指令并使用了reduce(+:vecout),这导致了分段错误。减少和数组有什么特别的地方吗?减少只适用于小数组,没有分段错误。然后需要增加堆栈大小:ulimit-s unlimited
谢谢,这很有效。但是为什么这个方法比使用原子更快呢?变量dima和dimc应该是私有的是的,我以前认识到这一点,现在在我的问题中改变了它。从我的观点来看,它们仍然是竞争条件,因为两个线程可以有相同的行索引。请参阅我建议的解决方案。@FrancoisJacq它们可以具有相同的行索引,但它们写入不同的数组。您的解决方案很好,但是每个上都有很多同步$omp并行do
。最后的决定应该来自绩效评估。谢谢你的回答。我将测量你和Vladimir F的解决方案的时间来比较它们。到目前为止,我能说的是,您的解决方案对我来说运行得更快,不会崩溃。你能告诉我你为什么把b_col循环排除在其他循环之外吗?当b_col循环在内部时,每个线程的行索引也应该不同,不是吗?循环b_col在//循环2外部,避免线程在修改vecout时计算相同的行索引=>争用情况(随机错误的风险)。你为什么要删去折叠条款?它只是表示接下来的三个循环可能合并到一个//one.row=((a_row-1)*dimb+b_row-1)*dimc+c_row,所以row不依赖于b_col。对于折叠问题:首先我尝试了使用折叠,然后没有。因为行不依赖于b_col,所以相同的行索引可以多次获得b_col。关于崩溃,如果你测量了有无,那么一切都没问题:评判永远是测量!在我之前的信息中,请阅读“dimb时间”,而不是“b_col时间”