3週間ほどCellから離れている間に、CBE SDK2.0やlibspe2がリリースされました。
libspe2はlibspe1と大きくspufs抽象化の仕組みが異なっているので、libspe2 APIの基本的な使い方を見ていきます。
SPEはプログラム中から直接扱えないため、ソフトウェアレベルで抽象化されて扱うための実装としてコンテキストが導入されており、コンテキストは"論理的なSPE"についての情報を保持します。プログラマはSPEコンテキストへのポインタを扱うことでSPEを操作できます。
SPEコンテキストを1つだけ扱う場合は次の順序で実行する。
- SPEコンテキストの作成
- SPEのローカルストアにSPEに実行させるプログラムをロードする
- SPEコンテキストを実行する
- SPEコンテキストを廃棄する
SPEコンテキストの作成はspe_context_create関数を使用します。
第一引数にコンテキストに適用するフラグを指定します。
第二引数はギャングコンテキスト(複数のコンテキストを1つに関連付け)を使用する際に使用します。
PPE側のプログラム
spe_context_ptr_t ctx;
// Create SPE context
if((ctx = spe_context_create(SPE_EVENTS_ENABLE, NULL)) == NULL) {
perror("spe_context_create");
return 1;
}
SPEのローカルストアにプログラムをロードするには、spe_program_load()関数を使用する。
ここではCESOFを使用しているため、ELFイメージをロードする必要はありませんが、ELFイメージを手動でロードする場合は、spe_image_open()関数を使用します。
extern spe_program_handle_t spe_mbox;
// Programe load to Local Store
if((rc = spe_program_load(ctx, &spe_mbox)) < 0) {
perror("spe_program_load");
return 1;
}
SPUと他のデバイス間(他のSPUやPPU)の通信には、MMIO・DMAといった手段のほかに、Mailboxという32bitメッセージをやり取りする仕組みが用意されています。今回はMailboxを利用してデータを送信します。メールボックスの詳細は、Cell Broadband Engine Programming Handbook 19.6 Mailboxesを参照してください。
SPUのMailboxへデータを書き込むには、spe_in_mbox_write()関数を使用します。
送信先のコンテキスト, 書き込むデータへのポインタ, 書き込むデータ数, ブロッキングに関する振る舞いを引数に指定します。
unsigned int mbox_data = 123;
// Write to Mailbox
if((rc = spe_in_mbox_write(ctx, &mbox_data, 1, SPE_MBOX_ALL_BLOCKING)) < 0) {
perror("spe_in_mbox_write");
return 1;
}
SPEコンテキストを実行します。
引数に与えたspe_stop_info_t型の変数であるstop_infoへのポインタを渡すことでSPEの終了状態に関する情報が取得できる。spe_stop_info_t構造体についての詳細は、libspe-v2.0.pdfを参照。
// Print exit status code
switch(stop_info.stop_reason) {
case SPE_EXIT:
printf("SPE_EXIT stop_info.result.stop_exit_code=0x%x\n", stop_info.result.spe_exit_code);
break;
case SPE_STOP_AND_SIGNAL:
printf("SPE_STOP_AND_SIGNAL stop_info.result.stop_signal_code=%d\n", stop_info.result.spe_signal_code);
break;
case SPE_RUNTIME_ERROR:
printf("SPE_RUNTIME_ERROR stop_info.result.spe_runtime_error=%d\n", stop_info.result.spe_runtime_error);
break;
case SPE_RUNTIME_EXCEPTION:
printf("SPE_RUNTIME_EXCEPTION stop_info.result.spe_runtime_exception=%d\n", stop_info.result.spe_runtime_exception);
break;
}
最後にSPEコンテキストを破棄する。
// Destroy SPE Context
if((rc = spe_context_destroy(ctx)) < 0) {
perror("spe_context_destroy");
return 1;
}
SPE側のプログラム
#include <stdio.h>
#include <spu_mfcio.h>
typedef union {
unsigned long long ull;
unsigned int ul[2];
} addr64;
int main(unsigned long long speid __attribute__((unused)),
addr64 argp __attribute__((unused))) {
unsigned int mbox_data;
printf("Hello, world from SPE.\n");
// Read data from mailbox
mbox_data = spu_read_in_mbox(); // spu_readch(SPU_RdInMbox)
printf("SPE mbox_data: %d\n", mbox_data);
return 26;
}
spu_read_in_mbox()関数でinbound mailboxにあるデータを読み込む。
ソースコード一式
ディレクトリ構造は次の通り。
% ls -FR
.:
Makefile ppu/ spu/
./ppu:
Makefile mbox_test.c
./spu:
Makefile spe_mbox.c
%
ppu/mbox_test.c
#include <stdio.h>
#include <libspe2.h>
extern spe_program_handle_t spe_mbox;
int main() {
int rc;
int flags;
unsigned int entry = SPE_DEFAULT_ENTRY;
unsigned int mbox_data = 123;
spe_context_ptr_t ctx;
spe_stop_info_t stop_info;
// Create SPE context
if((ctx = spe_context_create(SPE_EVENTS_ENABLE, NULL)) == NULL) {
perror("spe_context_create");
return 1;
}
// Programe load to Local Store
if((rc = spe_program_load(ctx, &spe_mbox)) < 0) {
perror("spe_program_load");
return 1;
}
// Write to Mailbox
if((rc = spe_in_mbox_write(ctx, &mbox_data, 1, SPE_MBOX_ALL_BLOCKING)) < 0) {
perror("spe_in_mbox_write");
return 1;
}
// SPE Context running
if((rc = spe_context_run(ctx, &entry, 0, NULL, NULL, &stop_info)) < 0) {
perror("spe_context_run");
return 1;
}
// Print exit status code
switch(stop_info.stop_reason) {
case SPE_EXIT:
printf("SPE_EXIT stop_info.result.stop_exit_code=0x%x\n", stop_info.result.spe_exit_code);
break;
case SPE_STOP_AND_SIGNAL:
printf("SPE_STOP_AND_SIGNAL stop_info.result.stop_signal_code=%d\n", stop_info.result.spe_signal_code);
break;
case SPE_RUNTIME_ERROR:
printf("SPE_RUNTIME_ERROR stop_info.result.spe_runtime_error=%d\n", stop_info.result.spe_runtime_error);
break;
case SPE_RUNTIME_EXCEPTION:
printf("SPE_RUNTIME_EXCEPTION stop_info.result.spe_runtime_exception=%d\n", stop_info.result.spe_runtime_exception);
break;
}
// Destroy SPE Context
if((rc = spe_context_destroy(ctx)) < 0) {
perror("spe_context_destroy");
return 1;
}
return 0;
}
実行結果
Mailboxを介した通信とSPEプログラムの返り値26(=0x1a)が正常に取得できています。
# ./mbox_test
Hello, world from SPE.
SPE mbox_data: 123
SPE_EXIT stop_info.result.stop_exit_code=0x1a
#
参考
SPE Runtime Management Library (PDF)
Cell Broadband Engine Programming Handbook Version 1.0 (PDF)