0

2D 配列にcudaMallocPitchandを使用しています。cudaMemcpy2D出力を正しく取得できなかったとしても、正しくコーディングしたかどうかはわかりません。誰でも助けてもらえますか?誰でも私のエラーをデバッグできますか? 前もって感謝します。

#include<stdio.h>
#include<cuda.h>
#define siz 4*sizeof(int)
__global__ void addmatrix(int *m1,int *m2,size_t pitch)
{
    int r=threadIdx.x;
    int *r1=m1+r*pitch;
    int *r2=m2+r*pitch;
    int c;
    for(c=1;c<=4;c++)
    {
        r1[c]+=r2[c];
    }
}
int main()
{
    int i,j;
    int **m1_c,**m2_c;
    int *m1_d,*m2_d;
    size_t pitch;
    cudaError_t err;
    m1_c=(int **)malloc(4*sizeof(int *));
    for(i=1;i<=4;i++)
    {
        m1_c[i]=(int *)malloc(siz);
    }
    m2_c=(int **)malloc(4*sizeof(int *));
    for(i=1;i<=4;i++)
    {
        m2_c[i]=(int *)malloc(siz);
    }
    for(i=1;i<=4;i++)
    {
        for(j=1;j<=4;j++)
        {
            m1_c[i][j]=rand()%10;
            m2_c[i][j]=rand()%10;
        }
    }
    for(i=1;i<=4;i++)
    {
        for(j=1;j<=4;j++)
        {
            printf("%d\t",m1_c[i][j]);
        }
        printf("\n");
    }
    printf("\n\n");
    for(i=1;i<=4;i++)
    {
        for(j=1;j<=4;j++)
        {
            printf("%d\t",m2_c[i][j]);
        }
        printf("\n");
    }
    err=cudaMallocPitch((void **)&m1_d,&pitch,siz,siz);
    err=cudaMallocPitch((void **)&m2_d,&pitch,siz,siz);
    err=cudaMemcpy2D(m1_d,pitch,m1_c,siz,siz,4,cudaMemcpyHostToDevice);
    err=cudaMemcpy2D(m2_d,pitch,m2_c,siz,siz,4,cudaMemcpyHostToDevice);
    dim3 grid(1);
    dim3 block(16);
    addmatrix<<<grid,block>>>(m1_d,m2_d,siz);
    cudaMemcpy2D(m1_c,siz,m1_d,pitch,siz,4,cudaMemcpyDeviceToHost);

    for(i=1;i<=4;i++)
    {
        for(j=1;j<=4;j++)
        {
            printf("%d\t",m1_c[i][j]);
        }
        printf("\n");
    }
    err=cudaFree(m1_d);
    err=cudaFree(m2_d);
    err=cudaDeviceReset();      
}
4

1 に答える 1

1

したがって、このコードにはいくつかの問題があります。順不同:

  1. 1 から 4 までのさまざまな配列にインデックスを付けていますが、これは C では正しくありません。C のインデックス付けはゼロから始まり、次元より 1 つ小さい値になります。これはCUDAとは関係ありません。
  2. cudaMemcpy2Dは、メモリ内の線形配列へのポインタである2 つのポインタ (srcおよび) を想定しています。dst説明全体に2Dが登場するため、これは紛らわしいと思いますが、2つのポインターパラメーターは基本的に両方とも同じタイプ(メモリへのポインター)であり、2つの異なるタイプのポインターを渡しています(1つはメモリーへのポインター、もう1つはメモリーへのポインターです)。はメモリへのポインタへのポインタです)。cudaMemcpy2D の定義から明らかなように、あなたの使い方は正しくありません。cudaMemcpy2D の使用方法に関する例を含む多くの回答済みの質問があります。それらのいくつかを検索して確認することをお勧めします。この問題を修正すると、ホスト マトリックスにデータを格納する方法を根本的に考え直す必要があることに注意してください。このような質問がたくさんあります多次元行列の処理について -- 可能であれば、それらを平坦化する必要があります。現在のコードでは、cudaMemcpy2D の使用に関するこのエラーは、ホスト マトリックスのポインター配列を破壊していることに注意してください。結果を印刷しようとすると、セグ フォールトが発生します。
  3. cudaMallocPitchに渡されたパラメータが正しくありません。渡している パラメータwidthとパラメータの両方について、これはバイト単位の行列次元です。ただし、パラメーターのバイト次元のみを渡す必要があります。パラメータには、行数、つまりあなたの場合は 4 を渡す必要があります。cudaMemcpy2D の呼び出しにも同様の要件がありますが、すぐに取得できます。heightsizwidthheight
  4. 次に、カーネルを見てみましょう。呼び出しでは、16 スレッドの 1 ブロックのグリッドを起動しています。あなたの行列には16個の要素があるので、それは理にかなっているようです。これは、各スレッドが結果の単一要素を担当するスレッド戦略を意味します。しかし、カーネル コードを見ると、各スレッドが行全体、つまり 4 つの要素の結果を計算しています。これを修正するには 2 つの方法があります。グリッドを 16 スレッドではなく 4 スレッドに減らすか (コード変更の観点からすると、おそらくより単純です)、またはカーネルを書き直して (for ループを削除して)、各スレッドは単一の出力要素を計算します (おそらく、より多くの作業を並行して実行します)。
  5. さらに、カーネルではpitch、ポインター演算ベースのインデックス作成でパラメーターを使用しています。ただし、ピッチはバイト単位であり、ポインター算術インデックスの場合、コンパイラーはパラメーターが要素内にあることを期待していることに注意してください。データ型に基づいて、バイトへの変換が行われます。繰り返しますが、これは実際には C の問題であり、CUDA に固有のものではありません。これは、カーネルで(pitch/sizeof(int))使用している場所を使用して修正できます。pitch
  6. sizあなたはピッチをカーネルに渡しています。pitchピッチパラメータを渡す必要があります。siz実質的にはホスト データ ストレージの「ピッチ」pitchですが、デバイス上のストレージのピッチです。カーネルはデバイス ストレージで動作しているため、正しいピッチが必要です。
  7. 推奨事項として、すべての cuda API 呼び出しとカーネル呼び出しでcuda エラー チェックを実行します。

上記の問題すべてに何らかの方法で対処するコードを次に示します。

#include<stdio.h>
#define siz (4*sizeof(int))

#define cudaCheckErrors(msg) \
    do { \
        cudaError_t __err = cudaGetLastError(); \
        if (__err != cudaSuccess) { \
            fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
                msg, cudaGetErrorString(__err), \
                __FILE__, __LINE__); \
            fprintf(stderr, "*** FAILED - ABORTING\n"); \
            exit(1); \
        } \
    } while (0)

__global__ void addmatrix(int *m1,int *m2,size_t pitch)
{
    int r=threadIdx.x;
    int *r1=m1+r*(pitch/sizeof(int));
    int *r2=m2+r*(pitch/sizeof(int));
    int c;
    for(c=0;c<4;c++)
    {
        r1[c]+=r2[c];
    }
}
int main()
{
    int i,j;
    int *m1_c,*m2_c;
    int *m1_d,*m2_d;
    size_t pitch;
    cudaError_t err;
    m1_c=(int *)malloc(16*sizeof(int));
    m2_c=(int *)malloc(16*sizeof(int));
    for(i=0;i<4;i++)
    {
        for(j=0;j<4;j++)
        {
            m1_c[(i*4)+j]=rand()%10;
            m2_c[(i*4)+j]=rand()%10;
        }
    }
    for(i=0;i<4;i++)
    {
        for(j=0;j<4;j++)
        {
            printf("%d\t",m1_c[(i*4)+j]);
        }
        printf("\n");
    }
    printf("\n\n");
    for(i=0;i<4;i++)
    {
        for(j=0;j<4;j++)
        {
            printf("%d\t",m2_c[(i*4)+j]);
        }
        printf("\n");
    }
    err=cudaMallocPitch((void **)&m1_d,&pitch,siz,4);
    cudaCheckErrors("cm1");
    err=cudaMallocPitch((void **)&m2_d,&pitch,siz,4);
    cudaCheckErrors("cm2");
    err=cudaMemcpy2D(m1_d,pitch,m1_c,siz,siz,4,cudaMemcpyHostToDevice);
    cudaCheckErrors("cm3");
    err=cudaMemcpy2D(m2_d,pitch,m2_c,siz,siz,4,cudaMemcpyHostToDevice);
    cudaCheckErrors("cm4");
    dim3 grid(1);
    dim3 block(4);
    addmatrix<<<grid,block>>>(m1_d,m2_d,pitch);
    cudaMemcpy2D(m1_c,siz,m1_d,pitch,siz,4,cudaMemcpyDeviceToHost);
    cudaCheckErrors("cm5");

    for(i=0;i<4;i++)
    {
        for(j=0;j<4;j++)
        {
            printf("%d\t",m1_c[(i*4)+j]);
        }
        printf("\n");
    }
    err=cudaFree(m1_d);
    err=cudaFree(m2_d);
    err=cudaDeviceReset();
}
于 2013-04-04T18:04:53.100 に答える