0

編集 3: グローバル メモリ内のプライベートな場所を読み書きするには、各スレッドが必要です。以下に、私の問題を示す実際のコードを投稿します。以下に、関連する主な変数と構造をリストします。

変数:

  • srcArr_h(ホスト) --> srcArr_d(デバイス) : 範囲 [0, COLORLEVELS]のランダムな float の配列ARRDIM
  • auxD(device) : 次元の配列ARRDIM*ARRDIM最終結果をデバイスに保持
  • auxH(ホスト) : 次元の配列ARRDIM*ARRDIMホストに最終結果を保持
  • c_glob_dCOLORLEVELS(device) :スレッドごとに float のプライベートな場所を予約する配列で、サイズはnum_threads*で指定されますCOLORLEVELS
  • idx(device) : 現在のスレッドの識別番号

私の問題: カーネルでは、c_glob[idx]各値ic( ic∈ [0, COLORLEVELS])を更新しますc_glob[idx][ic]。に格納されc_glob[idx][COLORLEVELS]ている最終結果を計算するために使用 します。私の問題は、私の最終結果が間違っていることです。auxH にコピーされた結果は、予想よりも少なくとも 1 桁大きい数値、または操作がオーバーフローする可能性が高いことを示唆する奇妙な数値を取得することを示しています。ヘルプ: 何が間違っていますか? 各スレッドがグローバル メモリ内の各プライベート ロケーションを読み書きできるようにするにはどうすればよいですか? 現在、 = 512 でデバッグしていますが、私の目標は~ 10^4 で動作させることです。したがって、g0auxD
ARRDIMARRDIMc_glob10^4*10^4 スレッドの配列)。実行ごとに許可されるスレッドの総数に問題があると思います..だから、私の問題に対する他の解決策を提案できるかどうか疑問に思っていました.
ありがとうございました。

#include <string>
#include <stdint.h>
#include <iostream>
#include <stdio.h>
#include "cuPrintf.cu"
using namespace std;

#define ARRDIM 512
#define COLORLEVELS 4

__global__ void gpuKernel
(
    float *sa, float *aux,
    size_t memPitchAux, int w,
    float *c_glob
)
{
    float sc_loc[COLORLEVELS];

    float g0=0.0f;

    int tidx = blockIdx.x * blockDim.x + threadIdx.x; 
    int tidy = blockIdx.y * blockDim.y + threadIdx.y; 

    int idx  = tidy * memPitchAux/4 + tidx;

    for(int ic=0; ic<COLORLEVELS; ic++)
    {
        sc_loc[ic] = ((float)(ic*ic));
    }

    for(int is=0; is<COLORLEVELS; is++)
    {
        int ic = fabs(sa[tidy*w +tidx]);
        c_glob[tidy * COLORLEVELS + tidx + ic] += 1.0f;
    }

    for(int ic=0; ic<COLORLEVELS; ic++)
    {
        g0 += c_glob[tidy * COLORLEVELS + tidx + ic]*sc_loc[ic];
    }

    aux[idx] = g0;
}

int main(int argc, char* argv[])
{
    /*
     * array src host and device
     */
    int heightSrc = ARRDIM;
    int widthSrc = ARRDIM;
    cudaSetDevice(0);

    float *srcArr_h, *srcArr_d;
    size_t nBytesSrcArr = sizeof(float)*heightSrc * widthSrc;

    srcArr_h = (float *)malloc(nBytesSrcArr); // Allocate array on host
    cudaMalloc((void **) &srcArr_d, nBytesSrcArr); // Allocate array on device
    cudaMemset((void*)srcArr_d,0,nBytesSrcArr); // set to zero

    int totArrElm = heightSrc*widthSrc;

    for(int ic=0; ic<totArrElm; ic++)
    {
        srcArr_h[ic] = (float)(rand() % COLORLEVELS);
    }

    cudaMemcpy( srcArr_d, srcArr_h,nBytesSrcArr,cudaMemcpyHostToDevice);

    /*
     * auxiliary buffer auxD to save final results
     */
    float *auxD;
    size_t auxDPitch;
    cudaMallocPitch((void**)&auxD,&auxDPitch,widthSrc*sizeof(float),heightSrc);
    cudaMemset2D(auxD, auxDPitch, 0, widthSrc*sizeof(float), heightSrc);

    /*
     * auxiliary buffer auxH allocation + initialization on host
     */
    size_t auxHPitch;
    auxHPitch = widthSrc*sizeof(float);
    float *auxH = (float *) malloc(heightSrc*auxHPitch);

    /*
     * kernel launch specs
     */
    int thpb_x = 16;
    int thpb_y = 16;

    int blpg_x = (int) widthSrc/thpb_x;
    int blpg_y = (int) heightSrc/thpb_y;
    int num_threads = blpg_x * thpb_x + blpg_y * thpb_y;

    /* 
     * c_glob: array that reserves a private location of COLORLEVELS floats for each thread
     */
    int cglob_w = COLORLEVELS;
    int cglob_h = num_threads;

    float *c_glob_d;
    size_t c_globDPitch;
    cudaMallocPitch((void**)&c_glob_d,&c_globDPitch,cglob_w*sizeof(float),cglob_h);
    cudaMemset2D(c_glob_d, c_globDPitch, 0, cglob_w*sizeof(float), cglob_h);

    /*
    * kernel launch
    */
    dim3 dimBlock(thpb_x,thpb_y, 1);
    dim3 dimGrid(blpg_x,blpg_y,1);

    gpuKernel<<<dimGrid,dimBlock>>>(srcArr_d,auxD, auxDPitch, widthSrc, c_glob_d);

    cudaThreadSynchronize();

    cudaMemcpy2D(auxH,auxHPitch, 
                 auxD,auxDPitch,  
                 auxHPitch, heightSrc,
                 cudaMemcpyDeviceToHost);
    cudaThreadSynchronize();

    float min = auxH[0];
    float max = auxH[0];
    float f;
    string str;

    for(int i=0; i<widthSrc*heightSrc; i++)
    {

        if(min > auxH[i])
            min = auxH[i];
        if(max < auxH[i])
            max = auxH[i];
    }
    cudaFree(srcArr_d);
    cudaFree(auxD);
    cudaFree(c_glob_d);

}
4

1 に答える 1

1

コード全体を表示しないことも、問題を再現する縮小サイズを表示しないことも決定しました。したがって、以下の解決策をテストして検証することはできませんでした。

問題の原因を突き止めたと思います。複数のスレッドが同じメモリ位置に並行して書き込もうとしています。これは競合状態につながる状況です。例として、プレゼンテーションの 4 番目のスライド「CUDA C: 競合状態、アトミック、ロック、ミューテックス、およびワープ」を参照してください。

競合状態には力ずくの解決策があります: アトミック関数です。それらについては、CUDA C プログラミング ガイドのセクション B.12 で説明されています。したがって、行を変更して問題を解決することができます

c[ic] += 1.0f;

atomicAdd(&c[ic],1);

この修正にはパフォーマンスが伴います。アトミック操作は、競合状態を回避するためにコードをシリアル化します。

アトミック関数は、実装を適切に再考することにより、それらを回避する方法を見つけることができるため、問題に対する力ずくの解決策であると述べました。しかし、あなたが提供した詳細が非常に少ないため、現時点ではこれを言うことはできません.

于 2013-11-16T21:55:20.547 に答える