0

私は次のコードを持っています

#include <iostream>
#include <cuda.h>
#include <cuda_runtime.h>
#include <ctime>
#include <vector>
#include <numeric>

float random_float(void)
{
    return static_cast<float>(rand()) / RAND_MAX;
}

std::vector<float> add(float alpha, std::vector<float>& v1, std::vector<float>& v2 )

{  /*Do quick size check on vectors before proceeding*/

  std::vector<float> result(v1.size());
  for (unsigned int i = 0; i < result.size(); ++i)
  {
    result[i]=alpha*v1[i]+v2[i];
  }

  return result;

}

__global__ void Addloop( int N, float alpha, float* x, float* y ) {
   int i;
   int i0 = blockIdx.x*blockDim.x + threadIdx.x;

   for( i = i0; i < N;  i += blockDim.x*gridDim.x ) 
      y[i] = alpha*x[i] + y[i];

   /*
   if ( i0 < N )
      y[i0] = alpha*x[i0] + y[i0];
    */
}

int main( int argc, char** argv ) {

    float alpha = 0.3;
    // create array of 256k elements
    int num_elements = 10;//1<<18;
    // generate random input on the host
    std::vector<float> h1_input(num_elements);
    std::vector<float> h2_input(num_elements);
    for(int i = 0; i < num_elements; ++i)
    {
        h1_input[i] = random_float();
        h2_input[i] = random_float();
    }
    for (std::vector<float>::iterator it = h1_input.begin() ; it != h1_input.end(); ++it)
        std::cout << ' ' << *it;
    std::cout << '\n';
    for (std::vector<float>::iterator it = h2_input.begin() ; it != h2_input.end(); ++it)
        std::cout << ' ' << *it;
    std::cout << '\n';

    std::vector<float> host_result;//(std::vector<float> h1_input, std::vector<float> h2_input );
    host_result = add( alpha, h1_input, h2_input );
    for (std::vector<float>::iterator it = host_result.begin() ; it != host_result.end(); ++it)
        std::cout << ' ' << *it;
    std::cout << '\n';

    // move input to device memory
    float *d1_input = 0;
    cudaMalloc((void**)&d1_input, sizeof(float) * num_elements);
    cudaMemcpy(d1_input, &h1_input[0], sizeof(float) * num_elements, cudaMemcpyHostToDevice);

    float *d2_input = 0;
    cudaMalloc((void**)&d2_input, sizeof(float) * num_elements);
    cudaMemcpy(d2_input, &h2_input[0], sizeof(float) * num_elements, cudaMemcpyHostToDevice);


    Addloop<<<1,3>>>( num_elements, alpha, d1_input, d2_input );

    // copy the result back to the host
    std::vector<float> device_result(num_elements);
    cudaMemcpy(&device_result[0], d2_input, sizeof(float) * num_elements, cudaMemcpyDeviceToHost);
    for (std::vector<float>::iterator it = device_result.begin() ; it != device_result.end(); ++it)
        std::cout << ' ' << *it;
    std::cout << '\n';


    cudaFree(d1_input);
    cudaFree(d2_input);
    h1_input.clear();
    h2_input.clear();
    device_result.clear();

    std::cout << "DONE! \n";
    getchar();

    return 0;
}

GPUメモリアクセスを理解しようとしています。簡単にするために、カーネルはAddloop<<<1,3>>>として起動されます。インスタンスとして gpu で動作する for ループを想像して、このコードがどのように機能するかを理解しようとしています。より具体的には、次の例を想像しますが、役に立ちません。

インスタンス 1:

for( i = 0; i < N; i += 3*1 ) // ( i += 0*1 --> i += 3*1 after Eric's comment) 
   y[i] = alpha*x[i] + y[i];

インスタンス 2:

for( i = 1; i < N; i += 3*1 ) 
   y[i] = alpha*x[i] + y[i];

インスタンス 3:

for( i = 3; i < N; i += 3*1 )
   y[i] = alpha*x[i] + y[i];

すべてのループの内部を見ると、2 つのベクトルを加算するロジックでは意味がありません。誰かが助けることができますか?

このインスタンスのロジックを採用している理由は、コメント内のカーネル内のコードの場合にうまく機能するためです。

これらの考えが正しければ、グリッド内に複数のブロックがある場合、インスタンスは何になるでしょうか? 言い換えれば、いくつかの例で は、i値と更新レート ( ) はどうなるでしょうか?+=updaterate

PS:カーネル コードはhereから借用しました。

アップデート:

エリックの答えの後N = 15、要素の数 ei の実行は次のようになると思います(間違っている場合は修正してください):

上記のインスタンス 1i = 0 , 3, 6, 9, 12では、対応するy[i]値が計算されます。上記のインスタンス 2i = 1 , 4, 7, 10, 13については、対応する残りのy[i]値を計算します。上記のインスタンス 3i = 2 , 5, 8, 11, 14では、残りのy[i]値が計算されます。

4

1 に答える 1

1

あなたblockDim.xは 3 でgridDim.x、設定によると 1<<<1,3>>>です。したがって、各スレッド(インスタンスと呼びます)では、次のようにする必要がありますi+=3*1

アップデート

ループを使用すると、for3 つのスレッドのみを使用して 15 要素を計算できます。一般に、限られた数のスレッドを使用して「無限」の作業を行うことができます。また、スレッドあたりの作業量が増えると、起動のオーバーヘッドが削減され、命令ストールが隠されるため、パフォーマンスが向上します。

別の利点は、固定数のスレッド/ブロックを使用してさまざまなサイズの作業を実行できるため、調整が少なくて済むことです。

于 2013-10-13T03:34:19.993 に答える