スレッド・バンドル
POSIXスレッド
今年は、1つのスレッド・バージョンからマルチスレッド・バージョンまでの最大確率関数を、そのコードの最も遅い部分がモデリング・グループIDのインデックス上でループするアーキテクチャ上の前提に基づいて、そのコードの最大確率関数を移植するように任命されました。これは、設計上、ループを通る各反復は残りの部分から独立している必要があります。
ループ時の楽しい問題
- 依存自動変数の再初期化に失敗し、
- モデリンググループIDでインデックス付けされた複数のグローバルポインタを変更します(
jG), - 計算専用のグローバル・メモリー・セグメントを(ID単位で)分離するには、thread_local変数が必要です。
1と3は簡単でした。2で、私はaの概念を含む賢いアルゴリズムを見つけましたTHREAD_BUNDLEシリアルモデリンググループIDのスレッド単位ブロックです。
保証THREAD_BUNDLE 少なくとも2のメモリページサイズを個々のポインタのサイズで割った大きさで、我々は異なるスレッドが独立して動作することを保証することができますページ 仮想メモリでは、これらのメモリ書き込みで相互排他ロックをエシェウできます。(もちろん、スレッドがそのスレッドを処理すると仮定します) THREAD_BUNDLE ほぼ同じ速度で)。
ついに削除しました。”同じ速度” ループを偶数/oddペアに分割することで、少なくとも1つのメモリーを保証します。ページ アクティブを分離THREAD_BUNDLE ループ。
コア・ループ
/* EVEN */
for (jG = minG; jG <= numG; jG += 2*THREAD_BUNDLE)
{
pthread_t ptid; 3 refs
arg_t* arg = mal (sizeof(*arg), "arg_t"); 12 refs
#define SET_ARG(foo) arg->foo = (foo) 30 refs
SET_ARG(jG);
...
#undef SET_ARG
// rsim_mlf_thread loops over the index bundle
// from jG to MIN(numG, jG + THREAD_BUNDLE - minG), doing
// stuff with global data structures also indexed by jG
pthread_create (&ptid, NULL, rsim_mlf_thread, arg);
PUSH_STACK_ELT(thread_stack, ptid, pthread_t);
}
{
pthread_t *ptid; 3 refs
while (POP_STACK_PTR(thread_stack, ptid, pthread_t) != NULL)
{
arg_t* arg; 6 refs
pthread_join(*ptid, (void**)&arg);
...
}
/* ODD */
for (jG = THREAD_BUNDLE + minG; jG <= numG; jG += 2*THREAD_BUNDLE)
{
pthread_t ptid; 3 refs
arg_t* arg = mal (sizeof(*arg), "arg_t"); 12 refs
...
