Cell SDK 2.0 に追加された SPU code overlays を試してみました。この機
能の説明は cd image (CellSDK20.iso) の pdf/cpbprg00.pdf - "Software
Development Kit 2.0 Programmer's Guide Version 1.0" Chapter
4. SPU code overlays にあります。
overlay 機能の概要
詳細は上記を参照ですが、基本的には、linker script の変更のみで
overlay 機能を使用することが可能です。overlay 実現に必要なものは linker
が実行バイナリ作成時に自動的に追加してくれます。
overlay するためには、関数の実体がどの section にあるか?や、いつ
section を入れ換えるか?を管理する必要があり、linker の手助けなしにやろう
とすると結構手間がかかるのですが、linker script を変更するだけでよいとい
うことになると、手軽にいろいろな構成が試せるので、ハマればかなり強力な機
能だと思います。
overlay 機能を使用する場合の linker script の変更点
以下の default で使用される linker script と、overlay 機能のサンプル
(simple) で使用される linker script の diff を見てもらえば一目瞭然ですが、
OVERLAY 出力 section の追加と、overlay 対象の入力 section の移動を行うだ
けです。
$ diff -u /opt/cell/toolchain-3.3/spu/lib/ldscripts/elf32_spu.x \
/opt/ibm/cell-sdk/prototype/src/samples/overlay/simple/spu_olay/ld.script
--- /opt/cell/toolchain-3.3/spu/lib/ldscripts/elf32_spu.x
+++ sdk-2.0_overlay/simple/spu_olay/ld.script
@@ -3,7 +3,7 @@
"elf32-spu")
OUTPUT_ARCH(spu)
ENTRY(_start)
-SEARCH_DIR("=/usr/spu/lib");
+SEARCH_DIR("/opt/cell/toolchain-3.3/spu/spu/lib");
/* Do we need any of these for elf?
__DYNAMIC = 0; */
SECTIONS
@@ -51,12 +51,17 @@
.plt : { *(.plt) }
.text :
{
- *(.text .stub .text.* .gnu.linkonce.t.*)
+ *( EXCLUDE_FILE(olay1/*.o olay2/*.o) .text .stub .text.* .gnu.linkonce.t.*)
KEEP (*(.text.*personality*))
*(.spu.elf)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
} =0
+ OVERLAY :
+ {
+ .segment1 {olay1/*.o(.text)}
+ .segment2 {olay2/*.o(.text)}
+ }
.fini :
{
KEEP (*(.fini))
@@ -180,7 +185,6 @@
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
- .note.spu_name 0 : { *(.note.spu_name) }
PROVIDE (__stack = 0x3fff0);
/DISCARD/ : { *(.note.GNU-stack) }
}
いろいろ試す
用意されたサンプルをただ実行してもしょうがないので、変更を加えて、以
下のことができるか確かめてみました。もとのサンプルは overview を使用して
います。
overview には se.o が overlay されないバグがありますが、これも修正し
ています。
overlay region 間をピンポンする関数呼び出し
ここでピンポンとは、ある region (reg A) の segment (seg A1) にある関
数 (func A1) から他の region (reg B) にある関数 (func B) が呼ばれた場合に、
func B から reg A の seg A1 と異なる segment (seg A2) にある関数 (func A2)
を呼ぶことです。
これが出来ると overlay の自由度はかなり高まります。
今回は、sj.c 内に sj() という関数を作成し、
sf() [reg 2, seg 3] -> sh() [reg 3, seg 5] -> sj() [reg 2, seg 7] という
順番で呼び出しを行っています。
data section の overlay
C 言語 (それとも OS のプロセス空間?) の規格的には、全ての data は全
ての text から参照可能になっている必要がありますが、運用として、あるdata
はある関数からしか参照しないようにすることは可能であり、overlay 対象とし
て考えられるため、実現できるか確かめてみました。
ただし、const でない場合や、overlay region 間をピンポンする関数呼び出
し を考慮すると、適用はよく考えないとハマることになります。それでもローカ
ル変数や、malloc で確保している領域を含めて overlay を検討すると LS は有
効活用できます。(例えば、同じ region に入れる segment のサイズに差があ
り、この差で data が吸収できる場合)
今回は、sj.c で static char 型の配列 (.data)、static const char の文
字列 (.rodata) を定義して、text と同じ segment に入れています。ついでに
例として、文字列を書き換えても反映されないバグも入れています。
実行結果
以下のように sj() も実行され、message (Hello World!) もきちんと表示
されているようです。
また、上記のバグは 2 回目の message は "modified!" と表示されるよう
に書き換えているのにそれが変更されていないことを指しています。
$ ./overlay_overview
Entering main
sa prints 97
sb prints 98
sc prints 100100099
sd prints 200200100
se prints 200200101
succeeded! expecting 101, got 101
succeeded! expecting 100, got 100
sf prints 200300102
sh prints 300500104
sj prints 300600106
sj overlay message: Hello World!
succeeded! expecting 106, got 106
succeeded! expecting 104, got 104
si prints 300600105
succeeded! expecting 105, got 105
succeeded! expecting 102, got 102
succeeded! expecting 99, got 99
sg prints 100400103
sh prints 300500104
sj prints 300600106
sj overlay message: Hello World!
succeeded! expecting 106, got 106
succeeded! expecting 104, got 104
si prints 300600105
succeeded! expecting 105, got 105
succeeded! expecting 103, got 103
succeeded! expecting 98, got 98
succeeded! expecting 97, got 97
Exiting main, status=0