0

Cuda で書かれたコードを openCL に変換しようとしていて、問題が発生しました。最終的な目標は、Mali T628 GPU を搭載した Odroid XU3 ボードにコードを実装することです。

移行を簡素化し、openCL カーネルをデバッグする時間を節約するために、次の手順を実行しました。

  1. コードを Cuda に実装し、Nvidia GeForce 760 でテストする
  2. コードを openCL に実装し、Nvidia GeForce 760 でテストします。
  3. Mali T628 GPU を搭載した Odroid XU3 ボードで openCL コードをテストします。

アーキテクチャが異なれば最適化も異なる可能性があることは知っていますが、それは今のところ私の主な関心事ではありません。Nvidia GPU で openCL コードを問題なく実行できましたが、Odroid ボードでコードを実行しようとすると奇妙なエラーが発生し続けます。アーキテクチャが異なれば、例外などの処理も​​異なることは知っていますが、それらを解決する方法がわかりません。

私の Nvidia では openCL コードが動作するので、スレッド/ブロック -> workItems/workGroups などの間で正しい移行を行うことができたと思います。

コードを実行すると、「CL_OUT_OF_RESOURCES」エラーが発生します。エラーの原因をコード内の 2 行に絞り込みましたが、これらの問題を修正できるかどうかはわかりません。

エラーは次の行によって発生します。

  1. lowerDist[pixelNum] = partialDiffSumTemp; 両方の変数はカーネルのプライベート変数であるため、潜在的な問題は見られません。
  2. d_disparityLeft[globalMemIdx + TILE_BOUNDARY_WIDTH - WINDOW_RADIUS + 0] = bestDisparity[0]; ここで、原因は「OUT_OF_BOUND」だと思いますが、元のコードには問題がないため、デバッグ方法がわかりません。

私のカーネルコードは次のとおりです。

#define ALIGN_IMAGE_WIDTH          64
#define NUM_PIXEL_PER_THREAD        4

#define MIN_DISPARITY               0  
#define MAX_DISPARITY              55  

#define WINDOW_SIZE                19 
#define WINDOW_RADIUS              (WINDOW_SIZE / 2)   

#define TILE_SHARED_MEM_WIDTH      96                       
#define TILE_SHARED_MEM_HEIGHT     32
#define TILE_BOUNDARY_WIDTH        64
#define TILE_BOUNDARY_HEIGHT       (2 * WINDOW_RADIUS)

#define BLOCK_WIDTH                (TILE_SHARED_MEM_WIDTH  - TILE_BOUNDARY_WIDTH) 
#define BLOCK_HEIGHT               (TILE_SHARED_MEM_HEIGHT - TILE_BOUNDARY_HEIGHT)  

#define THREAD_NUM_WIDTH            8
#define THREADS_NUM_HEIGHT         TILE_SHARED_MEM_HEIGHT

 //TODO fix input arguments
__kernel void hello_kernel( __global unsigned char*  d_leftImage,
                            __global unsigned char*  d_rightImage,
                            __global float* d_disparityLeft) {

    int blockX      = get_group_id(0);
    int blockY      = get_group_id(1);
    int threadX     = get_local_id(0);
    int threadY     = get_local_id(1);

    __local unsigned char leftImage      [TILE_SHARED_MEM_WIDTH * TILE_SHARED_MEM_HEIGHT];
    __local unsigned char rightImage     [TILE_SHARED_MEM_WIDTH * TILE_SHARED_MEM_HEIGHT];
    __local unsigned int  partialDiffSum [BLOCK_WIDTH           * TILE_SHARED_MEM_HEIGHT];

    int alignedImageWidth = 640;
    int partialDiffSumTemp;
    float bestDisparity[4] = {0,0,0,0};
    int lowestDist[4];
        lowestDist[0] = 214748364;
        lowestDist[1] = 214748364;
        lowestDist[2] = 214748364;
        lowestDist[3] = 214748364;

    // Read image blocks into shared memory. read is done at 32bit integers on a uchar array. each thread reads 3 integers(12byte) 96/12=8threads
    int sharedMemIdx = threadY * TILE_SHARED_MEM_WIDTH + 4 * threadX; 
    int globalMemIdx = (blockY * BLOCK_HEIGHT + threadY) * alignedImageWidth + blockX * BLOCK_WIDTH + 4 * threadX; 

    for (int i = 0; i < 4; i++) {
        leftImage [sharedMemIdx                        + i ] = d_leftImage [globalMemIdx                        + i];
        leftImage [sharedMemIdx + 4 * THREAD_NUM_WIDTH + i ] = d_leftImage [globalMemIdx + 4 * THREAD_NUM_WIDTH + i];
        leftImage [sharedMemIdx + 8 * THREAD_NUM_WIDTH + i ] = d_leftImage [globalMemIdx + 8 * THREAD_NUM_WIDTH + i];
        rightImage[sharedMemIdx                        + i ] = d_rightImage[globalMemIdx                        + i];
        rightImage[sharedMemIdx + 4 * THREAD_NUM_WIDTH + i ] = d_rightImage[globalMemIdx + 4 * THREAD_NUM_WIDTH + i];
        rightImage[sharedMemIdx + 8 * THREAD_NUM_WIDTH + i ] = d_rightImage[globalMemIdx + 8 * THREAD_NUM_WIDTH + i];
    }

    barrier(CLK_LOCAL_MEM_FENCE);

    int imageIdx = sharedMemIdx + TILE_BOUNDARY_WIDTH - WINDOW_RADIUS;
    int partialSumIdx = threadY * BLOCK_WIDTH + 4 * threadX;

    for(int dispLevel = MIN_DISPARITY; dispLevel <= MAX_DISPARITY; dispLevel++) {

        // horizontal partial sum
        partialDiffSumTemp = 0;
        #pragma unroll
        for(int i = imageIdx - WINDOW_RADIUS; i <= imageIdx + WINDOW_RADIUS; i++) {
                    //partialDiffSumTemp += calcDiff(leftImage [i], rightImage[i - dispLevel]);
                      partialDiffSumTemp += abs(leftImage[i] - rightImage[i - dispLevel]);
        }
        partialDiffSum[partialSumIdx] = partialDiffSumTemp;

        barrier(CLK_LOCAL_MEM_FENCE);

        for (int pixelNum = 1, i = imageIdx - WINDOW_RADIUS; pixelNum < NUM_PIXEL_PER_THREAD; pixelNum++, i++) {
            partialDiffSum[partialSumIdx + pixelNum] = partialDiffSum[partialSumIdx + pixelNum - 1] + 
                                                       abs(leftImage[i + WINDOW_SIZE] - rightImage[i - dispLevel + WINDOW_SIZE]) -
                                                       abs(leftImage[i]               - rightImage[i - dispLevel]);
        }

        barrier(CLK_LOCAL_MEM_FENCE);

        // vertical sum
        if(threadY >= WINDOW_RADIUS && threadY < TILE_SHARED_MEM_HEIGHT - WINDOW_RADIUS) {

            for (int pixelNum = 0; pixelNum < NUM_PIXEL_PER_THREAD; pixelNum++) {
                int rowIdx = partialSumIdx - WINDOW_RADIUS * BLOCK_WIDTH;
                partialDiffSumTemp = 0;

                    for(int i = -WINDOW_RADIUS; i <= WINDOW_RADIUS; i++,rowIdx += BLOCK_WIDTH) {
                           partialDiffSumTemp += partialDiffSum[rowIdx + pixelNum];
                    }

                    if (partialDiffSumTemp < lowestDist[pixelNum]) {
                        lowestDist[pixelNum]    = partialDiffSumTemp;
                        bestDisparity[pixelNum] = dispLevel - 1;
                    }


            }
        }

    }

    if (threadY >= WINDOW_RADIUS && threadY < TILE_SHARED_MEM_HEIGHT - WINDOW_RADIUS && blockY < 32) {

        d_disparityLeft[globalMemIdx + TILE_BOUNDARY_WIDTH - WINDOW_RADIUS + 0] = bestDisparity[0];
        d_disparityLeft[globalMemIdx + TILE_BOUNDARY_WIDTH - WINDOW_RADIUS + 1] = bestDisparity[1];
        d_disparityLeft[globalMemIdx + TILE_BOUNDARY_WIDTH - WINDOW_RADIUS + 2] = bestDisparity[2];
        d_disparityLeft[globalMemIdx + TILE_BOUNDARY_WIDTH - WINDOW_RADIUS + 3] = bestDisparity[3];
    }

}

助けてくれてありがとう

ユヴァル

4

1 に答える 1

0

私の経験から、NVidia GPU が境界外アクセスで常にクラッシュするとは限らず、多くの場合、カーネルは依然として期待どおりの結果を返します。

printfインデックスを確認するために使用します。Nvidia OpenCL 1.2 ドライバーがインストールされている場合printfは、コア機能として利用できるはずです。Mali-T628がOpenCL 1.1を使用していることを確認した限りprintf、ベンダー拡張として利用できるかどうかを確認してください。printfまた、利用可能な AMD/Intel CPU (OpenCL 1.2 / 2.0)でカーネルを実行することもできます。

インデックスをチェックする別の方法は、インデックスを__global int* debug格納する場所に配列を渡してから、ホスト上でそれらをチェックすることです。範囲外のインデックスが記録されるように、十分な大きさを割り当ててください。

于 2015-06-07T19:28:30.867 に答える