l'essentiel est invisible pour les yeux

Thursday, November 30, 2006

[Cell] Function-OffloadモデルでHello, World

Cellプログラミングにはいくつかのプログラミングモデルが存在する。
Cell上でのプログラミングモデルを順を追って紹介してみる。

第一回は、PPEとSPEの間でRemote Procedure Callを行うFunction-Offloadモデルと呼ばれるプログラミングモデルで一番単純なHello worldを書いてみた。このプログラミングモデルは、PPEからSPE上のプロシージャをPPE上で定義されたプロシージャのように呼び出すことが出来るRPCを実現する。

前回の記事、SPE上で実行時間を計測するでは、SPEの実行プログラムをオープンしSPEスレッドを作成して処理を実行し、そして処理が終了するのを待ってから、SPEプログラムハンドラを閉じて終了した。


spe_open_image();
spe_create_thread();
spe_wait();
spe_close_image();


Function-Offloadモデルでは、プログラム単位でSPEに処理をさせるのではなく、プロシージャ単位でSPUを使用して処理を並列化することを可能にする。Cell上ではスタブを利用することでMDAやMFCといった低レベルの詳細を知ることなく、PPE上からSPE上のプロシージャを実行することが可能になる。スタブがプロキシの役割を果たしPPEとSPEの通信の詳細であるDMA転送やMFCといった細かくて面倒な処理をラップしてくれる。

IDLのパラメータ定義やPPEからSPE上のプロシージャを呼び出すRPCの仕組みの詳細についてはとりあえず保留。

始めにプロシージャのインタフェースをIDLファイルで定義する。そのファイルをCBE SDKが提供するIDLコンパイラでコンパイルすることで、スタブクラスのソースコード(C言語)を作成してくれる。

初めに、IDLコンパイラの実行ファイルが存在しなかったのでビルドする。

% sudo yum install byacc flex
% cd /opt/IBM/cell-sdk-1.1/src/tools/idl
% make
% ls /opt/IBM/cell-sdk-1.1/host/bin/idl

/opt/IBM/cell-sdk-1.1/host/bin/idlという実行バイナリができあがる。

では、Function-Offload モデルを利用して"Hello World!"を書いていく。
始めに次のように作業用ディレクトリを作成する。ファイルについては順に作っていく。

% ls -FR
.:
Makefile hello.idl ppu/ spu/

./ppu:
Makefile hello.c

./spu:
Makefile hello.c
%

Function Offloadモデルでプログラミングを行うには、3つのソースファイルを作成する必要がある。
  • PPE上で実行するメインファイル
  • SPE上で実行するプロシージャ
  • プロシージャのインタフェースを定義したIDLファイルである。
始めに作業ディレクトリのトップディレクトリにhello.idlというファイルを作成する。
stub.hはIDLコンパイラにより自動生成される。

IDLファイルでhelloという名前のプロシージャーを定義する。[in]と指定されているのは関数への入力のための引数で、[out]と指定される場合は出力のための引数。返り値はつねにidl_id_t型で無ければならない。(その他については別途説明)
helloは、第一引数に文字列のサイズ、第二引数に文字列へのポインタを引数として受け取る。


interface greeting
{
import "../stub.h";
[sync] idl_id_t hello ([in] int nbytes, [in, size_is(nbytes)] char message[]);
}


このIDLファイルからスタブクラスを作成するためのMakeファイルを定義する。

########################################################################
# Subdirectories
########################################################################
DIRS := ppu spu

########################################################################
# Local Defines
########################################################################
IDL_SRC := hello.idl
IDL_FLAGS := -i -p ppu/stub_hello.c -s spu/stub_hello.c -n 4 -b spu_hello

INCLUDE = -I $(SDKINC) -I spu

include /opt/IBM/cell-sdk-1.1/make.footer


-b引数はスタブをプロキシとして実行されるSPUプログラム名、-n引数は割り当てるSPUの最大数を設定する。

makeを実行すると、ppu/stub_hello.cとspu/stub_hello.cというスタブが作成される。合わせてstub.hというヘッダが作成されるのでPPEとSPEプログラム上からこのヘッダを読み込むことでプロシージャを利用することが出来る。

次にPPU上で実行するプログラムppu/hello.cを書く。

#include <stdio.h>
#include <string.h>
#include <libidl.h> // stub.hの前に読み込む‚‹
#include "../stub.h"

int main() {
char *str = "Hello, World!";
hello(strlen(str), str);
return 0;
}


SPEプログラムにhelloプロシージャーの実装の詳細を定義する。
返り値はidl_id_tで固定。引数はIDLファイルで定義したものと合わせる。

#include <stdio.h>
#include <stdlib.h>
#include <idl_util.h>
#include "../stub.h"

idl_id_t hello(int nbytes, char msg[]) {
printf("SPE: %s\n", msg);
return 0;
}
PPE/SPEプログラムをコンパイルするためのMakefileを次のように書く。

ppu/Makefile
########################################################################
# Target
########################################################################
PROGRAM_ppu = ppu_hello

########################################################################
# Objects
########################################################################
IMPORTS = $(SDKLIB)/libidl.a $(SDKLIB)/libmisc.a -lspe

########################################################################
# make.footer
########################################################################
include /opt/IBM/cell-sdk-1.1/make.footer

spu/Makefile

########################################################################
# Target
########################################################################
PROGRAM_spu = ./spu_hello

########################################################################
# make.footer
########################################################################
include /opt/IBM/cell-sdk-1.1/make.footer


作業ディレクトリのトップディレクトリでmakeしシミュレータ上に転送する。

% make
% cp ppu/ppu_hello spu/ppu_hello /tmp/


シミュレータ上でゲストOSから/tmp/ppu_helloと/tmp/spu_outを転送する。

# callthru source /tmp/ppu_hello > ppu_hello
# callthru source /tmp/spu_hello > spu_hello
# chmod +x ppu_hello spu_hello
# ./ppu_out
SPE: Hello, World!
#


見事にHello, WorldをFunction-Offloadモデルを使用し、SPE上で実行させることが出来た。