libspes に spes::far_ptr クラスを追加してみた。
とりあえず最適化は後回しにして、とにかく SPE でプログラムを動かしたいという場合にちょっとだけ手助けをしてくれる。
例えばこんな感じ。
ppe.cpp:
struct spe_param {
uint32_t a;
float b;
};
main() {
spe_param param = { 1234, 5.678f };
...
spe_context_run(context, &entry, 0, ¶m, NULL, &stopinfo);
...
}
spe.cpp:
#include <libspes.h>
#include <stdint.h>
#include <stdio.h>
struct spe_param {
uint32_t a;
float b;
};
int main(uint64_t id, uint64_t args, uint64_t env) {
spes::far_ptr<spe_param> param = args;
printf("a:%d, b:%f\n", param->a, param->b);
return 0;
}
大抵の operator は実装してあるつもりなので、ポインタの移動、値の出し入れ、他の型のポインタへのキャストなんかは全て出来る。
けれどエイリアスを考慮しないため、実際にはちょっとややこしい面もある。
ポインタは一度値を読み出すと、ある範囲のバッファリングを行い、バッファ領域外のアクセスやデストラクタによってメインメモリに書き戻される。例えば次のようなコードがあったとして
struct spe_param {
uint64_t ptr;
...
};
int main(uint64_t id, uint64_t args, uint64_t env) {
spes::far_ptr<spe_param> param = args;
spes::far_ptr<char> data = param->ptr;
*data = 1;
return 0;
}
このコードは次のような動作をする。
- args のポイント先から一定量を param にバッファリングする。
- param->ptr のポイント先から一定量を data にバッファリングする。
- data のバッファに 1 を書き込む。
- data のデストラクタにより data をメインメモリに書き戻す。
- param のデストラクタにより param をメインメモリに書き戻す。
この時に、param は param の中身だけでなくある範囲のデータを持っているために、data のポイント先も持ってしまっているかも知れない。
つまり、data の内容を書き換えたはずなのに param のデストラクタで元に戻っている可能性がある。これを解決する為には
int main(uint64_t id, uint64_t args, uint64_t env) {
spes::far_ptr<spe_param> param = args;
spes::far_ptr<char> data = param->ptr;
param.commit(); // もしくは param.flush();
*data = 1;
return 0;
}
とする。
param は param へのアクセスがある度にダーティフラグをセットする。
farptr::commit() や farptr::flush() はバッファを書き戻し、ダーティフラグをクリアする。これにより param のデストラクタは書き戻しを行わなくなる。