ライブラリ MClib の基本的な使い方

開始と終了

M-Core 向けのアプリケーションは,ライブラリ MClib を使って記述します. MClib.h をインクルードしてください.
#include "MClib.h"
メイン関数の最初では MC_init 関数を必ず呼び出します. この関数を呼び出すことで,各ノードのノードIDとノードサイズを取得できます. ノードIDはx,yいずれも左上ノードが1となり, 右下ノードのノードIDはx,yともにノードサイズと等しくなります.
int id,x, id_y, rank_x, rank_y;
MC_init(&id_x, &id_y, &rank_x, &rank_y);
メイン関数の最後では MC_fini 関数を必ず呼び出します. 現時点ではこの関数は何の処理も行いませんが, 今後のバージョンで必須となる可能性があるためです.
MC_fini();
return 0;

DMAでデータを送信する

M-Coreでは,各ノードは独立したノードメモリを持つこととなっています. そのため,データの送受信は明示的に指定することが必要です. あるノードが持つデータを他のノードへ送信するためには, MC_setidxy 関数を使って送信先ノードを指定した後で, MC_dma_put 関数を使います.
MC_setidxy 関数は,送信先ノードIDを格納するint型ポインタと, 送信したいノードのx,y座標を引数に取ります. 例えば,送信先を(2, 4)の位置にあるノードに指定する場合は, 以下のように呼び出します.
int id;
MC_setidxy(&id, 2, 4);
MC_dma_put 関数は,送信先ノードID,送信先の転送開始位置を示すポインタ, 送信元の転送開始位置を示すポインタ,転送サイズ, 送信先のストライド,送信元のストライドを引数に取ります. 各ポインタおよび転送サイズは4の倍数を, ストライドは通常いずれも4を指定してください. 以下はサンプルのコードです.
#include "MClib.h"
volatile int a, b;

int main(int argc, char *args[])
{
    int id_x, id_y, rank_x, rank_y;
    MC_init(&id_x, &id_y, &rank_x, &rank_y);

    if (id_x == 1 && id_y == 1) {
        a = 1;
        b = 2;
        int dst = 0;
        setidxy(&dst, rank_x, rank_y);
        MC_dma_put(dst, &a, &b, 4, 4, 4);
    }
    MC_new_barrier();
    if (id_x == rank_x && id_y == rank_y) {
        printf("value of a = %d\n", a);
        printf("value of b = %d\n", b);
    }

    MC_finalize();

    return 0;
}
これにより,左上ノードの変数bの値が右下ノードの変数aにコピーされます. したがって,このプログラムの出力は以下の通りです.
value of a = 2
value of b = 0
なお,動的な変数(関数のローカル変数やmallocなどで確保するもの) のポインタを送信先の転送開始位置に指定しても,ほとんどの場合うまく行きません. 転送先ノードでその変数が同じアドレスに割り当てられている保証はないためです. 送信先の転送開始位置はグローバル変数か静的変数を使うべきです.
また,コンパイラの最適化によって一部のメモリの読み書きが冗長と見なされ, それらが削除されてしまうことにより問題が発生する場合があります. 以下のようなコードはその一例です.
static int flag;

// 何らかの処理

while (flag == 0); // 他のノードからフラグの書き換えを待つ???
このとき,コンパイラはflagの値をループ中に変化しないものとみなして, この記述を空の処理か,あるいは単純な無限ループに置換えるかもしれません. これは望まれる動作ではありません. このような最適化を抑制するために,他のノードから書き込まれるデータは volatile 修飾子をつけるべきです.

DMAでデータを受信する

上記の例と逆に,他のノードが持つデータを受信したい場合は, MC_dma_put 関数と同様のインタフェースで提供される MC_dma_get 関数を利用します. 以下はサンプルのコードです.
#include "MClib.h"
volatile int a, b;

int main(int argc, char *args[])
{
    int id_x, id_y, rank_x, rank_y;
    MC_init(&id_x, &id_y, &rank_x, &rank_y);

    if (id_x == 1 && id_y == 1) {
        a = 1;
        b = 2;
    }
    MC_new_barrier();
    if (id_x == rank_x && id_y == rank_y) {
        int dst = 0;
        setidxy(&dst, 1, 1);
        MC_dma_get(dst, &a, &b, 4, 4, 4);
        printf("value of a = %d\n", a);
        printf("value of b = %d\n", b);
    }

    MC_finalize();

    return 0;
}
これにより,右下ノードは左上ノードの変数aの値を取得し,変数bにコピーします. したがって,このプログラムの出力は以下の通りです.
value of a = 0
value of b = 1
get,putいずれの場合でも, 2番目の引数は外部ノードの転送開始位置を指すことに注意してください.