24

メインプログラム:

program main                                                                                                                                                    
  use omp_lib                                                                                                                                                   
  use my_module                                                                                                                                                 
  implicit none                                                                                                                                                 

  integer, parameter :: nmax = 202000                                                                                                                           
  real(8) :: e_in(nmax) = 0.D0                                                                                                                                  
  integer i                                                                                                                                                     

call omp_set_num_threads(2)                                                                                                                                     
!$omp parallel default(firstprivate)                                                                                                                            
!$omp do                                                                                                                                                        
  do i=1,2                                                                                                                                                      
     print *, e_in(i)                                                                                                                                           
     print *, eTDSE(i)                                                                                                                                          
  end do                                                                                                                                                        
!$omp end do                                                                                                                                                    
!$omp end parallel                                                                                                                                              
end program main

モジュール:

module my_module                                                                                                                                                
  implicit none                                                                                                                                                 

  integer, parameter, private :: ntmax = 202000                                                                                                  
  double complex :: eTDSE(ntmax) = (0.D0,0.D0)                                                                                                                  
!$omp threadprivate(eTDSE)                                                                                                                                      

end module my_module

を使用してコンパイル:

ifort -openmp main.f90 my_module.f90

実行時にセグメンテーション違反が発生します。メインプログラムの印刷コマンドの1つを削除すると、正常に実行されます。また、omp関数を削除し、-openmpオプションなしでコンパイルすると、正常に実行されます。

4

2 に答える 2

30

この動作の最も可能性の高い原因は、スタックサイズの制限が小さすぎることです(何らかの理由で)。は各OpenMPスレッドにプライベートであるためe_in、スレッドごとに1つのコピーがスレッドスタックに割り当てられます(指定した場合でも-heap-arrays!)。テイク1616kB(または1579 KiB)202000の要素。REAL(KIND=8)

スタックサイズの制限は、いくつかのメカニズムによって制御できます。

  • 標準のUnixシステムシェルでは、スタックサイズの量は。によって制御されulimit -s <stacksize in KiB>ます。これは、メインのOpenMPスレッドのスタックサイズ制限でもあります。この制限の値は、POSIXスレッド(pthreads)ライブラリによって、新しいスレッドを作成するときのデフォルトのスレッドスタックサイズとしても使用されます。

  • OpenMPは、環境変数を介して、すべての追加スレッドのスタックサイズ制限の制御をサポートしますOMP_STACKSIZE。その値は、オプションの接尾辞k/ K(KiBの場合)、m/ Mf(MiBの場合)、またはg/ G(GiBの場合)が付いた数値です。この値は、メインスレッドのスタックサイズには影響しません。

  • GNU OpenMPランタイム(libgomp)は、非標準の環境変数を認識しますGOMP_STACKSIZE。設定すると、の値が上書きされますOMP_STACKSIZE

  • Intel OpenMPランタイムは、非標準の環境変数を認識しますKMP_STACKSIZE。設定すると、の値が上書きされ、互換性のあるOpenMPランタイムが使用されている場合OMP_STACKSIZEの値も上書きGOMP_STACKSIZEされます(現在利用可能なIntel OpenMPランタイムライブラリはcompat1つだけであるため、これがデフォルトです)。

  • 変数が設定されていない場合*_STACKSIZE、IntelOpenMPランタイムのデフォルトは2m32ビットアーキテクチャと4m64ビットアーキテクチャです。

  • Windowsでは、メインスレッドのスタックサイズはPEヘッダーの一部であり、リンカーによってそこに埋め込まれます。Microsoftを使用LINKしてリンクを行う場合、サイズはを使用して指定されます/STACK:reserve[,commit]reserve引数は最大スタックサイズをバイト単位で指定し、オプションの引数commitは初期コミットサイズを指定します。0xどちらもプレフィックスを使用して16進値として指定できます。実行可能ファイルの再リンクがオプションでない場合は、PEヘッダーを。で編集することでスタックサイズを変更できますEDITBIN。リンカと同じスタック関連の引数を取ります。MSVCのプログラム全体の最適化を有効にしてコンパイルされたプログラム(/GL)は編集できません。

  • --stackWin32ターゲット用のGNUリンカーは、引数を介したスタックサイズの設定をサポートしています。オプションをGCCから直接渡すには、-Wl,--stack,<size in bytes>を使用できます。

スレッドスタックは、実際にはによって設定されたサイズ(またはデフォルト値)で割り当てられる*_STACKSIZEことに注意してください。メインスレッドのスタックは小さく始まり、要求に応じて設定された制限まで増加します。*_STACKSIZEしたがって、任意の大きな値に設定しないでください。設定すると、プロセスの仮想メモリのサイズ制限に達する可能性があります。

ここではいくつかの例を示します。

$ ifort -openmp my_module.f90 main.f90

メインスタックサイズの制限を1MiBに設定します(追加のOpenMPスレッドはデフォルトで4 MiBを取得します):

$ ulimit -s 1024
$ ./a.out
zsh: segmentation fault (core dumped)  ./a.out

メインスタックのサイズ制限を1700KiBに設定します。

$ ulimit -s 1700
$ ./a.out
  0.000000000000000E+000
 (0.000000000000000E+000,0.000000000000000E+000)
  0.000000000000000E+000
 (0.000000000000000E+000,0.000000000000000E+000)

メインスタックサイズの制限を2MiBに設定し、追加スレッドのスタックサイズを1MiBに設定します。

$ ulimit -s 2048
$ KMP_STACKSIZE=1m ./a.out
zsh: segmentation fault (core dumped)  KMP_STACKSIZE=1m ./a.out

ほとんどのUnixシステムでは、メインスレッドのスタックサイズ制限はPAMまたは他のログインメカニズムによって設定されます(を参照/etc/security/limits.conf)。ScientificLinux6.3のデフォルトは10MiBです。

エラーにつながる可能性のある別のシナリオは、仮想アドレス空間の制限が低すぎる場合です。たとえば、仮想アドレス空間の制限が1 GiBで、スレッドスタックサイズの制限が512 MiBに設定されている場合、OpenMPランタイムは追加のスレッドごとに512MiBを割り当てようとします。2つのスレッドでは、スタックのみに1 GiBがあり、コード、共有ライブラリ、ヒープなどのスペースを合計すると、仮想メモリのサイズが1 GiBを超えて大きくなり、エラーが発生します。

仮想アドレス空間の制限を1GiBに設定し、512 MiBスタックの2つの追加スレッドで実行します(への呼び出しをコメントアウトしましたomp_set_num_threads())。

$ ulimit -v 1048576
$ KMP_STACKSIZE=512m OMP_NUM_THREADS=3 ./a.out
OMP: Error #34: System unable to allocate necessary resources for OMP thread:
OMP: System error #11: Resource temporarily unavailable
OMP: Hint: Try decreasing the value of OMP_NUM_THREADS.
forrtl: error (76): Abort trap signal
... trace omitted ...
zsh: abort (core dumped)  OMP_NUM_THREADS=3 KMP_STACKSIZE=512m ./a.out

この場合、OpenMPランタイムライブラリは新しいスレッドの作成に失敗し、プログラムの終了を中止する前に通知します。

于 2012-11-07T09:20:02.017 に答える
11

セグメンテーション違反は、OpenMP使用時のスタックメモリ制限が原因です。前の回答の解決策を使用しても、WindowsOSで問題が解決しませんでした。スタックメモリではなくヒープへのメモリ割り当てを使用すると、うまくいくようです。

integer, parameter :: nmax = 202000  
real(dp), dimension(:), allocatable :: e_in
integer i

allocate(e_in(nmax))

e_in = 0

! rest of code

deallocate(e_in)

さらに、これにはデフォルトの環境パラメータの変更は含まれません。

ここでのohm314のソリューションに対する謝辞と参照:ヒープメモリ割り当てを使用した大規模アレイ

于 2016-05-24T02:47:23.723 に答える