2012-11-07 52 views
9

メインプログラム:このopenmpコードでセグメンテーションフォルトが発生しているのはなぜですか?

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オプションを指定せずにコンパイルしても、うまく動作します。

答えて

16

この現象の最も一般的な原因は、(何らかの理由で)スタックサイズの制限が小さすぎることです。 e_inはOpenMPスレッドごとにプライベートなので、スレッドスタックに1つのコピーが割り当てられます(-heap-arraysを指定した場合でも!)。 202000の要素がREAL(KIND=8)の場合、1616 kB(または1579 KiB)を消費します。

スタックサイズ制限は、いくつかのメカニズムによって制御することができる:スタックサイズの量をulimit -s <stacksize in KiB>によって制御される標準的なUNIXシステムシェルで

  • 。これは、メインOpenMPスレッドのスタックサイズの制限です。この制限の値は、新しいスレッドを作成するときに、デフォルトのスレッドスタックサイズとしてPOSIXスレッド(pthreads)ライブラリによっても使用されます。

  • OpenMPは、すべてスレッドのスタックサイズ制限を、環境変数OMP_STACKSIZEで制御することができます。その値は、KiBの場合はk/K、MiBの場合はm/M、添え字の場合はg/G(GiBの場合)です。この値は、ではメインスレッドのスタックサイズに影響しません。

  • GNU OpenMP実行時(libgomp)は、標準外の環境変数GOMP_STACKSIZEを認識します。設定すると、OMP_STACKSIZEの値が無効になります。

  • Intel OpenMPの実行時には、標準外の環境変数KMP_STACKSIZEが認識されます。これが設定されている場合は、OMP_STACKSIZEの値を上書きし、互換性のあるOpenMPの実行時間が使用されている場合はGOMP_STACKSIZEの値を上書きします(現在のところ、インテル®OpenMPランタイム・ライブラリーの唯一のものはcompatです)。

  • *_STACKSIZE変数のいずれも設定されていない場合は、インテルのOpenMPの実行時のデフォルトは32ビットアーキテクチャ上2mと64ビットのもので4mです。

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

  • Win32ターゲットのGNUリンカは、--stack引数を使用してスタックサイズを設定できます。オプションをGCCから直接渡すには、-Wl,--stack,<size in bytes>を使用できます。スレッド・スタックは、実際小さい開始し、セットまで必要に応じて成長するメインスレッドのスタックとは異なり、*_STACKSIZE(またはデフォルト値)で設定されたサイズでを割り当てられること

注制限する。したがって、*_STACKSIZEに任意の大きな値を設定しないと、プロセスの仮想メモリサイズ制限が発生する可能性があります。ここで

は、いくつかの例です:

$ ifort -openmp my_module.f90 main.f90 

(デフォルトどおり4のMIBになるだろう、追加のOpenMPスレッド)1 MIBへのメインスタックのサイズの上限を設定:

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

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

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

メインスタックサイズ制限を2 MiBに設定し、a 1 MIBへdditionalスレッド:ほとんどのUnixシステムで

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

メインスレッドのスタックサイズ制限をPAMまたは他のログイン機構(/etc/security/limits.confを参照)によって設定されます。 Scientific Linux 6.3のデフォルトは10 MiBです。

エラーにつながる可能性のあるもう1つのシナリオは、仮想アドレス空間の制限値が低すぎる場合です。たとえば、仮想アドレス空間の制限が1 GiBで、スレッド・スタック・サイズの制限が512 MiBに設定されている場合、OpenMPの実行時には、追加のスレッドごとに512 MiBが割り当てられます。 2つのスレッドを使用すると、スタックのGiBが1つしかなく、コード、共有ライブラリ、ヒープなどの領域が合計されると、仮想メモリのサイズは1 GiBを超えて増加し、エラーが発生します。

1ジブに仮想アドレス空間の制限を設定し、512個のMIBスタックを持つ2つの追加のスレッド(私はomp_set_num_threads()への呼び出しをコメントアウトしている)を使用して実行:OpenMPの実行時ライブラリを作成するために失敗するだろう。この場合

$ 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 

新しいスレッドを作成し、プログラムの終了を中止する前に通知します。

+0

私は、これらの配列は、ちょうど2つの要素であると考え、ことを逃しました。とにかく私はしばしば-fstack-arraysを使って配列の大きさを大きくしています。しかし、Ifortではなく。 –

+0

'gfortran'と' ifort'の両方で、静的配列のプライベートコピーは、通常の配列の配置に影響を与える可能性のあるコンパイラオプションにもかかわらずスレッドスタックに常に自動的に割り当てられます。 –

4

セグメンテーションフォルトは、OpenMPを使用する場合のスタックメモリの制限によるものです。以前の回答の解決策を使用しても、私のWindows OSで私の問題は解決されませんでした。

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のソリューションを参照してください:large array using heap memory allocation

+1

メインスレッドのWindowsアプリケーションのスタックサイズはリンク時に指定されているため、後でほとんどのUnixシステムと同様に自由に制御することはできません。私の答えはUnix固有のものです。私はWindowsについてのセクションを追加します。もちろん、ヒープ割り当ては、実際にコードを変更する余裕がない場合を除いて、最良の解決策です。 –

関連する問題