6

私はOpenCLの初心者です。ただし、C/C++ の基本と OOP は理解しています。私の質問は次のとおりです。合計計算タスクを並行して実行することは何とか可能ですか? 理論上は可能ですか?以下に、私がやろうとしたことを説明します。

タスクは、たとえば次のとおりです。

double* values = new double[1000]; //let's pretend it has some random values inside
double sum = 0.0;

for(int i = 0; i < 1000; i++) {
    sum += values[i];
}

私が OpenCL カーネルでやろうとしたこと (おそらく、異なるスレッド/タスクから同じ「合計」変数に同時にアクセスするため、間違っていると感じます):

__kernel void calculate2dim(__global float* vectors1dim,
                            __global float output,
                            const unsigned int count) {
    int i = get_global_id(0);
    output += vectors1dim[i];
}

このコードは間違っています。そのようなタスクを並行して実行することが理論的に可能であるかどうか、そして可能である場合、誰かが私に答えてくれれば非常に感謝します-どのように!

4

2 に答える 2

1

配列の値を並列に合計する場合は、競合を減らし、スレッド間でデータの依存関係がないことを確認する必要があります。

データの依存関係により、スレッドは互いに待機する必要があり、競合が発生します。これは、真の並列化を実現するために避けたいことです。

これを行う1つの方法は、配列をN個の配列に分割し、それぞれに元の配列のサブセクションを含めてから、異なる配列ごとにOpenCLカーネル関数を呼び出すことです。

最後に、すべてのカーネルがハードワークを完了したら、各配列の結果を1つにまとめることができます。この操作はCPUで簡単に行えます。

重要なのは、各カーネルで実行される計算間に依存関係がないことです。そのため、データを分割し、それに応じて処理する必要があります。

あなたのデータにあなたの質問からの実際の依存関係があるかどうかはわかりませんが、それはあなたが理解するためのものです。

于 2013-03-04T11:15:07.813 に答える
-1

私が参照用に提供したコードの一部は、その仕事をするはずです。

たとえば、 N個の要素があり、ワークグループのサイズはWS=64です。N2*WSの倍数であると仮定します(これは重要です。1つのワークグループが2 * WS要素の合計を計算します)。次に、以下を指定してカーネルを実行する必要があります。

globalSizeX = 2*WS*(N/(2*WS));

結果として、合計配列には2*WS要素の部分的な合計が含まれます。(例:sum[1] -インデックスが2*WSから4* WS-1までの要素の合計が含まれます)。

globalSizeXが2*WS以下の場合(つまり、ワークグループが1つしかない場合)、これで完了です。結果としてsum[0]を使用するだけです。そうでない場合は、手順を繰り返す必要があります。今回は、sum配列を入力配列として使用し、他の配列に出力します(2つの配列を作成し、それらの間にピンポンします)。など、ワークグループが1つだけになるまで続きます。

Hilli Steele/Blelloch並列アルゴリズムも検索してください。 この記事も役立つかもしれません

実際の例は次のとおりです。

__kernel void par_sum(__global unsigned int* input, __global unsigned int* sum)
{
    int li = get_local_id(0);
    int groupId = get_group_id(0);

    __local int our_h[2 * get_group_size(0)];
    our_h[2*li + 0] = hist[2*get_group_size(0)*blockId + 2*li + 0];
    our_h[2*li + 1] = hist[2*get_group_size(0)*blockId + 2*li + 1];

    // sweep up
    int width = 2;
    int num_el = 2*get_group_size(0)/width;
    int wby2 = width>>1;

    for(int i = 2*BLK_SIZ>>1; i>0; i>>=1)
    {

        barrier(CLK_LOCL_MEM_FENCE);

        if(li < num_el)
        {
            int idx = width*(li+1) - 1;
            our_h[idx] = our_h[idx] + our_h[(idx - wby2)];
        }

        width<<=1;
        wby2 = width>>1;
        num_el>>=1;
    }

        barrier(CLK_LOCL_MEM_FENCE);

    // down-sweep
    if(0 == li)
        sum[groupId] = our_h[2*get_group_size(0)-1]; // save sum
}
于 2013-03-06T16:16:50.110 に答える