4. Tips

4.1. 一部のコードをネイティブコンパイラでコンパイルする場合

ネイティブコンパイラで作成したオブジェクトファイルとOmni Compilerで作成したオブジェクトファイルとはリンクすることが可能である.ただし,下記の制限がある.

4.1.1. C言語の場合

例えば a.cb.c という2つのコードがあり, a.c はネイティブコンパイラ(ここでは mpicc )を用いて, b.c はOmni Compiler(ここでは xmpcc )を用いてコンパイルしたい場合は,下記のように個別に行うことが可能である.ただし,リンクには必ずOmni Compilerを利用する必要がある.

$ mpicc a.c -c
$ xmpcc b.c -c
$ xmpcc a.o b.o

4.1.2. Fortranの場合

基本的にはC言語と同様であるが,モジュールの利用についてのみ注意が必要になる.Omni Compilerでは, .xmod ファイルという特殊なファイルを使って,モジュールの利用を行っている.そのため,例えばgfortranを使って通常の .mod ファイルを作成しても,その .mod ファイルはOmni Compilerからは利用することはできない.

そこで,Omni Compilerは .mod ファイルを .xmod ファイルに変換するコマンド T_Module を提供している. T_Module はgfortran-4.4, 4.7, 4.9が作成した .mod ファイルの変換に対応している.

./configure--enable-mod2xmod オプションをつけることで, T_Module がOmni Compilerと同時にビルドされる.なお, T_Module のビルドには, mpfrgmp が必要である.

$ ./configure --enable-mod2xmod

例えば, test.modtest.xmod というOmni Compiler用のモジュールファイルに変換する場合,下記のように実行する.

$ T_module test.mod

4.2. MPIプログラムからXMPプログラムを呼び出す方法

Omni Compilerが用意している関数xmp_init()とxmp_finalize()をMPIプログラムに挿入する.xmp_initの引数で指定したMPIコミュニケータで,XMPプログラムは動作する.

#include "xmp.h"

int main(int argc, char **argv)
{
  MPI_Init(&argc, &argv);
  xmp_init(MPI_COMM_WORLD);
  foo();   // foo() is an XMP program
  xmp_finalize();
  MPI_Finalize();

  return 0;
}
program test
  include 'mpif.h'
  integer ierror

  call MPI_INIT(ierror)
  call xmp_init(MPI_COMM_WORLD)
  call foo()  ! foo is an XMP program
  call xmp_finalize()
  call MPI_FINALIZE(ierror)
end program test

MPIプログラムはMPIコンパイラでコンパイルし,XMPプログラムはXMPコンパイラでコンパイルする.リンカにはXMPコンパイラを利用する.

$ mpicc mpi.c -c
$ xmpcc xmp.c -c
$ xmpcc mpi.o xmp.o

4.3. インストールが失敗する場合

4.3.1. MPIへのPATHの確認

which コマンドを使って,MPIへの PATH が設定されているかを確認する.下記はDebian GNU/Linux 8.3においてOpenMPIを aptitude コマンドでインストールした場合の例である.

% which mpicc
/usr/bin/mpicc

もし,MPIへの PATH が設定されていなければ, which コマンドは何も出力しない.

なお,CentOS 7においてOpenMPIを yum でインストールした場合,OpenMPIは /usr/lib64/openmpi/ にインストールされる.そのため,手動で下記のように PATH を設定する必要がある.

$ export PATH=/usr/lib64/openmpi/bin:$PATH

4.4. mpi-conduit以外のGASNetを用いた場合の注意点

mpi-conduit以外のGASNetを用いる場合,GASNetの制約(詳細は GASNetのREADME の"MPI Interoperability"を参照)のため,GASNetによる通信(Coarray,post/wait/lock/unlock指示文)とMPIによる通信(post/wait/lock/unlock指示文以外の通信指示文.例えば,bcast指示文など)がネットワーク上で同時に発生することは許していない.

そのため,GASNetとMPIの2種類の通信が同時に発生しないようにする必要がある.具体的には,GASNetによる通信の後に,XcalableMP/Cの場合は関数 xmp_sync_all() ,XcalableMP/Fortranの場合は sync all 文を挿入する.同様にMPIによる通信の後は, barrier 指示文を挿入する.

  • XcalableMP/C
// (GASNetによる通信)

xmp_sync_all(&status)

// (MPIによる通信)

#pragma xmp barrier

// (GASNetによる通信)
  • XcalableMP/Fortran
! (GASNetによる通信)

sync all

! (MPIによる通信)

!$ xmp barrier

! (GASNetによる通信)

4.5. Omni Compilerのテスト

omnni compilerでは,Omni Compilerが正常に動作するかを確かめるためのテストプログラムを用意している.テストプログラムのコンパイルと実行には,Omni Compilerのインストールおよび PATH の設定後に下記のコマンドを実行する.

$ make tests  // テストプログラムのコンパイル
$ make run-tests  // テストプログラムの実行
$ make clean-tests // テストプログラムのバイナリの削除

make tests コマンドは, ./test ディレクトリ以下にテストプログラムを生成する. make run-tests コマンドによるテストプログラムの実行はローカルノードで行われるため,クロスコンパイラを用いている場合は make run-tests コマンドによるテストプログラムの実行を行うことはできない.クロスコンパイラを用いている場合でテストの実行を行いたい場合は, ./test ディレクトリ以下のテストプログラムに対してユーザが直接計算ノードで実行を行う必要がある.

4.6. プロファイリングツールとの連携

Omni Compilerには,プロファイリングツールであるScalasca(version 1.4.3で動作確認)およびtlogとの連携機能がある.本機能は,XcalableMPの下記指示文の実行に要する時間などを計測することができる.本機能は現時点ではXcalableMP/Cのみの対応である.

  • loop
  • reduction
  • gmove
  • bcast
  • reflect
  • barrier
  • task

4.6.1. Scalascaを用いたプロファイリング

まずScalascaをインストールし,Scalacaへの PATH を設定する.

コードに存在するすべての指示文についてプロファイリングをとりたい場合は,--profile scalasca オプションをつけてコンパイルを行い,実行する.

$ xmpcc --profile scalasca a.c

特定の指示文にのみプロファイルをとりたい場合は,その指示文に profile という節を追加し, --selective-profile scalasca オプションをつけてコンパイルを行い,実行する.

#pragma xmp bcast (a) profile
$ xmpcc --selective-profile scalasca a.c

Scalascaを用いたプロファイリング方法の詳細は Scalascaの公式サイト を参考のこと.

_images/scalasca.png

4.6.2. tlogを用いたプロファイリング

tlogはOmni Compilerのインストール時に自動的にインストールされる.

コードに存在するすべての指示文についてプロファイリングをとりたい場合は, --profile tlog オプションをつけてコンパイルを行い,実行する.

$ xmpcc --profile tlog a.c

特定の指示文にのみプロファイルをとりたい場合は,その指示文に profile という節を追加し, --selective-profile tlog オプションをつけてコンパイルを行い,実行する.

#pragma xmp bcast (a) profile
$ xmpcc --selective-profile tlog a.c

プログラム実行後に, trace.log というプロファイル結果が保存されたファイルが生成される.プロファイル結果を閲覧する場合は, tlogview コマンドを用いる.

$ tlogview trace.log
_images/tlog.png

4.7. XMP Pythonパッケージの使い方

PythonプログラムからXMPプログラムを呼び出すことができる.現時点ではXMPプログラムはC言語のみの対応である.

4.7.1. Omni Compilerのインストール

--enable-shared オプションをつけ,XMPの共有ライブラリを生成する. (INSTALL PATH) には,インストール先を指定する.

$ ./configure --enable-shared --prefix=(INSTALL PATH)

4.7.2. XMPプログラムの例

// test.c
#include <stdio.h>
#include <xmp.h>
#pragma xmp nodes p[*]

void hello0(){
  printf("Hello 0 on node p[%d]\n", xmp_node_num());
}

void hello1(long a[3]){
  printf("Hello 1 on node p[%d]\n", xmp_node_num());
}

void hello2(long a[3], long b[2]){
  printf("Hello 2 on node p[%d]\n", xmp_node_num());
}

4.7.3. PythonプログラムからXMPプログラムをコールする場合

Pythonプログラムでは,xmpおよびmpi4pyパッケージを用いる.

# test.py
import xmp
from mpi4py import MPI

lib  = xmp.Lib("test.so")
job0 = lib.call(MPI.COMM_WORLD, "hello0")
job1 = lib.call(MPI.COMM_WORLD, "hello1", [1,2,3])
job2 = lib.call(MPI.COMM_WORLD, "hello2", ([1,2,3], [4,5]))

callメソッドは指定したXMPプログラムを並列実行させる.第1引数はMPIコミュニケータであり,これはXMPプログラムのnode setとして用いられる.第2引数はXMPプログラムの関数名である.第3引数はXMPプログラムに渡される引数である(省略可能).もし複数の引数を渡したいときはタプルを用いる.

4.7.4. PythonプログラムからXMPプログラムをスポーンする場合

import xmp

lib = xmp.Lib("test.so")
job0 = lib.spawn(4, "hello0")
job1 = lib.spawn(4, "hello1", [1,2,3])
job2 = lib.spawn(4, "hello2", ([1,2,3], [4,5,6]), async=True)
job2.wait()

spawnメソッドは指定したXMPプログラムをスポーンさせる.第1引数はプロセス数であり,この並列数でXMPプログラムは起動する.第2引数はXMPプログラムの関数名である.第3引数はXMPプログラムに渡される引数である(省略可能).もし複数の引数を渡したいときはタプルを用いる.さらにasync=Trueが指定された場合は,XMPプログラムは非同期で実行される.waitメソッドで非同期実行しているXMPプログラムの終了を待つ.

4.8. XMPプログラムの共有ライブラリの生成

共有ライブラリの生成オプションはネイティブコンパイラに依存する.gccの場合は -fPIC -shared である.

$ xmpcc -fPIC -shared test.c -o test.so

Pythonの環境変数 PYTHONPATH を用いて,XMPのPythonパッケージへのPATHを指定する.また,環境変数 LD_LIBRARY_PATH を用いて,XMPの共有ライブラリへのPATHを指定する.

$ export PYTHONPATH=(INSTALL PATH)/lib
$ export LD_LIBRARY_PATH=(INSTALL PATH)/lib:$LD_LIBRARY_PATH
$ mpirun -np 2 python ./test.py