4.6 埋め込みSPEプログラム
出典: PS3 Linux Information Site / Cell/B.E.のパワーを体験しよう
第3.2節で紹介したように、基本的なSPEプログラムの実行方法は、PPEプログラムがSPE用のELF実行ファイルをオープンし、PPEプログラム内部にSPEプログラム・イメージを読み込んでから実行するという方法でした。
このように、PPEプログラムとSPEプログラムを別々のELF実行ファイルとして作成することも可能ですが、PPEプログラム側のELF実行ファイルにSPEプログラム自体を埋め込む (同梱させる) こともできます。
4.6.1 CBEA埋め込みSPEオブジェクト・フォーマット (CESOF)
埋め込みSPEプログラムは、PPEプログラム中にデータとしてSPEプログラム・イメージそのものが埋め込まれたもので、図 4.15に示すようにSPEプログラムを内包した特別なPPEオブジェクトをPPEプログラムにリンクすることで実現されます。このPPEオブジェクトをCESOF (CBEA Embedded SPE Object Format) オブジェクトと呼びます。このようにして埋め込まれたSPEプログラムは、SPEプログラム・イメージのハンドル (spe_program_handle_t型データ) としてPPEプログラムから参照することができます。
SPEを使用するPPE用のプログラムやライブラリを1個のファイルとして作成したいときに、CESOFオブジェクトが利用されます。プログラムが1つのファイルにまとめられることで、PPEプログラム側でのSPEプログラムのELF実行ファイルのオープン処理が省けます。また、SPEプログラムのファイルパス指定の間違いやファイル削除などの不注意によりSPEプログラムのELF実行ファイルが見つからないといった実行時の問題も避けられます。
4.6.2 Hello Worldプログラム (埋め込みSPEプログラム版)
ここでは、第3.2節で紹介したHello Worldプログラムを例に、埋め込みSPEプログラムのプログラミング方法について解説します。リスト (4-13) に示したとおり、埋め込まれるSPEプログラムは変更する必要はありません。
リスト (4-13) Hello Worldプログラム (SPE用プログラム)
#include <stdio.h>
int main(unsigned long long spe, unsigned long long argp, unsigned long long envp)
{
printf(“Hello world!\n”);
return 0;
}
リスト (4-14) のように、SPEプログラムを埋め込む側のPPEプログラムでは、埋め込まれるSPEプログラムをspe_program_handle_t型の外部シンボルとして参照します。
リスト (4-14) Hello Worldプログラム (PPE用プログラム)
1 #include <libspe2.h>
2
3 extern spe_program_handle_t prog;
4
5 int main(int argc, char **argv)
6 {
7 int ret;
8 spe_context_ptr_t spe;
9 unsigned int entry = SPE_DEFAULT_ENTRY;
10 spe_stop_info_t stop;
11
12 // No need to open/close SPE program image (spe_image_open() and spe_image_close())
13
14 spe = spe_context_create(0, NULL);
15 /* ... snip ... */
16 ret = spe_program_load(spe, &prog);
17 /* ... snip ... */
18 ret = spe_context_run(spe, &entry, 0, NULL, NULL, &stop);
19 /* ... snip ... */
20 ret = spe_context_destroy(spe);
21
22 return 0;
23 }
| 3行目 | SPEプログラム・イメージのハンドルを外部変数として宣言しておきます。この変数名には、後述するembedspuコマンドによって生成されるCESOFオブジェクト中に埋め込まれるSPEプログラム・イメージの外部シンボル名を指定します。 |
| 12行目 | SPEプログラム・イメージはPPEプログラム中に埋め込まれているため、spe_image_open()関数およびspe_image_close()関数を呼び出す必要がなくなります。 |
| 16行目 | spe_program_load()関数の第2引数には、SPEプログラム・イメージのハンドルへのポインタを指定するため、ポインタ参照をしている点に注意してください。 |
4.6.3 埋め込みSPEオブジェクトの作成
それでは、SPEプログラムが埋め込まれたPPEプログラムの作成方法について解説します。基本的には、以下のような流れで作成します。
(1) SPEオブジェクトの作成
(2) SPEプログラムの作成 (SPEオブジェクトのリンク)
(3) CESOFオブジェクトの作成
(4) PPEオブジェクトの作成
(5) PPEプログラムの作成 (PPEオブジェクトとCESOFオブジェクトのリンク)
手順 (1) ~ (5) を図に示すと、図 4.16のようになります。埋め込まれるSPEプログラムを作成する手順 (手順 (1)と(2)) は、従来の手順と同じです。
手順 (3) で、embedspuコマンドと呼ばれる特別なコマンドを利用しSPEプログラムからCESOFオブジェクトを作成します。手順 (4) で、PPEプログラムのソースコードからPPEオブジェクトを作成し、手順 (5) でCESOFオブジェクトとPPEオブジェクトをリンクして、最終的にPPEプログラムを作成します。
4.6.4 コンパイルと実行
Hello Worldプログラムを例にSPEプログラムをPPEプログラムに埋め込む手順について解説します。最も簡単なコンパイル方法を用例 (4-5) に示します。
用例 (4-5) プログラムのコンパイル
$ spu-gcc –c hello_spe.c ・・・手順(1) $ spu-gcc hello_spe.o –o hello_spe.elf ・・・手順(2) $ embedspu -m64 prog hello_spe.elf hello_embedspe.o ・・・手順(3) $ gcc –m64 –c hello_ppe.c ・・・手順(4) $ gcc –m64 –lspe2 hello_ppe.o hello_embedspe.o –o hello_ppe.elf ・・・手順(5)
まずは、spu-gccコマンドを利用して、SPEプログラムのELF実行ファイルを作成します (手順 (1)・(2))。次に、embedspuコマンド (あるいはppu-embedspuコマンド)を利用してSPEプログラムが埋め込まれたCESOFオブジェクトを作成します(手順 (3)) 。
また、PPEプログラムのソースコードからは、gccコマンドを利用して、PPEオブジェクトを作成します (手順 (4))。最後に、PPEオブジェクトとCESOFオブジェクトをリンクし、PPEプログラムのELF実行ファイルを作成します (手順 (5))。
実行に必要なファイルは、手順 (5) で作成されたPPEプログラム1個だけで、手順 (2)で作成されたSPEプログラムのELF実行ファイルは必要ありません。
なお、embedspuコマンドは、埋め込まれるSPEプログラムのPPEプログラムから参照される外部シンボル名、埋め込まれるSPEプログラムのファイル名、作成させれるCESOFオブジェクトのファイル名を引数に指定します。embedspuコマンドの用法を用例 (4-6) に示します。
用例 (4-6) embedspuコマンドの用法
embedspu {-flags ...} [symbol_name] [input_filename] [output_filename]
また、embedspuコマンドには、任意のコンパイラへのオプションを渡すことができます。例えば、32ビットもしくは64ビットのPPEオブジェクトを生成する場合には、-m32や-m64といったオプションを指定します。
4.6.5 参考資料
CESOFオブジェクトについては、この他にもPPEプログラムとSPEプログラムでグローバル変数の共有を行うための機構などがあります。CESOFオブジェクトについて、さらに学習したい方は「Cell Broadband Engine Linux Reference Implementation Application Binary Interface Specification」の第2章「CBEA Embedded SPE Object Format」を参照してください。


