私の状況: ワープ内の各スレッドは、完全に独立した個別のデータ配列で動作します。すべてのスレッドは、データ配列をループします。ループの反復回数はスレッドごとに異なります。(これには費用がかかります、私は知っています)。
for ループ内で、各スレッドは 3 つの float を計算した後、最大値を保存する必要があります。for ループの後、ワープ内のスレッドは、ワープ内の「隣接スレッド」のみによって計算された最大値をチェックすることによって「通信」します(パリティによって決定されます)。
質問:
- 乗算を行って「最大」操作の条件を回避すると、ワープの発散が回避されますよね? (以下のコード例を参照)
- (1.) で述べた余分な乗算操作は価値がありますよね? - つまり、あらゆる種類のワープ発散よりもはるかに高速です。
- ワープ発散 (すべてのスレッドに対して 1 セットの命令) を引き起こす同じメカニズムは、for ループの最後で暗黙的な「スレッド バリア」(ワープ用) として利用できます (「#pragma非 GPU コンピューティングでの omp for" ステートメント)。したがって、あるスレッドが別のスレッドによって保存された値をチェックする前に、for ループの後でワープの「syncthreads」呼び出しを行う必要はありません。(これは、「シンスレッド」が「GPU 全体」、つまりインターワープとインター MP のみを対象としているためですよね?)
コード例:
__shared__ int N_per_data; // loaded from host
__shared__ float ** data; //loaded from host
data = new float*[num_threads_in_warp];
for (int j = 0; j < num_threads_in_warp; ++j)
data[j] = new float[N_per_data[j]];
// the values of jagged matrix "data" are loaded from host.
__shared__ float **max_data = new float*[num_threads_in_warp];
for (int j = 0; j < num_threads_in_warp; ++j)
max_data[j] = new float[N_per_data[j]];
for (uint j = 0; j < N_per_data[threadIdx.x]; ++j)
{
const float a = f(data[threadIdx.x][j]);
const float b = g(data[threadIdx.x][j]);
const float c = h(data[threadIdx.x][j]);
const int cond_a = (a > b) && (a > c);
const int cond_b = (b > a) && (b > c);
const int cond_c = (c > a) && (c > b);
// avoid if-statements. question (1) and (2)
max_data[threadIdx.x][j] = conda_a * a + cond_b * b + cond_c * c;
}
// Question (3):
// No "syncthreads" necessary in next line:
// access data of your mate at some magic positions (assume it exists):
float my_neighbors_max_at_7 = max_data[threadIdx.x + pow(-1,(threadIdx.x % 2) == 1) ][7];
アルゴリズムを GPU に実装する前に、アルゴリズムのあらゆる側面を調査して、実装作業に見合うだけの価値があることを確認しています。だから我慢してください..