2

2 つの行列の対応する行を追加する cuda カーネルの非常に単純な例があります。行列のメモリ アクセスについて質問があります。mexfunction を介してカーネルを呼び出します。matlab では列優先の順序でアクセスし、C/C++ では行優先の順序でアクセスすることがわかっています。cuda メモリ構成に基づいて、各ブロックとスレッドのグリッド内に座標 (x,y) があります。行/列優先の順序 [ 1]。最初のカーネルでは、間違っていたら訂正してください。2 番目のカーネルでは行優先のアクセスであるのに対し、列優先のアクセスがあります。両方のカーネルは、同じパラメーター、ブロック数、およびフレーム数で初期化されます。私は、行列の行優先順アクセスを使用する 2 番目のカーネルが、C++ の場合と同様に、行列にアクセスする正しい方法であると信じていました。残念ながら、列優先のカーネルは、アルゴリズムに従って正しい結果を返します。誰か良い説明がありますか?この観察結果は、mexfunction を介してカーネルを呼び出すという事実と関係がありますか?これは、matlab を意味し、結果として列優先のアクセスを意味しますか?

両方のカーネルは次のように呼ばれます。

int numElements =  rows * cols; // rows and cols of d_A or d_B
int threadsPerBlock = 16;
int blocksPerGrid = ceil( (double) (numElements) / threadsPerBlock);
dim3 dimBlock( threadsPerBlock,threadsPerBlock ); 
dim3 dimGrid( blocksPerGrid, blocksPerGrid ); 
cudaEuclid<<<dimGrid, dimBlock>>>( d_A, d_B, d_C, rows, cols );

カーネル 1: (動作していますが、行優先の C++ スタイルではありません)

 __global__ void cudaEuclid( float* A, float* B, float* C, int rows, int cols )
{
        int i, squareeucldist = 0;
        int r = blockDim.x * blockIdx.x + threadIdx.x; // rows
        int c = blockDim.y * blockIdx.y + threadIdx.y; // cols 


        if( r < rows  ){
            for ( i = 0; i < cols; i++ )
                            //column-major order
                squareeucldist  += ( A[r + rows*i] - B[r + rows*i] ) * ( A[r + rows*i] - B[r + rows*i] );
            C[r] = squareeucldist;
            squareeucldist = 0;
        }
}   

カーネル 2: (行優先順、C++ スタイル)

__global__ void cudaEuclid( float* A, float* B, float* C, int rows, int cols )
    {
        int i, squareeucldist = 0;
        int c = blockDim.x * blockIdx.x + threadIdx.x; // cols
        int r = blockDim.y * blockIdx.y + threadIdx.y; // rows


        if( r < rows  ){
            for ( i = 0; i < cols; i++ )
                            //row-major order
                squareeucldist  += ( A[i + cols*r] - B[i + cols*r] ) * ( A[i + cols*r] - B[i + cols*r] );
            C[r] = squareeucldist;
            squareeucldist = 0;
    }
4

2 に答える 2

1

この観察結果は、mexfunction を介してカーネルを呼び出すという事実と関係がありますか?これは、matlab を意味し、結果として列優先のアクセスを意味しますか?

はい。

それを拡張すると、単純な 1D バッファーを使用して C/C++ で列優先の規則を使用できない理由がないことを実証したことを意味します (CUDA の使用はあなたの場合には関係ありません)。

MATLAB 配列は、たまたまデータ バッファーを列優先の順序で保持する特別なクラスと考えてください。実際には内部で呼び出さmxArrayれており、MATLAB を使用するだけで詳細を確認できますformat debug

>> format debug
>> x = [1 2 3; 4 5 6]
x =

Structure address = a91d8a0 
m = 2
n = 3
pr = 7406f620 
pi = 0
     1     2     3
     4     5     6

のアドレスに単一のバッファがあり、pr行と列mxArrayがあることがわかります。MATLAB であるため、2 番目の値については C での慣習どおりではありません。C では、この 2D 配列を として定義すると、値は として配置されます。m=2n=3x(2)42int A[2][3] = { {1, 2, 3}, {4, 5, 6} };1 2 3 4 5 6

ただし、行と列から線形インデックスを計算してアクセスする単純な 1D バッファーがある場合は、規則を変更することを妨げるものは何もありません。C の例では、バッファ (例float* A) を操作しているだけなので、インデックスを作成する方法 ( A[r + rows*c]vs. A[c + cols*r]) はあなた次第です。

簡単に言うと、MATLAB で転置して行優先のカーネルを使用するか、MATLAB 入力をそのままにして列優先のカーネルを使用します。

于 2013-10-09T22:03:40.130 に答える
1

あなたが言及したように、Matlab は列優先の順序付けを使用するため、特定の行列、たとえば はA、それに応じて CPU メモリに格納されます。

プログラムのある時点で、Aホスト メモリからデバイス メモリに移動する必要がありますcudaMemcpy。したがって、A列優先の順序でデバイス メモリに格納されるため、それを考慮して読み取る必要があります。

明らかに、行列を転置することにより、Matlab で行優先の順序付けストレージを架空に実現できます。これには、結合されたメモリアクセスを実現するためのいくつかの利点があります。

于 2013-10-10T09:24:59.490 に答える