MPC++ MTTL − はじめに


このドキュメントでは以下のことについて記述しています。 以下の例では SCore ユーザーズガイド内の はじめに で記述されているユーザ環境を想定しています。


"Hello World" プログラムを MPC++ に書きなおす

ここではもっともシンプルだがもっとも有名な 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=Nscrun のオプションとして指定してください(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-ult ディレクトリの下にあります:

ainvoke.ccリモートスレッド呼び出しのラウンドトリップタイムを計測します
burst.ccノード間のバンド幅を計測します

関連項目

SCore クラスタソフトウェアシステムリファレンスガイド


PCCC logo PCクラスタコンソーシアム

CREDIT
This document is a part of the SCore cluster system software developed at PC Cluster Consortium, Japan. Copyright (C) 2003 PC Cluster Consortium.