ここではもっともシンプルだがもっとも有名な C プログラム、"Hello, World" がどのように MPC++ プログラムに変換されるかを示します。
#include <stdio.h> main(int argc, char **argv) { printf("hello, world\n"); exit(0); }
まず、インクルードファイル mpcxx.h
を加える必要があります。次に、main()
関数のはじめで mpcxx_initialize()
関数を呼ばなければなりません。本質的にやらなければならないことはこれで全てです。
#include <stdio.h> #include <mpcxx.h> main(int argc, char **argv) { mpcxx_initialize(argc, argv); printf("hello, world\n"); exit(0); }
MPC++ プログラムのコンパイルは普通の C/C++ のコンパイルと同じくらい簡単です。上で書きなおした MPC++ プログラムが hello.cc として保存されたとしましょう。MPC++ コンパイラは拡張子が .cc のソースファイルのみを受け付けるので、ファイル名 hello.c ではコンパイルできません。
$ mpc++ hello.cc compiling hello.cc $
普通の C/C++ コンパイラと同じように、MPC++ コンパイラは a.out という名前の実行ファイルを生成します。MPC++ コンパイラは C/C++ コンパイラの受け付けるほとんどのオプションを受け付けます。
最初に、以下のように msgb を起動してクラスタ内の空いているホストを見つけることができます:
$ msgb -group pcc &
次に、プログラムを走らせるクラスタホストを示すグループ名を指定して scout
を呼び出します。グループ名はデータベース scorehosts.db(5) で定義します。
$ scout -g pcc SCOUT: Spawn done. SCOUT: session started $新しいシェルプロセスが
scout
プログラムの子プロセスとして生成されます。msgb
が既に起動している場合、scout
がリモートプロセスを呼び出している間、msgb
ウィンドウ内のいくつかのホストあるいは全てのホストが赤に変わります。scout
プログラムを起動するホストはクラスタ内のホストである必要はありません。
これでようやくプログラムを起動することができます:
$ scrun ./a.out SCORE: connected (jid=100) <0:0> SCORE: Single host, single process ready. hello, world $普通の C/C++ プログラムの出力と同じ結果が得られるはずです。
msgb
が既に起動していれば、クラスタ上でプログラムを起動している間、msgb
ウィンドウ内のいくつかあるいは全てのホストが赤に変わります。msgb
ウィンドウは、クラスタ上で誰がプログラムを起動していているか知らせます。ホスト上で同時に複数のプログラムが起動されないようにホストがロックされます(同一ホスト上で複数のプログラムを実行するには SCore-D の複数ユーザモードを使用してください)。
上の例では、プログラムは一つのホスト(ノード)で起動されました。プログラムを複数のノード上で起動するには、-noes=
N を scrun
のオプションとして指定してください(N はプログラムを走らせたいノードの数です)。
$ scrun -nodes=2 ./a.out SCORE: connected (jid=100) <0:0> SCORE: 2 hosts, single process/host ready. hello, world $結果は一台のホストで動かしたときと全く同じです。何が間違っているのでしょうか?この例では、MPC++ ランタイムライブラリの
mpcxx_initialize()
関数はノード番号 0 として割り当てられたホスト上でのみリターンし、他のノードは idle 状態になっていました。並列で hello プログラムを実行させるには、MPC++ の初期化関数を mpcxx_initialize()
から mpcxx_spmd_initialize()
に変える必要があります。
#include <stdio.h> #include <mpcxx.h> main(int argc, char **argv) { mpcxx_spmd_initialize(argc, argv); printf("hello, world\n"); exit( 0 ); }
修正したファイルをコンパイルするのを忘れないでください。再度ためしてみましょう:
$ scrun -nodes=2 ./a.out SCORE: connected (jid=100) <0:0> SCORE: 2 hosts, single process/host ready. hello, world hello, world $
今度は二つの結果が得られました。mpcxx_spmd_initialize()
関数が各ホスト上でリターンしたからです。四つのノードを指定すれば、四つの結果が得られるはずです。確認するために、hello プログラムに少し修正を加えます:
#include <stdio.h> #include <mpcxx.h> main(int argc, char **argv) { mpcxx_spmd_initialize(argc, argv); printf("hello, world (from node %d)\n", myNode); exit( 0 ); }
変数 myNode
は MPC++ ランタイムライブラリで定義されていて、ノード番号が収められています。整数変数 numNode
は並列実行用に割り当てられたノードの数を示します。numNode
の値がコマンドラインから指定されたノード数と異なる場合があることに注意してください。従って、どんな MPC++ プログラムも numNode
に特定の値が入っていることを仮定してはなりません。プログラムが特定のノード数でしか動作できない場合には、プログラム中の mpcxx_(spmd_)initialize
を呼んだ直後で numNode
の値をチェックしてください。
修正を加えたプログラムを四つのノードで動かしてみましょう。
$ scrun -nodes=4 ./a.out SCORE: connected (jid=100) <0:0> SCORE: 4 hosts, single process/host ready. hello, world (from node 0) hello, world (from node 2) hello, world (from node 1) hello, world (from node 3) $
今度は四つの結果が得られ、たしかに各ノードから一つずつの結果が得られています。結果の順序に注意してください。main()
関数の本体が各ホスト上で並列に呼ばれ実行されるため、どのノードの結果が一番最初になるか、などといったことは予測できません。これは並列計算の特質です。
この scout
セッションを終えるには、シェルを抜けてください。
$ exit SCOUT: session done $
/opt/score/example/mttl
ディレクトリの下にあります:
ainvoke.cc | リモートスレッド呼び出しのラウンドトリップタイムを計測します |
burst.cc | ノード間のバンド幅を計測します |
関連項目
![]() |
PCクラスタコンソーシアム |