レベル: 中級 Jonathan Bartlett (johnnyb@eskimo.com), Director of Technology, New Medio
2007年 07月 17日 PPE (Power Processor Element) プログラムが SPE (Synergistic Processor Element) のアクセスと管理に使用する標準ライブラリー、libspe に大幅な改訂が行われ、Cell/B.E. (Cell Broadband Engine) SDK 2.1 ではライブラリー・インターフェースを libspe1 から libspe2 に正式に変更しています。この記事では、Jonathan Bartlett が libspe2 のコンセプトを紹介し、libspe2 で基本 SPE プロセスの管理と通信を行う方法を説明します。
libspe は、プログラマーが SPE プロセスの管理と通信を行うためのインターフェースを提供します。libspe1 から libspe2 へのアップグレードでは、PPE から SPE プロセスを管理する方法が全体的に見直されています。この記事では、バージョン番号に関係なくこのライブラリーを総称するときには libspe と呼び、特定のバージョンを指すときには libspe1、libspe2 と呼ぶことにします。
libspe2 の詳細に入る前に、libspe は物理 SPE を管理するためのものではないということを念頭に置いてください。libspe を使用するコードはユーザー・レベルのコードであるため、ハードウェア・リソースを直接変更することはできません。ユーザー・レベルのコードは、そのコードが物理的に実装されているオペレーティング・システムが最適だと判断する方法により、オペレーティング・システム経由で SPE のリソースを要求します。オペレーティング・システムは、例えば複数のコンテキストを単一の物理 SPE にスケジュールするには、必要に応じてコンテキストをロードおよびアンロードするという方法をとります。それぞれの SPE プロセスは SPE が実行中である限り SPE 全体にアクセスできますが、オペレーティング・システムは任意の時点で自由に実行を中断し (後で再開) 、別の SPE コンテキストを実行するようにスケジュールできます。このすべての動作は、SPE での過剰なコンテキスト切り替えによってパフォーマンスが劣化しない限り、SPE および PPE 両方のユーザー・レベル・ソフトウェアには見えません。
オペレーティング・システムが管理する SPE リソースは、libspe1 ではスレッドと呼ばれていましたが、libspe2 ではコンテキストと呼ばれるようになっています。この変更は単なる用語の変更ではなく、libspe2 では SPE リソース管理からスレッド化モデルを切り離すことを目標にしているからです。
SPE コンテキストの作成と使用方法
libspe1 と libspe2 との間には、SPE コードの基本的な実行に 2 つの大きな相違点があります。libspe1 ではコンテキストの作成と実行は spe_create_thread によって同時に処理されていましたが、libspe2 では別々のステップとなっています (実際には、以下で説明するように複数のステップがあります)。
libspe1 の場合、SPE コードを実行するための呼び出しは非同期で処理され、SPE コードはそれに続く PPE コードと同時に spe_create_thread によって実行されていました。libspe2 では、SPE コードを実行するための呼び出しは同期して処理されます。つまり、1 つ以上の SPE 同時実行スレッドを取得するには、プログラムで PPE コードにその数だけスレッドを作成し、それぞれのスレッド内で SPE プログラムを実行しなければならないということです。作業が増えるように思えますが、実際にはヘルパー関数でラップすれば簡単なことなので、SPE プログラムの実行方法にかなりの柔軟性がもたらされます。
以下は、新しい SPE スレッドの実行を開始する libspe1 プログラムです (ppe_example.c として入力)。
リスト 1. libspe1 での単純なスレッド作成
#include <stdlib.h>
#include <stdio.h>
#include <libspe.h>
/* Assumes you have an embedded SPE program under the name test_handle */
extern spe_program_handle_t test_handle;
int main() {
/* Create the thread and record the thread ID */
speid_t spe_id = spe_create_thread(0, &test_handle, NULL, NULL, -1, 0);
int status;
/* Check for errors */
if(spe_id == 0) {
perror("Unable to create SPE thread");
exit(1);
}
/* Wait for completion */
spe_wait(spe_id, &status, 0);
return 0;
}
|
このプログラムの SPE コードは以下のとおりです (spe_example.c として入力)。
リスト 2. スレッドのデモ用 SPE コード
#include <stdio.h>
int main(unsigned long long spe_id, unsigned long long pdata) {
printf("Hello world!\n"); /* Calls back to PPE */
return 0;
}
|
プログラムをビルドするには、以下のコードを入力します。
spu-gcc spe_example.c -o spe_example
ppu-embedspu test_handle spe_example spe_example_csf.o
ppu-gcc ppe_example.c spe_example_csf.o -lspe -o ppe_example
|
プログラムの PPE 部分は、libspe2 では以下のように書き直すことができます (SPE コードを変更する必要はありません)。
リスト 3. libspe2 での単純なスレッド作成
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <libspe2.h>
/* NOTE -- the prototype is based on the standard pthread thread signature */
void *spe_test_function(void *data);
/* Assumes you have an embedded SPE program under the name test_handle */
extern spe_program_handle_t test_handle;
int main() {
pthread_t my_thread;
int retval;
/* Create Thread */
retval = pthread_create(
&my_thread, /* Thread object */
NULL, /* Thread attributes */
spe_test_function, /* Thread function */
NULL /* Thread argument */
);
/* Check for thread creation errors */
if(retval) {
fprintf(stderr, "Error creating thread! Exit code is: %d\n", retval);
exit(1);
}
/* Wait for Thread Completion */
retval = pthread_join(my_thread, NULL);
/* Check for thread joining errors */
if(retval) {
fprintf(stderr, "Error joining thread! Exit code is: %d\n", retval);
exit(1);
}
return 0;
}
/* NOTE -- the prototype is based on the standard pthread thread signature */
void *spe_test_function(void *data) {
int retval;
unsigned int entry_point = SPE_DEFAULT_ENTRY; /* Required for continuing
execution, SPE_DEFAULT_ENTRY is the standard starting offset. */
spe_context_ptr_t my_context;
/* Create the SPE Context */
my_context = spe_context_create(SPE_EVENTS_ENABLE|SPE_MAP_PS, NULL);
/* Load the embedded code into this context */
spe_program_load(my_context, &test_handle);
/* Run the SPE program until completion */
do {
retval = spe_context_run(my_context, &entry_point, 0, NULL, NULL, NULL);
} while (retval > 0); /* Run until exit or error */
pthread_exit(NULL);
}
|
このプログラムのビルド・プロセスには、それほどの違いはありません。
spu-gcc spe_example.c -o spe_example
ppu-embedspu test_handle spe_example spe_example_csf.o
ppu-gcc ppe_example.c spe_example_csf.o -lspe2 -o ppe_example
|
ご覧のように、libspe2 では libspe に自動的にスレッド化を行わせるのではなく、pthread を使用してスレッド化を処理します (pthread の詳細は、記事の終わりにある「参考文献」を参照)。このコードが行う手順は以下のとおりです。
- pthread を作成して実行します (
pthread_create )。
- SPE コンテキストを作成します (
spe_context_create )。
- このコンテキストに SPE コードをロードします (
spe_program_load )。
- SPE コードを完了するまで実行 (および再実行) します (
spe_context_run )。
このようにプロセスを複数のステップに分けることで、プログラマーがプロセスの各段階を直接制御できるようにしています。別のスレッド・モデルを使用するには、pthread 呼び出しを目的のスレッド化システムと置き換えるだけです。アプリケーションに組み込まれたプログラム・ファイルではなく、外部のプログラム・ファイルを実行するにしても、spe_program_load を呼び出す前に spe_image_open を使用するだけの話です。PPE コールバックの動作方法をカスタマイズするにはどうするかと言えば、ただ単に spe_context_run のループとフラグを変更するだけです。それでも複雑だというのなら、プログラムにとって最も有効に機能するシーケンスをただ単にヘルパー関数にラップしてください。
プロセス全体は至って単純明快ですが、spe_context_run となると話は別です。これは実際に SPE でコードを実行させる関数です。この関数は同期を行います。つまり PPE が SPE コードを実行している間、現在 PPE で実行中のスレッドを中断し、SPE コードが終了または (例えばシグナルを送出するために) 一時的に停止するとPPE スレッドを再開します。上記の単純なプログラムでは spe_context_run の do..while ループを除外すればいいだけのことですが、複雑なプログラムではループを維持して戻り値を調べ、プログラムが正常に終了したのか、それとも停止およびシグナル送出命令の結果、特殊な処理を行わなければならないのか、を判断する必要が出てくることがあります。
spe_context_run にはいくつかの興味深い引数もあります。最初の引数は単なる実行対象コンテキストの参照ですが、2 番目の引数はプログラムのオフセットへのポインターで、実行を開始する箇所を指定します。文字どおり、プログラムのどのバイトから実行を開始するかを SPE に指示するわけです。これを管理するのは思うほど難しくありません。その理由は第一に、すべてのプログラムのデフォルト開始点は SPE_DEFAULT_ENTRY であること、第二に、値へのポインターを渡しているため、spe_context_run 関数はリターン時に正しい再エントリー位置を指すように値を変更するためです。したがって正しく初期化される限り、エントリー・ポイントは実際には spe_context_run 自体で維持されることになります。その一方で、シグナル送出後に SPE プログラムの実行を任意の場所から再開できるという付加的柔軟性がもたらされます。
3 番目の引数は一連の実行フラグです。このフラグは通常、0 に設定すれば問題ありませんが、SPE_NO_CALLBACKS フラグを送信することもできます。このフラグを送信すると、spe_context_run 関数にコールバック関数を自動的にディスパッチさせてユーザーに見えないようにするのではなく、プログラムですべてのコールバック関数を直接処理できるようになります。4 番目と 5 番目の引数はそれぞれ argp と envp です。この 2 つの引数を使用して、SPE プログラムの起動時に SPE プログラムに引数と環境情報を渡します (libspe1 の spe_create_thread に含まれるパラメーターと同じです)。最後の引数は spe_stop_info_t 型の構造体へのオプションのポインターです。高度な使用方法では、このポインターを使って spe_context_run がその戻り値を返した詳細の理由を得られますが、ほとんどのアプリケーションでは戻り値の情報だけで十分です。
spe_context_run の戻りコードは、プログラムが正常に終了した場合は 0、「停止およびシグナル送出」命令が実行された場合は正の値 (実際の値はシグナル送出命令によって設定)、そしてエラー条件を示す場合は -1 となります (すると errno が設定され、spe_stop_info_t 構造体が指定されている場合には、この構造体に詳細情報が含まれます)。
PPE コールバック関数
libspe1 では SPE プログラムから簡単に PPE の特定の libc 関数を呼び出し、それによって基本的にオペレーティング・システムの libc にアクセスすることができましたが、SPE が使用できる関数のリストは原則的に事前定義されていました。libspe2 では、SPE が呼び出せる PPE コールバック関数を追加で組み込むためのインターフェースが用意されています。
PPE でコールバック関数を追加で作成するには、PPE コード内に関数自体を作成するとともに、SPE でサンクを実行するスタブを生成する必要があります。コールバックを実行する際に、SPE は単一の 4 バイト引数へのポインターを PPE に提供するため、値を返すための直接的サポートは行いません。コールバックで呼び出しおよびリターンを行う際の一般的なパターンは、関数へのパラメーターと戻り値の両方を保持する構造体を作成することです。そして、この構造体のアドレスをデータとして渡します。ただし覚えておかなければならないのは、この場合、コールバック関数はポインターを取得するのではなくポインターへのポインターを取得するという点です。
このコールバック関数のプロトタイプは以下のとおりです。
int the_callback_function(void *ls_base, unsigned int data_ptr);
|
戻り値は、成功した場合には 0 になります。それ以外の値はエラーとみなされ、spe_context_run がリターンします (spe_stop_info_t 構造体が指定されている場合には、この構造体に戻り値そのものが含まれます)。ls_base は、SPE のローカル・ストアがメモリーにマッピングされている実効アドレス (PPE プロセスの仮想アドレス) で、data_ptr は SPE から渡されたパラメーターへの SPE ポインターです。SPE のアドレス空間は PPE のアドレス空間にメモリー・マッピングされているため、SPE ローカル・ストアとの間でデータを移動するのは非常に簡単です。
data_ptr は SPE ポインターであることから、これには特別な処理が必要です。SPE ポインターは PPE プロセスのアドレス空間ではなく、ローカル・ストアのアドレス空間を参照することを思い出してください。つまり、SPE ポインターはすべて、間接参照される前に PPE アドレス空間に変換されなければならないということです。そのためには以下の作業が必要になります。
-
ls_base を char * により、演算の再にバイトとして処理するようにします。
- SPE ポインターを
ls_base に加えます。
- 結果を適切なポインター型にキャストします。
- 新しいポインターを割り当てるか、または間接参照します。
ポインターへのポインター (data_ptr が通常そうであるように) の場合の手順は、上述の手順を間接参照の各段階で行う必要があるため、多少難しくなります。
DMA の代わりにメモリーにマッピングされたローカル・ストアを使うことで、コールバックへの引数 (SPE のローカル・ストアにある引数) にアクセスしやすくなります。SPE のローカル・ストアにメモリーにマッピングされたインターフェースを介してアクセスすると、DMA ではなく MMIO を経由するため、速度が遅くなる場合があります。それでも、小さいデータを保存、取得する場合には、大きなデータ・セットの場合のようには問題になりません。この方法には、コールバック関数を実装する上で特に有効な 2 つの利点があります。
- メモリーにマッピングされたデータの転送では、DMA 転送の場合のように 16 バイトのデータ・アライメントを維持する必要がありません。
- メモリーにマッピングされたデータの転送では、DMA 転送を設定してこれが完了するまで待機するのではなく、短いアドレス空間への変換に続いてポインターの間接参照が行われるだけなので、遥かに実行しやすくなります。
いずれにしても、記載する例ではメモリーにマッピングされたアドレスを使ってローカル・ストアにアクセスしますが、遠慮なくお望みの通信方式を使って実装してください。
以下の例では、ストリング長を計算するコールバック関数を実装します。strlen() がすでに SPE の libc に実装されているため多少冗長になっていますが、戻り値、単純な引数があり、実装は単純なため、模範的な例となります。PPE 関数は以下のとおりです。
リスト 4. PPE コールバック関数の例
/* We are using this to make explicit what values are SPE addresses (which we treat as
offsets from ls_base) */
typedef unsigned int spe_offset_t;
/* This is our input/output structure */
typedef struct {
spe_offset_t str; /* Input param - this is an address on the SPE */
int length; /* Output param */
} my_strlen_param_t;
int my_strlen(void *ls_base_tmp, unsigned int data_offset) {
/* Convert the void pointer to a char pointer - this allows us to do byte offsets
into the memory-mapped address space */
char *ls_base = (char *)ls_base_tmp;
/* Grab the PPE memory-mapped pointer to the "params" pointer variable */
/* We sent ¶ms to this function, but data_offset actually has the value of
&(¶ms) */
spe_offset_t params_offset = *((spe_offset_t *)(ls_base + data));
/* Now use that to find the value of ¶ms */
my_strlen_param_t *params = (my_strlen_param_t *)(ls_base + params_offset);
/* Convert the SPE address of the string into the PPE memory-mapped address */
char *the_string = ls_base + params->str;
/* Calculate the length of the string and return it */
params->length = strlen(the_string);
/* Successful termination */
return 0;
}
|
実際のコードはこれで作成できましたが、この関数を実行する SPE のスタブを作成する必要がまだ残っています。libspe2 仕様によると、SPE は以下のアセンブリー言語命令のシーケンスでコールバックを使用しなければなりません。
stop 0x2110 #stop tells the SPE to stop running and signal the PPE, and passes the
value "0x2110"
#The "21" part of "0x2110" tells the PPE that you are requesting a
callback
#The "10" part of "0x2110" tells the PPE which callback you are
requesting
actual_data:
.word 0 #This is the "data" that will be transmitted to your program. We added
#the label actual_data so that values can be loaded into here before
#signalling the PPE
#Here is where execution continues. The callback mechanism jumps the "data" word when
returning.
|
お気付きかもしれませんが、このコードは数値 0x2110 で PPE コードを参照しています。16 進数字 21 はシグナリング・メカニズムにこれが PPE コールバックであることを指示し、16 進数字 10 は呼び出そうとしている特定のコールバックを参照しています。PPE 側では、それぞれのコールバックが 0x00 から 0xff までの特定の数値でコールバック・システムに登録されなければなりません。0 から 3 は、C99、POSIX、および Linux® 関数用に予約されています (これらの場合は、特定の関数を表す補助的な「オペコード」を最上位バイトに含めています)。コールバック関数を登録する際に使用するのは、spe_callback_handler_register です。最初のパラメーターは関数アドレス、2 番目のパラメーターは登録するコールバック番号、そして最後のパラメーターは SPE_CALLBACK_NEW となります。番号が使用中の場合はエラーがスローされるはずですが、この特定の機能には多少のバグがあります。そのため、コールバックが呼び出されていない場合には、別のコールバック番号に変えてみてください。
アセンブリー命令は自分で作成する必要がないので心配ご無用です。そのための便利な C 関数があります。C から呼び出しを行うには、C ライブラリーの __send_to_ppe 関数を使用してください。この関数が SPE を停止し、PPE にシグナルを送出し、そして単一引数を渡すために必要なアセンブリー言語の機能を実行してくれます。__send_to_ppe の呼び出しに使用する引数は以下の 3 つです。
- 最初の引数は PPE にシグナルを送ります。PPE コールバックは 16 進数字
21 で始まり、次の 2 つの 16 進数字が呼び出し対象のコールバック番号を参照します。
- 2 番目の引数は、複数の関数をコーディングするコールバックに使用する引数で、基本的にコールバック関数が値に応じて機能を切り替えられるようにする働きがあります。この値は基本的に、データ・ポインターの上位バイトに接続されます。大抵の単純なアプリケーションがこの引数に使用するのは 0 だけです。
- 3 番目の引数は、PPE に渡すデータ (通常はポインター) です。ただし、システムが実際に引数を渡すときには、3 番目のパラメーターの上位バイトが 2 番目のパラメーターの値に置き換えられることに注意してください。
__send_to_ppe はスタブの作成を極めて単純なものにします。ストリング長の例では、SPE スタブは以下のようになります。
#include <sys/send_to_ppe.h>
/* We could just use a pointer, but doing it this way will make it consistent in the
SPE and PPE */
typedef unsigned int spe_offset_t;
/* This is our input/output structure */
typedef struct {
spe_offset_t str; /* Input param - this is an address on the SPE */
int length; /* Output param */
} my_strlen_param_t;
int my_strlen(char *str) {
/* Construct parameters */
my_strlen_param_t params = { (spe_offset_t)str, 0 };
/* Signal PPE (returns when PPE is finished) */
__send_to_ppe(0x2110, 0, ¶ms);
/* Return the result */
return params.length;
}
|
以下は、コールバックを使用するプログラムの完全なリストです。まず初めに、PPE コードを記載します (callback_ppe.c として入力)。
リスト 5. コールバック関数を説明する PPE コード
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <libspe2.h>
#include <string.h>
/* Define Types */
typedef unsigned int spe_offset_t;
typedef struct {
spe_offset_t str;
int length;
} my_strlen_param_t;
/* Function Prototypes */
void *spe_test_function(void *data);
int my_strlen(void *ls_base, spe_offset_t data);
/* SPE Code Reference */
extern spe_program_handle_t test_handle;
/* PPE Callback Function */
int my_strlen(void *ls_base_tmp, unsigned int data) {
char *ls_base = (char *)ls_base_tmp;
spe_offset_t params_offset = *((spe_offset_t *)(ls_base + data));
my_strlen_param_t *params = (my_strlen_param_t *)(ls_base + params_offset);
char *the_string = ls_base + params->str;
params->length = strlen(the_string);
return 0;
}
/* Code to test our function */
int main() {
pthread_t my_thread;
int retval;
/* Register our callback */
spe_callback_handler_register(my_strlen, 0x10, SPE_CALLBACK_NEW);
retval = pthread_create(&my_thread, NULL, spe_test_function, NULL);
if(retval) {
fprintf(stderr, "Error creating thread! Exit code is: %d\n", retval);
exit(1);
}
retval = pthread_join(my_thread, NULL);
if(retval) {
fprintf(stderr, "Error joining thread! Exit code is: %d\n", retval);
exit(1);
}
return 0;
}
void *spe_test_function(void *data) {
int retval;
unsigned int entry_point = SPE_DEFAULT_ENTRY;
spe_context_ptr_t my_context;
my_context = spe_context_create(SPE_EVENTS_ENABLE|SPE_MAP_PS, NULL);
spe_program_load(my_context, &test_handle);
retval = spe_context_run(my_context, &entry_point, 0, NULL, NULL, NULL);
if(retval) {
perror("An error occurred running the SPE program");
}
pthread_exit(NULL);
}
|
今度は、スタブ、そしてこのスタブを使用するサンプル・コードの両方を実演する SPE コードを記載します (callback_spe.c として入力)。
リスト 6. PPE コールバックのスタブを作成して使用するプログラム
#include <sys/send_to_ppe.h>
/* Type declarations */
typedef unsigned int spe_offset_t;
typedef struct {
spe_offset_t str; /* Input param */
int length; /* Output param */
} my_strlen_param_t;
/* Function declarations */
int my_strlen(char *str);
/* Callback Stub */
int my_strlen(char *str) {
my_strlen_param_t params = { (spe_offset_t)str, 0 };
__send_to_ppe(0x2110, 0, ¶ms);
return params.length;
}
/* Example Usage */
int main(unsigned long long spe_id, unsigned long long argp, unsigned long long envp) {
char *my_str = "Hello there!";
printf("The length of '%s' is %d\n", my_str, my_strlen(my_str));
return 0;
}
|
ビルド方法は以下のとおりです。
spu-gcc callback_spe.c -o spe_callback
ppu-embedspu test_handle spe_callback spe_callback_csf.o
ppu-gcc -lspe2 -lpthread callback_ppe.c spe_callback_csf.o -o ppe_callback_example
|
libspe2 での problem state 関数
libspe2 での problem state 関数は、libspe1 のものと非常によく似ています。違いの 1 つは、すべての libspe2 関数は戻り値を状態に対してのみ使用し、結果を返すためには使用しないということです。libspe2 関数は成功するとゼロを返し、エラーが発生するとエラー・コードが errno に格納されます。もう 1 つの違いは、libspe1 関数は一般的に SPE スレッド ID (speid_t 型) を最初のパラメーターに使用するのに対し、libspe2 では通常、SPE コンテキスト・ポインター (spe_context_ptr_t 型) を使用するという点です。
以下に、libspe1 と libspe2 の関数の違いをいくつか抜粋します。
表 1. libspe1 と libspe2 の関数の相違点
| libspe1 関数 | libspe2 関数 | 注記 |
|---|
| spe_mfc_* (get、put、getb など) | spe_mfcio_* | これらの関数の機能は双方のシステムで同じです。 |
|---|
| spe_mfc_read_tag_status_* (all、any、または immediate) | spe_mfcio_tag_status_read | libspe2 関数は、4 番目のパラメーターを定数にして、使用する機能を指示することによって、3 つのlibspe1 関数の機能を 1 つにまとめています。また、libspe2 の5 番目のパラメーターは、戻り値を返すのではなく、戻り値へのポインターとなっています。 |
|---|
| spe_stat_*_mbox | spe_*_mbox_status | この 2 つの関数はほとんどそのまま対応します。 |
|---|
|
spe_read_out_mbox
| spe_out_mbox_read | libspe2 関数には 2 つのパラメーターが追加されています。2 番目のパラメーターは結果へのポインターです。また、libspe2 では この関数の単一の呼び出しで複数の結果を返すことができます。読み出す結果の最大数は 3 番目のパラメーターに指定します。この関数は読み出された結果の数も返します。結果が負の場合はエラーを示します。 |
|---|
| spe_write_in_mbox | spe_in_mobx_write | libspe2 関数のほうが遥かに柔軟性に優れています。2 番目のパラメーターは書き込む値の配列へのポインターで、3 番目のパラメーターに書き込み回数が格納されます。4 番目のパラメーターは振る舞いです。SPE_MBOX_ALL_BLOCKING の場合はこの関数のすべてのメッセージが書き込まれるまでブロックし、SPE_MBOX_ANY_BLOCKING の場合はメッセージのいずれか 1 つが書き込まれるまでブロックし、SPE_MBOX_ANY_NONBLOCKING の場合はブロックせずに書き込めるメッセージのみを書き込みます。この関数は、特定の振る舞いで書き込まれる可能性のあるメッセージ数を返します。エラーがあった場合は -1 を返します。 |
|---|
| spe_get_ls | spe_ls_area_get | この関数の戻り値は、SPE のローカル・ストアへのポインターです。エラーが発生すると NULL が戻され、errno が設定されます。 |
|---|

 |
まとめ
libspe2 への移行は、一層柔軟な SPE プロセス管理環境を実現します。2.1 SDK は正式に libspe1 を廃止する予定なので、libspe2 への移行は間もなく重要になるはずです。さらに libspe2 に追加で組み込まれたコールバック登録などの機能によって、SPE プログラミングがもっと簡単に行えるようになります。
参考文献 学ぶために
製品や技術を入手するために
議論するために
著者について
記事の評価
|