3.2 簡単なSPEプログラム
出典: PS3 Linux Information Site / Cell/B.E.のパワーを体験しよう
ここでは、libspe2を利用した基本的なプログラミング方法について解説します。SPEプログラミングの手始めとして、1基のSPEを利用した簡単なプログラムを例にSPEプログラムの実行の流れについて見ていきます。
3.2.1 SPEプログラムの実行の流れ
libspe2では、以下の手順に従いPPEプログラムからSPEプログラムを実行します。
PPEセントリック・モデルにおける典型的なSPEプログラムの実行の流れを図 3.1に示します。
(1) SPEプログラム・イメージのオープン
(2) SPEコンテキストの生成
(3) SPEプログラムのLSへのロード
(4) SPEプログラムの実行
(5) SPEコンテキストの破棄
(6) SPEプログラム・イメージのクローズ
手順 (1) ~ (6) を図に示すと、図 3.3のようになります。
以降では、具体的なプログラムを用いて、それぞれの手順について説明します。
3.2.2 Hello Worldプログラム
リスト (3-1) は、「Hello world!」を表示するSPEプログラムです。このプログラムを例にPPEプログラムからSPEプログラムを実行する基本的なプログラミング方法について解説します。
リスト (3-1) Hello Worldプログラム (SPE用プログラム)
1 #include <stdio.h>
2
3 int main(unsigned long long spe, unsigned long long argp, unsigned long long envp)
4 {
5 printf("Hello world!\n");
6
7 return 0;
8 }
(1) SPEプログラム・イメージのオープン
まず、spe_image_open()関数を用いて、ELF実行ファイルに格納されたSPEプログラム・イメージをオープンします。
API定義 (3-1) spe_image_open()関数のプロトタイプ宣言
spe_program_handle_t * spe_image_open(const char *filename);
| 第1引数 | filename | SPEプログラムのELF実行ファイルのパス (絶対パスもしくは相対パス) を指定します。 |
| 返値 | 成功時には、オープンされたSPEプログラム・イメージのハンドルへのポインタを返します。失敗時には、NULLを返しerrnoにエラーコードを設定します。 |
用例 (3-1) にspe_image_open()関数の使用例を示します。
用例 (3-1) SPEプログラム・イメージをオープンする
prog = spe_image_open("./spe_hello.elf");
(2) SPEコンテキストの生成
続いて、spe_context_create()関数を用いて、SPEコンテキストを生成します。
API定義 (3-2) spe_context_create()関数のプロトタイプ宣言
spe_context_ptr_t spe_context_create(unsigned int flags,
spe_gang_context_ptr_t gang);
| 第1引数 | flags | SPEコンテキストの動作を設定するフラグを指定します。本チュートリアルでは、このフラグは利用しないため、デフォルト値0を設定します。 |
| 第2引数 | gang | SPE ギャングコンテキストを指定します。SPEギャングコンテキストは、本チュートリアルでは利用しないため、NULLを指定します。SPEギャングコンテキストの詳細についてはリファレンス「SPE Runtime Management Library version 2.0」の用語定義 (Terminology) を参照してください。 |
| 返値 | 成功時には、SPEコンテキストへのポインタを返します。失敗時には、NULLを返し、errnoにエラーコードを設定します。 |
なお、生成されたSPEコンテキストは、アプリケーション側で不要になり次第、後述するspe_context_destroy()関数で破棄する必要があります。用例 (3-2) にspe_context_create()関数の使用例を示します。
用例 (3-2) SPEコンテキストを生成する
spe = spe_context_create(0, NULL);
(3) SPEプログラムのLSへのロード
SPEコンテキストの準備ができたら、spe_program_load()関数を用いて、(1)でオープンされたSPEプログラムをLSへロードします。
API定義 (3-3) spe_program_load()関数のプロトタイプ宣言
int spe_program_load(spe_context_ptr_t spe,
spe_program_handle_t *program);
| 第1引数 | spe | SPEコンテキストへのポインタを指定します。 |
| 第2引数 | program | LSへロードするSPEプログラム・イメージのハンドルへのポインタを指定します。 |
| 返値 | 成功時には、0を返します。失敗時には、-1を返し、errnoにエラーコードを設定します。 |
用例 (3-3) にspe_program_load()関数の使用例を示します。
用例 (3-3) SPEプログラムをLSへロードする
ret = spe_program_load(spe, prog);
(4) SPEプログラムの実行
SPEコンテキストにロードされたプログラムは、spe_context_run()関数により実行されます。
API定義 (3-4) spe_context_run()関数のプロトタイプ宣言
int spe_context_run(spe_context_ptr_t spe,
unsigned int *entry,
unsigned int runflags,
void *argp,
void *envp,
spe_stop_info_t *stopinfo);
| 第1引数 | spe | 実行させるSPEコンテキストへのポインタを指定します。 |
| 第2引数 | entry | 実行開始アドレスを格納した変数へのポインタを指定します。通常は、実行開始アドレスとしてSPE_DEFAULT_ENTRYを使用します。 |
| 第3引数 | runflags | 特別な振る舞いをさせるためのフラグを指定します。通常は、0を指定します。 |
| 第4引数 | argp | SPEプログラムのmain()関数の第2引数に渡す値を指定します。 |
| 第5引数 | envp | SPEプログラムのmain()関数の第3引数に渡す値を指定します。 |
| 第6引数 | stopinfo | SPEプログラムが停止した時の詳細情報を格納する変数へのポインタを指定します。 |
| 返値 | 成功時には、0以上の値を返します。失敗時には、-1を返し、errnoにエラーコードを設定します。 |
引数の詳細な仕様についてはリファレンス「SPE Runtime Management Library Version 2.0」を参照して下さい。
(http://67.117.136.164/pub/cell/linux-20061110-docs/libspe-v2.0.pdf)
spe_context_run()関数が呼ばれると、SPEプログラムへ処理が移ります。SPEプログラムが終了した後、呼び出し元のPPEプログラムへと処理が戻ります。SPEプログラムのmain()関数から戻ってくる、もしくはSPEプログラムがexit()関数を呼んだ場合、返値として0が返されます。それ以外の場合、0以外の値が返されます。SPEプログラムの停止に関する詳しい情報がある場合には、第6引数stopinfoに指定した領域に格納されます。用例 (3-4) にspe_context_run()関数の使用例を示します。
用例 (3-4) SPEプログラムを実行する
ret = spe_context_run(spe, &entry, 0, NULL, NULL, &stop_info);
(5) SPEコンテキストの破棄
SPEプログラムの実行を終え、アプリケーションにとって不要になったSPEコンテキストは、spe_context_destroy()関数により破棄します。
API定義 (3-5) spe_context_destroy()関数のプロトタイプ宣言
int spe_context_destroy(spe_context_ptr_t spe);
| 第1引数 | spe | 破棄したいSPEコンテキストへのポインタを指定します。 |
| 返値 | 成功時には、0を返します。失敗時には、-1を返し、errnoにエラーコードを設定します。 |
用例 (3-5) にspe_context_destroy()関数の使用例を示します。
用例 (3-5) SPEコンテキストを破棄する
ret = spe_context_destroy(spe);
(6) SPEプログラム・イメージのクローズ
最後に、spe_image_close()関数を用いて、(1)でオープンされたSPEプログラム・イメージをクローズします。
API定義 (3-6) spe_image_close()関数のプロトタイプ宣言
int spe_image_close(spe_program_handle_t *program);
| 第1引数 | program | クローズしたいSPEプログラム・イメージのハンドルへのポインタを指定します。 |
| 返値 | 成功時には、0を返します。失敗時には、-1を返し、errnoにエラーコードを設定します。 |
用例 (3-6) にspe_image_close()関数の使用例を示します。
用例 (3-6) SPEプログラム・イメージをクローズする
ret = spe_image_close(prog);
ここまでが、libspe2を用いてPPEプログラムからSPEプログラムを実行する基本的なプログラミング方法となります。
3.2.3 例題プログラムの解説
それでは、例題プログラムのソースコード全体について解説します。
例題プログラム (3-1) Hello Worldプログラム (PPE用プログラム)
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <libspe2.h>
4
5 int main(int argc, char **argv)
6 {
7 int ret;
8
9 spe_context_ptr_t spe;
10 spe_program_handle_t *prog;
11 unsigned int entry;
12 spe_stop_info_t stop_info;
13
14 prog = spe_image_open("hello_spe.elf");
15 if (!prog) {
16 perror("spe_image_open");
17 exit(1);
18 }
19
20 spe = spe_context_create(0, NULL);
21 if (!spe) {
22 perror("spe_context_create");
23 exit(1);
24 }
25
26 ret = spe_program_load(spe, prog);
27 if (ret) {
28 perror("spe_program_load");
29 exit(1);
30 }
31
32 entry = SPE_DEFAULT_ENTRY;
33 ret = spe_context_run(spe, &entry, 0, NULL, NULL, &stop_info);
34 if (ret < 0) {
35 perror("spe_context_run");
36 exit(1);
37 }
38
39 ret = spe_context_destroy(spe);
40 if (ret) {
41 perror("spe_context_destroy");
42 exit(1);
43 }
44
45 ret = spe_image_close(prog);
46 if (ret) {
47 perror("spe_image_close");
48 exit(1);
49 }
50
51 return 0;
52 }
| 3行目 | SPEを制御する時に必要なヘッダファイル“libspe2.h”をインクルードします。 |
| 9行目~12行目 | SPEプログラムおよびSPEコンテキストを扱うための変数を宣言します。 |
| 14行目 | spe_image_open()関数を用いて、実行したいSPEプログラム・イメージをオープンします。 |
| 20行目 | spe_context_create()関数を用いて、SPEコンテキストを生成します。 |
| 26行目 | spe_program_load()関数を用いて、SPEプログラムをLSにロードします。 |
| 33行目 | spe_context_run()関数により、SPEプログラムを実行します。 |
| 39行目 | spe_context_destroy()関数を用いて、実行処理の終わったSPEコンテキストを破棄します。 |
| 45行目 | spe_image_close()関数を用いて、SPEプログラム・イメージをクローズします。 |
例題プログラム (3-2) Hello Worldプログラム (SPE用プログラム)
1 #include <stdio.h>
2
3 int main(unsigned long long spe, unsigned long long argp, unsigned long long envp)
4 {
5 printf("Hello world!\n");
6
7 return 0;
8 }
| 3行目 | main()関数の第1引数speにはSPEコンテキストの実効アドレスが渡されます。また、第2引数argp、第3引数evnpには、PPE側で呼び出されたspe_context_run()関数の第4引数argp、第5引数envpがそれぞれ渡されます。 |
| 5行目 | 文字列“Hello world!”を標準出力に出力します。 |
Hello Worldプログラムのソースコードは以下のリンクからダウンロードできます。
ファイルダウンロード:hello.tar.gz
3.2.4 プログラムのコンパイルと実行
ここでは、プログラムのコンパイル方法と実行方法について解説しますが、あらかじめ第1.4節の手順に従って開発環境を構築してください。SPEを利用したアプリケーションは、PPEプログラムとSPEプログラムから構成されていますので、それぞれのソースコードをコンパイルし、双方のELF実行ファイルを作成する必要があります。
PPEプログラムのコンパイルには、gccコマンドを利用します。libspe2を利用するため、gccのリンカオプションとして-lspe2オプションを指定し、libspe2.soをリンクします。また、SPEプログラムのコンパイルには、spu-gccコマンドを利用します。用例 (3-7) にHello Worldプログラムの場合のコンパイル方法を示します。
用例 (3-7) プログラムのコンパイル
$ gcc -lspe2 hello_ppe.c -o hello_ppe.elf $ spu-gcc hello_spe.c -o hello_spe.elf
アプリケーションを実行するには、2つのプログラムのうちPPEプログラムのほうをシェルプロンプト上で起動してください。用例 (3-8) にHello Worldプログラムの場合の実行方法を示します。
用例 (3-8) プログラムの実行
$ ./hello_ppe.elf Hello world! $

