-インテルコンパイラ・レシピ-
株式会社HPCソリューションズ
2013年03月18日
インテル®MICアーキテクチャ初の製品としてXeon Phi 5110Pが発売されました。 各メーカーからも搭載製品が順次発売される予定です。 今回はMICでのはじめてプログラミングを行うユーザに向けてインテルコンパイラの利用方法を紹介します。
MICのプログラミング手法として以下が可能です。
- OpenMPプログラミング
- MPIプログラミング
- OFFLOADプログラミング
実際にはこれらを混合したハイブリッドMPIプログラミングが実用的だと思います。 以降に、簡単な例を交えてコンパイルと実行方法を紹介します。 また、本書は既にMPSSパッケージとインテルコンパイラ2013(C++、Fortran)、及びインテルMPIライブラリ4.1がインストール済みであることを前提とします。
OpenMPプログラム
基本的にC、C++、FortranのプログラムはMIC用のオプションを付けてコンパイルし直すことで、MIC上で実行することが出来ます。 ここではインテルコンパイラに付属のCのOpenMPプログラムopenmp_sample.cの例を説明します。 まず、MICを搭載したサーバにログインし、openmp_sample.cを作業可能なディレクトリにコピーします。
[hpcs@server ~]$ cp /opt/intel/composerxe/Samples/ja_JP/C++/openmp_samples/openmp_sample.c .
コンパイルオプション「-mmic」と「-openmp」をつけてコンパイルします。
[hpcs@server ~]$ icc -mmic -openmp openmp_sample.c
「-mmic」はMIC用のオブジェクトを生成するためのコンパイルオプションです。
-mmic build an application that runs natively on Intel® MIC Architecture
「-openmp」はOpenMPのプログラムをコンパイルするためのオプションです。 最適化オプション「-O3」などは使用できますが、「-xHOST」などのベクトル化オプションは今のところサポートされていません。 コンパイル出来ると、実行モジュール a.out が作成されます。 実行するためにはa.outをMICへコピーします。 ただし、OpenMPのプログラムを実行する際には動的ライブラリlibiomp5.soが必要になるので、これも一緒にコピーします。
[hpcs@server ~]$ scp a.out mic0:
a.out 100% 39KB 39.0KB/s 00:00
[hpcs@server ~]$ scp /opt/intel/composerxe/lib/mic/libiomp5.so mic0:
libiomp5.so 100% 1039KB 1.0MB/s 00:00
MICにログインして実行します。動的ライブラリ読み込みのため、環境変数LD_LIBRARY_PATHを設定します。 またこのプログラムの場合、デフォルトのスタックサイズでは小さいため、無制限に変更しています。
[hpcs@server ~]$ scp $ ssh mic0
[hpcs@mic0 ~]$ export LD_LIBRARY_PATH=.
[hpcs@mic0 ~]$ ulimit -s unlimited
[hpcs@mic0 ~]$ ./a.out
Using time() for wall clock time
Problem size: c(600,2400) = a(600,1200) * b(1200,2400)
Calculating product 5 time(s)
We are using 240 thread(s)
Finished calculations.
Matmul kernel wall clock time = 1.00 sec
Wall clock time/thread = 0.00 sec MFlops = 17280.000000
OpenMPのスレッド数はMICの場合もOMP_NUM_THREADSで調整します。 上記の例では240スレッドで実行されています。 OMP_NUM_THREADSが設定されない場合は全コアを使用してスレッドを立てます。
※XeonPhi 5110Pは60コアを搭載していますが、各コアは4スレッドを同時実行できるため、MIC上のOSは240コアとして認識しています。
NFSマウント
インテルMPIライブラリはサーバとMICの間でMPIプログラムを実行することが出来ます。 しかしながら、先ほどのOpenMPプログラムの様に、プログラムを実行するのに必要なライブラリやファイルが複数あります。 いちいちMICにコピーするのは大変ですので、いっそサーバ上のインテルMPIのディレクトリをNFSマウントさせてしまいましょう。 普通のNFSマウントと若干手順が異なりますので注意して下さい。
インテルコンパイラ関連ツールは /opt/intel にインストールされているとします。 サーバにrootでログインし、このディレクトリを/etc/exportsに登録、NFSサービスを立ち上げます。
[root@server ~]# cat /etc/exports
/work *(rw,no_root_squash)
[root@server ~]# service nfs start
[root@server ~]# exportfs -v
/opt/intel (rw,wdelay,no_root_squash,no_subtree_check)
[root@server ~]# chkconfig nfs on
[root@server ~]# chkconfig –list nfs
nfs 0:off 1:off 2:on 3:on 4:on 5:on 6:off
クライアントの設定はサーバ側でmicctrlコマンドを使い行います。
[root@server ~]# micctrl –addnfs=/opt/intel –dir=/opt/intel
[root@server ~]# [root@f3k-phi ~]# tail -1 /opt/intel/mic/filesystem/mic0/etc/fstab
host:/opt/intel /opt/intel nfs nolock 1 1
NFSマウントオプションを変更したい場合は上記の/opt/intel/mic/filesystem/mic0/etc/fstabを修正して下さい。 これで設定は完了です。 設定を有効にするため、MPSSサービスを再起動します。 MPSSサービスの再起動はMICの再起動に相当しますので数分の時間がかかります。
[root@server ~]# service mpss restart
Shutting down MPSS Stack: [ OK ]
Starting MPSS Stack: [ OK ]
mic0: online (mode: linux image: /lib/firmware/mic/uos.img)
再起動出来たら/opt/intelがマウントされているか確認してください。
[root@server ~]# ssh mic0 df
Filesystem 1K-blocks Used Available Use% Mounted on
none 3941176 0 3941176 0% /dev
none 6700000 74696 6625304 1% /
none 3941176 0 3941176 0% /dev
tmpfs 3941176 0 3941176 0% /dev/shm
host:/opt/intel 1888795680 16441984 1776408384 1% /opt/intel
/opt/intelをNFSマウントすることで後述するインテルMPIは動作するようになります。 ただ、MIC上のLD_LIBRARY_PATHなどの環境変数設定はされていないので注意が必要です。 また、作業領域もNFSマウントしておいた方が実行モジュールをコピーする手間が省けます。 /homeはインストール時にMIC上に作成されてしまうので、/workとか/dataとかの作業用ディレクトリを別途作るのが便利でしょう。
micctrl –addnfs=[NFS export] –dir=[mount dir] [–server=[server name]] [MIC list]
Add the NFS export to the MIC card’s fstab. ‘NFS export’ is the NFS export to mount. The ‘-dir’ paramter specifies the mount point on the MIC card.
MPIプログラムの実行方法
サンプルプログラムを使って説明します。 サーバの作業可能なディレクトリに/opt/intel/impi/4.1.0/test/test.cをコピーして下さい。 以下の説明ではホームにコピーしています。
[hpcs@server ~]$ cp /opt/intel/impi/4.1.0/test/test.c .
サーバのCPUとMICのコアの両方を使う場合、それぞれの実行モジュールを作成する必要があります。 ここではMIC用の実行モジュールに拡張子「.mic」をつけます。
CPU用にコンパイル
[hpcs@server ~]$ mpiicc test.c -o test
MIC用にコンパイル
[hpcs@server ~]$ mpiicc -mmic test.c -o test.mic
これで実行モジュール「test」と「test.mic」が出来ました。これらを使い、以下の様に実行します。
[hpcs@server ~]$ scp test.mic mic0:
test.mic 100% 9991 9.8KB/s 00:00
[hpcs@server ~]$ export I_MPI_MIC=enable
[hpcs@server ~]$ mpirun -n 2 -host server ./test : -n 2 -host mic0 ./test.mic
Hello world: rank 0 of 4 running on server
Hello world: rank 1 of 4 running on server
Hello world: rank 2 of 4 running on mic0
Hello world: rank 3 of 4 running on mic0
先ほどMIC用コンパイルでは実行モジュール名の末尾に「.mic」をつけましたが、環境変数 I_MPI_MIC_POSTFIXを使用するとMIC用の実行モジュールはCPU用に「.mic」をつけたものとして認識します。 これによりマシンリストが使うことが出来、mpirun文が少し短くできます。 マシンリスト machinesにサーバとMICのホスト名を一行づつ書いて、以下の様に実行します。
[hpcs@server ~]$ cat machines
server
mic0
[hpcs@server ~]$ export I_MPI_MIC_POSTFIX=.mic
[hpcs@server ~]$ mpirun -f machines -ppn 2 ./test
Hello world: rank 0 of 4 running on server
Hello world: rank 1 of 4 running on server
Hello world: rank 2 of 4 running on mic0
Hello world: rank 3 of 4 running on mic0
「-ppn」は各ホストで指定したプロセス数を実行するmpirunのオプションです。
I_MPI_MIC=[value]
[value]:
enable | yes | on | 1 :
Enable the Intel(R) Xeon Phi(TM) coprocessor
recognition.
disable | no | off | 0:
Disable the Intel(R) Xeon Phi(TM) coprocessor
recognition.
I_MPI_MIC_POSTFIX=[value]
[value]: Specify a string as the postfix of an Intel(R) Xeon Phi(TM) coprocessor file name. The default value is an empty string.
OFFLOADプログラム
インテルコンパイラはCPU上で動かすプログラムから関数やループなどの一部をMICで実行させるためのディレクティブを実装しています。 まずは、これまで同様、サンプルプログラムを作業ディレクトリにコピーしましょう。
[hpcs@server ~]$ cp /opt/intel/composerxe/Samples/ja_JP/C++/mic_samples/LEO_tutorial/tbo_sort.c .
このサンプルプログラムはOpenMPで書かれたプログラムです。 OFFLOADのディレクティブを有効にするコンパイルオプションはありません。 デフォルトでOFFLOADが有効になります。 これはシリアル(非OpenMP)のプログラム、MPIのプログラムでも同様です。
hpcs@server ~]$ icc -openmp tbo_sort.c -o tbo_sort
[hpcs@server ~]$ export OFFLOAD_REPORT=1
[hpcs@server ~]$ ./tbo_sort.exe
C/C++ Tutorial: Offload Demonstration
Checking for Intel(R) Xeon Phi(TM) (Target CPU) devices…
Number of Target devices installed: 1
[Offload] [MIC 0] [File] tbo_sort.c
[Offload] [MIC 0] [Line] 182
[Offload] [MIC 0] [Tag] Tag0
[Offload] [MIC 0] [CPU Time] 0.000000 (seconds)
[Offload] [MIC 0] [MIC Time] 0.027028 (seconds)
[Offload] [MIC 0] [File] tbo_sort.c
[Offload] [MIC 0] [Line] 205
[Offload] [MIC 0] [Tag] Tag1
[Offload] [MIC 0] [CPU Time] 0.000000 (seconds)
[Offload] [MIC 0] [MIC Time] 0.000067 (seconds)
[Offload] [MIC 0] [File] tbo_sort.c
[Offload] [MIC 0] [Line] 235
[Offload] [MIC 0] [Tag] Tag2
[Offload] [MIC 0] [CPU Time] 0.000000 (seconds)
[Offload] [MIC 0] [MIC Time] 0.000049 (seconds)
Unsorted original values…first twenty (20) values:
Evens and Odds:
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
Sorted results…first ten (10) values each:
Evens: 2 4 6 8 10 12 14 16 18 20
Odds : 1 3 5 7 9 11 13 15 17 19 Primes: 2 3 5 7 11 13 17 19 23
ここでは実行時に環境変数OFFLOAD_REPORTを設定しました。 これにより実行時に「[Offload]」で始まる出力が追加されています。 MICでの実行時間などが表示されます。 OFFLOAD_REPORT=2にすればCPU→MICのデータ転送量も表示されます。 レポートはプログラムのOFFLOAD TARGET節の指定のある個所毎に表示されます。
OFFLOAD_REPORT=[value]
[value]:
1
Produces a report about time taken.
2
In additon to the information produced at value 1, adds the amount of data
transferred between the CPU and the coprocessor.
3
In addition to the information produced at value 2, gives additional
details on offload activity, including device initialization, and
individual variable transfers.
デバッグの際や、MIC非搭載サーバなどで実行する際にはOFFLOADを無効にするオプションを付けてコンパイルして下さい。
[hpcs@server ~]$ icc -no-offload -openmp tbo_sort.c -o tbo_sort
-no-offload disable any offload usage