2GB以上 アドレス空間 コンパイルオプション
PGI 64 ビット対応 Linux 版の製品における F77, F2003, C/C++ のコンパイラを使用して、2GB 以上の静的割付けされた単一オブジェクトがある場合のコンパイル・オプションの例を示します。2GB 以上のメモリ空間を利用する場合に必要なオプションです。ここでの説明は、Linux のみに適用できるものであり、Windows® や OS X においては、、「2GB以上の静的割付けの単一オブジェクト」を扱うことができる -mcmodel=medium と等価なプログラミングモデルは提供されていません。
2013年3月26日更新 Copyright © 株式会社ソフテック
まず始めに、Linux 以外の OS 上での取り扱いについて説明します。Windows x64上、並びに Apple OS X 64bit 上では、「2GB以上の単一オブジェクト」を扱うことができる -mcmodel=medium オプションと等価な機能を提供しておりません。これは、Microsoft® Win64 プログラミング・モデルが、2GB を超える静的な単一データ・オブジェクトのハンドリングをサポートしていないためです。従って、単一あるいは、メモリ空間総量が 2GB を超える静的配列を扱うようなプログラムでは制約があります。例え Windows 64ビット版であっても、2GBを超える単一配列オブジェクトがプログラム上に存在する場合、静的な配列宣言はできません。これを回避する方法として、静的配列宣言を動的な配列宣言(Allocatable 配列宣言)に変更する方法がありますが、プログラムの改修が伴います。こうした制約は、PGI コンパイラの制約ではなく、Win64 プログラミングモデル上の制約です。Apple Mac OS 上においても、同様な理由で、2GB を超える静的な単一データオブジェクトを使用できません。従って、2GB以上のデータオブジェクトを扱うプログラムをコンパイルする場合は、現在のところ、このような制約がない Linux 版の方が適しています。
以上の制約は、あくまでも 2GB 以上の静的配列を扱う場合のものですが、動的な配列宣言の配列を使用することにより、Windows(64bit) / OS X でも 2GB 以上のメモリ空間を使用することができます。特に Win64 上では、2GB 以上のアドレッシング(インデックスの計算)の処理を有効にするためのオプションがあります。Win64環境でのPGIコンパイラでは、以下のオプション(-Mlargeaddressaware) を付加することにより、アプリケーションが 2 GB を超えるアドレスを処理することをリンカに知らせることができます。これについては、マイクロソフト社のページを参照して下さい。なお、OS X には、こう言った類のオプションは存在しません。
pgfortran -Minfo -fastsse -Mlargeaddressaware -Mlarge_arrays test.f90 コンパイル時、リンク時共に指定して下さい。
マイクロソフト Windows 環境では、「静的な メモリallocation」領域は 64bit OS環境であっても 2GB 以内の領域しか使えません。これはマイクロソフト Windows の仕様です。プログラムどのような宣言を行うかによってメモリ配置が異なり、さらに、静的変数配列であればその最大長は 2GB に制約されることになります。 64-bitWindows の場合、プログラム上では以下のようなデータ割付制限があります。
Fortran の場合
C/C++の場合
大規模な静的配列を ALLOCATABLE 配列で置き換え、プログラムの開始時に目的のサイズに割り当てる方法をとります。
例えば、
double precision a(n,n,n), b(n,n,n)
あるいは、
real*8 a(n,n,n), b(n,n,n)
と言った静的に割り当て宣言された配列で、そのサイズが大きくなりそうな配列に限って、プログラムを修正する必要があります。静的から動的割付の方法で配列の割付を変更する必要があります。プログラムの実行時に allocation されるようにします。
real(8),allocatable,dimension(:,:,:) :: a , b
..
N = 20000
..
allocate(a(n,n,n), b(n,n,n))
...
pgf77/pgfortran -fastsse -mcmodel=medium -i8 test.f pgcc/pgc++ -fastsse -mcmodel=medium test.c
pgfortran -mcmodel=medium -i8 test.f
PGF77、pgfortran、PGCC、PGC++ は、x86-64 Application Binary Interface で定義されている、 -mcmodel=small 並びに -mcmodel=medium アドレッシング・モデルの両方をサポートします。次に示す表は、これらのプログラミング・モデルでの制約事項を示します。また、下表は様々なコンパイル/リンクオプションの組み合わせで32ビット、64ビット実行モジュールを作成した際の 32ビット、64ビットの処理形態を示しております。
Programming Models on 64-bit Linux86-64 Systems | ||||||
---|---|---|---|---|---|---|
Combined Options to PGI Compilers |
Address Arithmetic |
Maximum Data Size in Gbytes |
コメント | |||
A | I | AS | DS | TS | ||
-tp {32bit target} | 32 | 32 | 2 | 2 | 2 | 32bit linux86 互換 |
-tp {64bit target} | 64 | 32 | 2 | 2 | 2 | 64bit Addressing だが、メモリモデルは -mcmodel=small であり、データ領域は 2GB に制約される |
-tp {64bit target} -fpic | 64 | 32 | 2 | 2 | 2 | -mcmodel=medium を伴うコンパイルでは、-fpic は指定できない |
-tp {64bit target} -mcmodel=medium |
64 | 64 | >2 | >2 | >2 | 64ビットデータ・アドレッシングをフル・サポートする (-Mlarge_arraysオプションを包括している) |
-tp オプションは、明示的な CPU ターゲットを指定してクロスコンパイルを行うためのオプションです。デフォルトでは、コンパイルを行う「システム」のプロセッサ・ターゲットがその最適化のために使用され、かつ、当該システムの OS のビット数(64bit or 32bit)に応じた実行モジュールが生成されます。従って、64bit Linux のシステムの場合は、デフォルトで 64bit 実行バイナリが生成されますので、そのもとで、2GB 以上のメモリ空間を必要とするプログラムの場合は、上記の -mcmodel=medium を指定して下さい。
Address Type (A) | アドレス計算に使用されるデータのビット数のサイズ(32-bit or 64-bit) |
Index Arithmetic (I) | 配列並びに他のデータ構造のインデックス計算で使用されるデータのビット数のサイズ。もし I が 32bit の場合、単一データオブジェクトのサイズは、2GB に制約される。 |
Maximum Array Size (AS) | 任意の単一データオブジェクトの最大サイズ |
Maximum Data Size (DS) | 実行モジュールの中の .bss セクションにおける全てのデータオブジェクトの総和最大サイズ |
Maximum Total Size (TS) | 実行プログラムにおける全てのデータオブジェクトと実行テキスト・コードの総和した際の最大サイズ |
プログラムエリアとは、Linux オペレーティングシステムとユーザプログラムによって使用されるそれらが総和された領域です。ほとんどの 32ビットLinuxシステムでは、32ビットアドレッシングですので理論的には 2GB までアクセス可能ですが、通常 1GB のみがデータ領域として使用することができます。一方、64ビットシステム上でのデフォルトである small memory model の環境においても、ユーザデータあるいは実行モジュールの総和量は、1GB までに制約されます。これは、32ビットシステムと同様にシステム・ルーチンと共有ライブラリ、スタック等のアドレスが、2GB空間の内、その他の 1GB 領域を使用するため、この部分が Linux のカーネル管理領域として占有されます。但し、共有ライブラリを使用せず、静的なリンクにより固定アドレスで開始されるプログラムは、ほとんどの領域のメモリアクセス(2GB以内)が可能となります。
64ビットシステム上での medium memory model の環境を構築するためには、-mcmodel=medium オプションをコンパイル/リンク時に指定する必要があります。このメモリモデルでは、2GB以上のデータオブジェクト並びに .bss セクションのサイズであっても、問題なく動作します。
リンク時に、-mcmodel=medium オプションが必要となる生成実行モジュールにリンクされるオブジェクト・ファイルは、-mcmodel=medium オプションあるは、-fpic のどちらかでコンパイルされたものに限ります。-fpic オプションと -mcmodel=medium オプションを同時に使用してコンパイルすることはできません。すなわち、位置独立な実行モジュール (-fpic) の作成を行う場合は、-mcmodel=medium を使用することはできません。
64ビット環境における64ビットアドレッシング機能は、データサイズが非常に大きな場合、予期せぬ問題が生じる場合があります。
静的配列のサイズの総量が 2GB を越えた C プログラムの例で、セグメンテーションフォールトを起こしてみます。
● C プログラム bigadd.c
[kato@photon29 SAMPLES]$ cat bigadd.c #include <stdio.h> #define SIZE 600000000 /* > 2GB/4 */ static float a[SIZE], b[SIZE]; int main() { long long i, n, m; float c[SIZE]; /* goes on stack */ n = SIZE; m = 0; for (i = 0; i < n; i += 10000) { a[i] = i + 1; b[i] = 2.0 * (i + 1); c[i] = a[i] + b[i]; m = i; } printf("a[0]=%g b[0]=%g c[0]=%g\n", a[0], b[0], c[0]); printf("m=%lld a[%lld]=%g b[%lld]=%gc[%lld]=%g\n",m,m,a[m],m,b[m],m,c[m]); return 0; }
● Linux上で実行してみる
【コンパイル】 -mcmodel=mediumオプション [kato@photon29 SAMPLES]$ pgcc -mcmodel=medium -fastsse -Minfo bigadd.c main: 12, Loop not vectorized: mixed data types Loop not vectorized: may not be beneficial Unrolled inner loop 4 times 【実行】 [kato@photon29 SAMPLES]$ ./a.out Segmentation fault (セグメンテーションフォルト発生) 【コンパイル】 -Mchkstk(実行時のスタックサイズの出力)を追加し、ランタイムで stack sizeを把握する [kato@photon29 SAMPLES]$ pgcc -mcmodel=medium -fastsse -Minfo -Mchkstk bigadd.c main: 12, Loop not vectorized: mixed data types Loop not vectorized: may not be beneficial Unrolled inner loop 4 times [kato@photon29 SAMPLES]$ ./a.out Error: in routine main there is a stack overflow: thread 0, max 10228KB, used 0KB, request -1894967208B スタックサイズが足りないことが分かる。ここで表示されるサイズの量は、あまり厳密に考えない。 【現在のスタックサイズの把握(bash)】 [kato@photon29 SAMPLES]$ ulimit -s 10240 【スタックサイズの変更(bash) 3GB に変更後、実行】 [kato@photon29 SAMPLES]$ ulimit -s 3000000000 [kato@photon29 SAMPLES]$ ./a.out a[0]=1 b[0]=2 c[0]=3 m=599990000 a[599990000]=5.9999e+08 b[599990000]=1.19998e+09c[599990000]=1.79997e+09 実行モジュール a.out の bss セクションのサイズ表示(2GB を越えていることが分かる) [kato@photon29 SAMPLES]$ size --format=sysv a.out | grep bss .bss 4800000064 6295360 [kato@photon29 SAMPLES]$ size --format=sysv a.out | grep Total Total 4800003980
2GB を越えるFortranプログラムで -mcmodel=medium を指定して実行する
● Fortran プログラム mat.f90 (6GB 以上)
[kato@photon30 SAMPLES]$ cat mat.f90 program mat integer i, j, k, size, l, m, n parameter (size=16000) ! >2GB parameter (m=size,n=size) real*8 a(m,n),b(m,n),c(m,n),d do i = 1, m do j = 1, n a(i,j)=10000.0D0*dble(i)+dble(j) b(i,j)=20000.0D0*dble(i)+dble(j) enddo enddo !$omp parallel !$omp do do i = 1, m do j = 1, n c(i,j) = a(i,j) + b(i,j) enddo enddo !$omp do do i=1,m do j = 1, n d = 30000.0D0*dble(i)+dble(j)+dble(j) if(d .ne. c(i,j)) then print *,"err i=",i,"j=",j print *,"c(i,j)=",c(i,j) print *,"d=",d stop endif enddo enddo !$omp end parallel print *, "M =",M,", N =",N print *, "c(M,N) = ", c(m,n) end
● Linux上で実行してみる
【コンパイル】 -mcmodel=medium, -i8 オプション [kato@photon30 SAMPLES]$ pgfortran -mcmodel=medium -i8 -mp -fast -Minfo mat.f90 mat: 7, Loop interchange produces reordered loop nest: 8,7 Unrolled inner loop 4 times Used combined stores for 2 stores 14, Parallel region activated 16, Parallel loop activated with static block schedule Loop interchange produces reordered loop nest: 17,16 Generated an alternate version of the loop Generated vector sse code for the loop Generated 2 prefetch instructions for the loop 22, Barrier 23, Parallel loop activated with static block schedule 24, Loop not vectorized/parallelized: contains call 34, Barrier Parallel region terminated 【実行】 [kato@photon30 SAMPLES]$ ulimit -s (stacksize を調べる) 10240 [kato@photon30 SAMPLES]$ time ./a.out M = 16000 , N = 16000 c(M,N) = 480032000.0000000 real 0m2.832s user 0m7.645s sys 0m1.899s (a.out は 6GB 以上使用するプログラム) [kato@photon30 SAMPLES]$ size --format=sysv a.out | grep bss .bss 6144000416 6300672 [kato@photon30 SAMPLES]$ size --format=sysv a.out | grep Total Total 6144008305