« CELL で時間計測 | メイン | どれにしよう »

Local Storage の空きメモリを取得する

 このエントリに出てくる用語に「ローカルストレージ」と「メモリ」がありますが、このエントリ内では同義で、SPE に含まれる 256KB のメモリを指します。
 他のエントリではメインメモリ(PLAYSTATION3 では 256MB)を指す事が多いので注意して下さい。

 ローカルストレージのヒープ領域は _end からスタックの最後までであると「SPU C/C++ 言語拡張」の「6.1.3. malloc()用ヒープ領域」に書かれています。
 メモリマップの大雑把なイメージとしては下のような感じです。

アドレス内容
0x3ffff



スタック

変数 arg
変数 spe_id

ヒープ

_end


0x00000

プログラムコード
_start

 習慣上、メモリは下から上に向かって続いているとしています。
 スタックはローカル変数を保存する領域であり、関数の中で関数を呼んでいくと、下に向かって侵略されていきます。
 ヒープ領域というのが目的の空きメモリであり、_end から上に向かって malloc() や new で確保する事が出来ます。

 この _end というのは gcc が定義するシンボルであり、プログラム中でそのまま使用する事が出来ます。また、前述の通りスタックというのは変数を保存する領域の為、変数のアドレスを得る事で現在の関数内における大雑把なローカルストレージのサイズが分ります。
 ※スタックチェインを辿っていけば正確なサイズを知る事も可能ですが、そこまでする必要も無いでしょう。


// heap_size.c
#include <stdio.h>

extern unsigned char _end[];

int main(unsigned long long spe_id, unsigned long long arg)
{
    const unsigned ls_size   = (unsigned)&arg;
    const unsigned code_size = (unsigned)&_end;
    const unsigned heap_size = ls_size - code_size;

    printf("  ls_size:%10d bytes\n", ls_size);
    printf("code_size:%10d bytes\n", code_size);
    printf("heap_size:%10d bytes\n", heap_size);

    return 0;
}

$ spu-gcc heap_size.c -o heap_size
$ ./heap_size
  ls_size:    262080 bytes
code_size:      3424 bytes
heap_size:    258656 bytes

 _end を unsigned char [] で宣言しているのは便宜上であり、int でも void * でも構いません。
 ここで、上記の通り _end が unsigned char [] で宣言されているとした場合、malloc() や new を使用しない限り _end[0] 〜 _end[heap_size - alpha] までは自由にアクセスする事が出来ます。
 直接的なアクセスは管理を自力で行う分、コードの可読性や移植性、そして安全性においていささか危険ですが、メモリを極限まで節約しなくてはいけない状態では malloc() や new といったメモリを管理する為のプログラムを節約出来る分だけ有効です。また、malloc() や new はメモリを管理する為の管理領域も必要とするので、それも節約する事が出来ます。

 _end[0] 〜 _end[heap_size - alpha] の -alpha の部分は、ローカル変数として使用するメモリの分をマージンとして引かなくてはなりません。
 ローカル変数はレジスタに割り当てられ、そのレジスタの保存用にメモリに割り当てられるわけですが、レジスタの割り当て方は「SPU Application Binary Interface 仕様書」の「2.2.1. レジスタ」に載っています。
 ここに載っている通り、各関数で最低 2000 (125 * 16) バイト使用されるので、main() が foo() を呼び出し、foo() が bar() を呼び出すような 3 階層のプログラムでは alpha が最低 2000*3 = 6000 になります。もちろんもっと階層の深い場合や、関数の中で使用している変数が多い場合、配列のサイズが大きい場合は余分に空けておかなければなりません。
 訂正:最低 2000 バイトというのは誤りでした。

トラックバック

このエントリーのトラックバックURL:
http://yoffy.dyndns.org/cgi-bin/mt/mt-tb.cgi/547

コメント (3)

Q:

各関数で最低2000バイトというのは間違いですよ、その呼び出される先の関数内で使用される分のみしか退避されません。

Q cont.:

あの2000バイトというのは、スタックポインタとオフセットを使ってスタックアクセスを行う場合に、-2000よりも小さい(つまりSPの指す番地から2000バイト以上先の)領域へ、後から使うデータを格納してはならないという規約です。
割り込みルーチン用のスタックを共用するための工夫なので、1関数毎にそれだけのスタックを消費すると言う事ではありません。

よっふぃ〜:

誤解してました。ありがとうございます。

コメントを投稿

About

2007年01月01日 17:58に投稿されたエントリーのページです。

ひとつ前の投稿は「CELL で時間計測」です。

次の投稿は「どれにしよう」です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。

Powered by
Movable Type 3.37