Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Parallel processing 基本do循环上发生gfortran openmp分段错误_Parallel Processing_Fortran_Gfortran_Openmp - Fatal编程技术网

Parallel processing 基本do循环上发生gfortran openmp分段错误

Parallel processing 基本do循环上发生gfortran openmp分段错误,parallel-processing,fortran,gfortran,openmp,Parallel Processing,Fortran,Gfortran,Openmp,我有一个程序,将粒子分布到细胞网格中的云中。只需在粒子总数(Ntot)上循环并填充256^3网格(即每个粒子分布在8个单元上) 这很好。但是当我运行它(./cic)时,我得到了一个分段错误。我认为我的循环是一个典型的omp do问题。当我没有在openmp中编译程序时,它可以工作 !$omp parallel do do i = 1,Ntot if (x1(i).gt.0.and.y1(i).gt.0.and.z1(i).gt.0) then dense(int(x1(i)),

我有一个程序,将粒子分布到细胞网格中的云中。只需在粒子总数(Ntot)上循环并填充256^3网格(即每个粒子分布在8个单元上)

这很好。但是当我运行它(./cic)时,我得到了一个分段错误。我认为我的循环是一个典型的omp do问题。当我没有在openmp中编译程序时,它可以工作

!$omp parallel do
 do i = 1,Ntot
   if (x1(i).gt.0.and.y1(i).gt.0.and.z1(i).gt.0) then
     dense(int(x1(i)),int(y1(i)),int(z1(i))) = dense(int(x1(i)),int(y1(i)),int(z1(i))) &
     + dx1(i) * dy1(i) * dz1(i) * mpart
   end if

   if (x2(i).le.Ng.and.y1(i).gt.0.and.z1(i).gt.0) then
     dense(int(x2(i)),int(y1(i)),int(z1(i))) = dense(int(x2(i)),int(y1(i)),int(z1(i))) &
     + dx2(i) * dy1(i) * dz1(i) * mpart
   end if

   if (x1(i).gt.0.and.y2(i).le.Ng.and.z1(i).gt.0) then
     dense(int(x1(i)),int(y2(i)),int(z1(i))) = dense(int(x1(i)),int(y2(i)),int(z1(i))) &
     + dx1(i) * dy2(i) * dz1(i) * mpart
   end if

   if (x2(i).le.Ng.and.y2(i).le.Ng.and.z1(i).gt.0) then
     dense(int(x2(i)),int(y2(i)),int(z1(i))) = dense(int(x2(i)),int(y2(i)),int(z1(i))) &
     + dx2(i) * dy2(i) * dz1(i) * mpart
   end if

   if (x1(i).gt.0.and.y1(i).gt.0.and.z2(i).le.Ng) then
     dense(int(x1(i)),int(y1(i)),int(z2(i))) = dense(int(x1(i)),int(y1(i)),int(z2(i))) &
     + dx1(i) * dy1(i) * dz2(i) * mpart
   end if

   if (x2(i).le.Ng.and.y1(i).gt.0.and.z2(i).le.Ng) then
     dense(int(x2(i)),int(y1(i)),int(z2(i))) = dense(int(x2(i)),int(y1(i)),int(z2(i))) &
     + dx2(i) * dy1(i) * dz2(i) * mpart
   end if

   if (x1(i).gt.0.and.y2(i).le.Ng.and.z2(i).le.Ng) then
     dense(int(x1(i)),int(y2(i)),int(z2(i))) = dense(int(x1(i)),int(y2(i)),int(z2(i))) &
     + dx1(i) * dy2(i) * dz2(i) * mpart
   end if

   if (x2(i).le.Ng.and.y2(i).le.Ng.and.z2(i).le.Ng) then
     dense(int(x2(i)),int(y2(i)),int(z2(i))) = dense(int(x2(i)),int(y2(i)),int(z2(i))) &
     +  dx2(i) * dy2(i) * dz2(i) * mpart
   end if
  end do
!$omp end parallel do
迭代之间没有依赖关系。想法?

有关如何使变量共享和私有的说明,请参阅

看起来所有变量都应该共享,除了循环变量
i
,它必须是私有的。这将建议使用以下行:

!$omp parallel do default(shared) private(i)
这将修复您的分段错误(假设所有变量都正确)

但是,不同的线程可能会试图同时覆盖
稠密
的相同部分,从而导致不正确的总数。为了防止这种情况发生,您需要将每个分配到
稠密
的内容包装在类似
!$omp原子
!$omp临界
部分的内容中

但是,您可能会发现这样的关键部分会导致线程花费大部分时间等待,因此您可能看不到与纯串行代码相比的任何改进


原则上,您可以通过使用
reduce
关键字声明
density
来解决此问题,但不幸的是,它不能用于数组。

此问题以及中的问题,源于启用OpenMP时禁用自动堆数组的事实。这意味着如果没有
-fopenmp
,大数组Y将自动放置在静态存储器中(称为
.bss
段)在堆栈上分配小型阵列。当您打开OpenMP支持时,不会使用自动静态分配,并且会在例程的堆栈上分配您的
密集
阵列。OS X上的默认堆栈限制非常严格,因此存在分段错误

这里有几个选项。第一个选项是通过赋予
SAVE
属性,使
densite
具有静态分配。另一个选项是通过使其
可分配,然后使用
allocate
语句,在堆上显式分配它,例如:

REAL, DIMENSION(:,:,:), ALLOCATABLE :: dense

ALLOCATE(dense(256,256,256))

! Computations, computations, computations

DEALLOCATE(dense)
较新的Fortran版本支持在数组超出范围时自动释放数组,而不使用
SAVE
属性

请注意,您的OpenMP指令很好,不需要额外的数据共享子句。您不需要在
PRIVATE
子句中声明
i
,因为循环计数器具有预定的私有数据共享类。您不需要将其他变量放入
SHARED
子句中,因为它们是隐式共享的。但是,您在
densite
上执行的操作应该与
原子更新
同步(或者在较旧的OpenMP实现上简单地与
原子更新
同步),或者您应该使用
缩减(+:densite)
。原子更新被转换为锁定的添加,与循环中包含条件导致的巨大减速相比,不应该引起太多减速:

INTEGER :: xi, yi, zi

!$OMP PARALLEL DO PRIVATE(xi,yi,zi)
...
if (x1(i).gt.0.and.y1(i).gt.0.and.z1(i).gt.0) then
  xi = int(x1(i))
  yi = int(y1(i))
  zi = int(z1(i))
  !$OMP ATOMIC UPDATE
  dense(xi,yi,zi) = dense(xi,yi,zi) &
                  + dx1(i) * dy1(i) * dz1(i) * mpart
end if
...
对其他情况进行适当更改后复制代码。如果编译器抱怨
原子结构中的
UPDATE
子句,只需将其删除即可


减少(+:密集)
将在每个线程中创建一个
稠密
副本,这将消耗大量内存,并且最终应用的缩减将随着
稠密
的大小而变得越来越慢。对于小型数组,它将比原子更新更有效。

似乎您尚未声明任何共享或私有变量,因此它非常有用It’你会犯错误也就不足为奇了。你能帮我一点忙吗是每个线程将反馈到的唯一变量,因此可能是共享的。其余所有变量都是独立的。是否有任何编译标志可用于确定出错的位置?如何声明
dense
?它是一个自动数组,是
save
'd还是
可分配的
以及它到底是如何分配的ted?旁边请注意:我对免费的Solaris Studio的数据竞争分析器有很好的经验。它可以大大加快错误位置的搜索速度。dense在一开始是静态分配的。
default(shared)
private(I)
在这种情况下会改变任何东西,因为在Fortran OpenMP中,除非声明
threadprivate
,否则默认情况下变量是隐式
共享的,并且循环计数器具有预定的
private
数据共享属性。
reduce
子句仅接受C/C++中的数组。在Fortran中,数组是完美的对于减少,即使是可分配的,也是可以接受的。上面的这个循环在另一个不需要并行的循环中-它只循环了4次。我需要指定如何处理这个外部循环吗?我想要并行的唯一事情就是上面的循环。感谢Hristo-我已经按照您指定的方式分配了稠密。所以我基本上可以删除共享和私有组件,因为它是隐式的。我应该在哪里使用原子更新?谢谢。我想这需要在末尾使用!$OMP END PARALLEL DO,并且private语句正好在内部循环之前,而不是在外部。@Griff,是的,
PARALLEL DO
只是用来显示
private
子句的位置goes-基本上这是原始代码中的
并行do
。我刚刚添加了三个需要私有的辅助变量。在您的代码中只有一个并行区域,无论它只包含内环还是外环,正如我在其他问题中向您展示的那样。好的,谢谢。它仍然不起作用。我“我不是要你一行一行地看,但是如果
INTEGER :: xi, yi, zi

!$OMP PARALLEL DO PRIVATE(xi,yi,zi)
...
if (x1(i).gt.0.and.y1(i).gt.0.and.z1(i).gt.0) then
  xi = int(x1(i))
  yi = int(y1(i))
  zi = int(z1(i))
  !$OMP ATOMIC UPDATE
  dense(xi,yi,zi) = dense(xi,yi,zi) &
                  + dx1(i) * dy1(i) * dz1(i) * mpart
end if
...