1

ビデオ フレーム データに対して何らかの処理を実行するアプリケーションを開発しています。それを高速化するために、2 枚のグラフィック カードを使用し、OpenCL でデータを処理します。私の考えは、1 つのフレームを最初のカードに送信し、別のフレームを 2 番目のカードに送信することです。デバイスは同じコンテキストを使用しますが、異なるコマンド キュー、カーネル、およびメモリ オブジェクトを使用します。

ただし、2枚のカードで必要な時間は1枚のグラフィックカードで必要な時間とほぼ同じであるため、計算は並行して実行されないように思えます。

独立したデータに対して複数のデバイスを同時に使用する良い例はありますか?

前もって感謝します。

編集:

2 つの別々のコンテキストに切り替えた後の結果のコードを次に示します。ただし、グラフィック カードが 2 枚の場合の実行時間は、グラフィック カードが 1 枚の場合と同じままです。

    cl::NDRange globalws(imageSize);
    cl::NDRange localws;

    for (int i = 0; i < numDevices; i++){
            // Copy the input data to the device
            commandQueues[i].enqueueWriteBuffer(inputDataBuffer[i], CL_TRUE, 0, imageSize*sizeof(float), wt[i].data);

            // Set kernel arguments
            kernel[i].setArg(0, inputDataBuffer[i]);

            kernel[i].setArg(1, modulusBuffer[i]);
            kernel[i].setArg(2, imagewidth);
        }

        for (int i = 0; i < numDevices; i++){
            // Run kernel
            commandQueues[i].enqueueNDRangeKernel(kernel[i], cl::NullRange, globalws, localws);
        }

        for (int i = 0; i < numDevices; i++){
            // Read the modulus back to the host
            float* modulus = new float[imageSize/4];
            commandQueues[i].enqueueReadBuffer(modulusBuffer[i], CL_TRUE, 0, imageSize/4*sizeof(float), modulus);

            // Do something with the modulus;
        }
4

1 に答える 1

3

あなたの主な問題は、ブロッキング呼び出しを使用していることです。そのように操作すれば、いくつのデバイスを持っていても問題ありません。操作を実行し、それが完了するのを待っているため、並列化はまったくありません (またはほとんどありません)。あなたは現時点でこれを行っています:

Wr:-Copy1--Copy2--------------------
G1:---------------RUN1--------------
G2:---------------RUN2--------------
Re:-------------------Read1--Read2--

少なくとも次のようにコードを変更する必要があります。

Wr:-Copy1-Copy2-----------
G1:------RUN1-------------
G2:------------RUN2-------
Re:----------Read1-Read2--

このコードで:

cl::NDRange globalws(imageSize);
cl::NDRange localws;

for (int i = 0; i < numDevices; i++){
        // Set kernel arguments //YOU SHOULD DO THIS AT INIT STAGE, IT IS SLOW TO DO IT IN A LOOP
        kernel[i].setArg(0, inputDataBuffer[i]);

        kernel[i].setArg(1, modulusBuffer[i]);
        kernel[i].setArg(2, imagewidth);

        // Copy the input data to the device
        commandQueues[i].enqueueWriteBuffer(inputDataBuffer[i], CL_FALSE, 0, imageSize*sizeof(float), wt[i].data);
    }

    for (int i = 0; i < numDevices; i++){
        // Run kernel
        commandQueues[i].enqueueNDRangeKernel(kernel[i], cl::NullRange, globalws, localws);
    }

    float* modulus[numDevices];
    for (int i = 0; i < numDevices; i++){
        // Read the modulus back to the host
        modulus[i] = new float[imageSize/4];
        commandQueues[i].enqueueReadBuffer(modulusBuffer[i], CL_FALSE, 0, imageSize/4*sizeof(float), modulus[i]);
    }

    clFinish();

        // Do something with the modulus;

複数のコンテキストを持つコメントに関しては、両方の GPU を通信するかどうかによって異なります。GPU がメモリのみを使用する限り、コピー オーバーヘッドは発生しません。ただし、カーネル引数を常に設定/設定解除すると、他の GPU へのコピーがトリガーされます。だから、それに注意してください。

GPU 間の非通信に対するより安全なアプローチは、さまざまなコンテキストです。


あなたの主な問題は、カーネルの実行ではなくメモリのコピーであると思われます。メモリのレイテンシを非表示にすると、1 つの GPU でニーズを満たす可能性が高くなります。

Wr:-Copy1-Copy2-Copy3----------
G1:------RUN1--RUN2--RUN3------
Re:----------Read1-Read2-Read3-
于 2014-06-03T10:23:32.740 に答える