0

CUDA と GPU を使用して、LCG 乱数ジェネレーターを並行して実行しようとしています。ただし、実際には複数のスレッドを同時に実行するのに問題があります。コードのコピーは次のとおりです。

#include <iostream>
#include <math.h>

__global__ void rng(long *cont)
{

    int a=9, c=3, F, X=1; 
    long M=524288, Y;     
    printf("\nKernel X is %d\n", X[0]);     
    F=X;
    Y=X;
    printf("Kernel F is %d\nKernel Y is %d\n", F, Y);
    Y=(a*Y+c)%M;
    printf("%ld\t", Y);
    while(Y!=F)
    {
        Y=(a*Y+c)%M;
        printf("%ld\t", Y);
    cont[0]++;
    }
}
int main()
{
    long cont[1]={1};
    int X[1];
    long *dev_cont;
    int *dev_X;
    cudaEvent_t beginEvent;
    cudaEvent_t endEvent;
    cudaEventCreate( &beginEvent );
    cudaEventCreate( &endEvent );
    printf("Please give the value of the seed X ");
    scanf("%d", &X[0]);
    printf("Host X is: %d", *X);
    cudaEventRecord( beginEvent, 0);
    cudaMalloc( (void**)&dev_cont, sizeof(long) );
    cudaMalloc( (void**)&dev_X, sizeof(int) );
    cudaMemcpy(dev_cont, cont, 1 * sizeof(long), cudaMemcpyHostToDevice);
    cudaMemcpy(dev_X, X, 1 * sizeof(int), cudaMemcpyHostToDevice);
    rng<<<1,1>>>(dev_cont);
    cudaMemcpy(cont, dev_cont, 1 * sizeof(long), cudaMemcpyDeviceToHost);
    cudaEventRecord( endEvent, 0);
    cudaEventSynchronize (endEvent );
    float timevalue;
    cudaEventElapsedTime (&timevalue, beginEvent, endEvent);
    printf("\n\nYou generated a total of %ld numbers", cont[0]);
    printf("\nCUDA Kernel Time: %.2f ms\n", timevalue);
    cudaFree(dev_cont);
    cudaFree(dev_X);
    cudaEventDestroy( endEvent );
    cudaEventDestroy( beginEvent );
    return 0;
}

現在、1 つのスレッドで 1 つのブロックのみを送信しています。ただし、100 スレッドを送信すると、同じ番号を 100 回生成してから次の番号に進むだけです。理論的には、これは予期されることですが、数値が繰り返されると「乱数」の目的が自動的に無視されます。

私が実装したいアイデアは、複数のスレッドを持つことです。あるスレッドは次の式を使用します: Y=(a*Y+c)%M ただし、Y=1 の初期値を使用し、別のスレッドは同じ式を使用しますが、初期値は Y=1000 などです。ただし、 、最初のスレッドが 1000 個の数値を生成したら、それ以上の計算を停止する必要があります。これを続けると、Y=1000 の値を持つ数値を生成する 2 番目のスレッドに干渉するためです。

誰かが正しい方向を指し示すことができれば、少なくとも内部に異なる関数や命令を含む複数のスレッドを作成して並列に実行する方法で、残りを理解しようとします.

ありがとう!

更新: 7 月 31 日午後 8 時 14 分 (EST)

コードを次のように更新しました。基本的に、256 個の乱数を生成しようとしています。これらの 256 個の数値が格納される配列を作成しました。また、スレッド内の Y の値に対して 10 個の異なるシード値を持つ配列を作成しました。また、デバイスで 10 個のスレッドを要求するようにコードを変更しました。また、生成された数値を配列に保存しています。コードが正常に機能していません。それを修正する方法、または私が望むものを達成する方法についてアドバイスしてください。

ありがとう!

#include <iostream>
#include <math.h>

__global__ void rng(long *cont, int *L, int *N)
{

    int Y=threadIdx.x;
    Y=N[threadIdx.x];
    int a=9, c=3, i;
    long M=256;
    for(i=0;i<256;i++)
    {
        Y=(a*Y+c)%M;
        N[i]=Y;
        cont[0]++;
    }
}
int main()
{
    long cont[1]={1};
    int i;
    int L[10]={1,25,50,75,100,125,150,175,200,225}, N[256];
    long *dev_cont;
    int *dev_L, *dev_N;
    cudaEvent_t beginEvent;
    cudaEvent_t endEvent;
    cudaEventCreate( &beginEvent );
    cudaEventCreate( &endEvent );
    cudaEventRecord( beginEvent, 0);
    cudaMalloc( (void**)&dev_cont, sizeof(long) );
    cudaMalloc( (void**)&dev_L, sizeof(int) );
    cudaMalloc( (void**)&dev_N, sizeof(int) );
    cudaMemcpy(dev_cont, cont, 1 * sizeof(long), cudaMemcpyHostToDevice);
    cudaMemcpy(dev_L, L, 10 * sizeof(int), cudaMemcpyHostToDevice);
    cudaMemcpy(dev_N, N, 256 * sizeof(int), cudaMemcpyHostToDevice);
    rng<<<1,10>>>(dev_cont, dev_L, dev_N);
    cudaMemcpy(cont, dev_cont, 1 * sizeof(long), cudaMemcpyDeviceToHost);
    cudaMemcpy(N, dev_N, 256 * sizeof(int), cudaMemcpyDeviceToHost);
    cudaEventRecord( endEvent, 0);
    cudaEventSynchronize (endEvent );
    float timevalue;
    cudaEventElapsedTime (&timevalue, beginEvent, endEvent);
    printf("\n\nYou generated a total of %ld numbers", cont[0]);
    printf("\nCUDA Kernel Time: %.2f ms\n", timevalue);
    printf("Your numbers are:");
    for(i=0;i<256;i++)
    {
        printf("%d\t", N[i]);
    }
    cudaFree(dev_cont);
    cudaFree(dev_L);
    cudaFree(dev_N);
    cudaEventDestroy( endEvent );
    cudaEventDestroy( beginEvent );
    return 0;
}

@Bardia - ニーズに合わせてコードを変更する方法を教えてください。

更新: 8 月 1 日午後 5 時 39 分 (EST)

@Bardia のカーネル コードへの変更に対応するようにコードを編集しました。ただし、数値の生成にいくつかのエラーが出てきています。まず、作成されている数値の量をカウントするためにカーネルで作成したカウンターが機能していません。最後に、「1」の数字が生成されたことのみを表示します。カーネルが命令を実行するのにかかる時間を測定するために作成したタイマーも、0.00 ミリ秒を表示し続けているため、機能していません。また、数式に設定したパラメーターに基づいて、生成されて配列にコピーされ、画面に表示される数値は、表示される (または閉じる) 意図された数値を反映していません。これらはすべて以前は機能していました。

新しいコードは次のとおりです。

#include <iostream>
#include <math.h>

__global__ void rng(long *cont, int *L, int *N)
{

    int Y=threadIdx.x;
    Y=L[threadIdx.x];
    int a=9, c=3, i;
    long M=256;
    int length=ceil((float)M/10); //256 divided by the number of threads.
    for(i=(threadIdx.x*length);i<length;i++)
    {
        Y=(a*Y+c)%M;
        N[i]=Y;
        cont[0]++;
    }
}
int main()
{
    long cont[1]={1};
    int i;
    int L[10]={1,25,50,75,100,125,150,175,200,225}, N[256];
    long *dev_cont;
    int *dev_L, *dev_N;
    cudaEvent_t beginEvent;
    cudaEvent_t endEvent;
    cudaEventCreate( &beginEvent );
    cudaEventCreate( &endEvent );
    cudaEventRecord( beginEvent, 0);
    cudaMalloc( (void**)&dev_cont, sizeof(long) );
    cudaMalloc( (void**)&dev_L, sizeof(int) );
    cudaMalloc( (void**)&dev_N, sizeof(int) );
    cudaMemcpy(dev_cont, cont, 1 * sizeof(long), cudaMemcpyHostToDevice);
    cudaMemcpy(dev_L, L, 10 * sizeof(int), cudaMemcpyHostToDevice);
    cudaMemcpy(dev_N, N, 256 * sizeof(int), cudaMemcpyHostToDevice);
    rng<<<1,10>>>(dev_cont, dev_L, dev_N);
    cudaMemcpy(cont, dev_cont, 1 * sizeof(long), cudaMemcpyDeviceToHost);
    cudaMemcpy(N, dev_N, 256 * sizeof(int), cudaMemcpyDeviceToHost);
    cudaEventRecord( endEvent, 0);
    cudaEventSynchronize (endEvent );
    float timevalue;
    cudaEventElapsedTime (&timevalue, beginEvent, endEvent);
    printf("\n\nYou generated a total of %ld numbers", cont[0]);
    printf("\nCUDA Kernel Time: %.2f ms\n", timevalue);
    printf("Your numbers are:");
    for(i=0;i<256;i++)
    {
        printf("%d\t", N[i]);
    }
    cudaFree(dev_cont);
    cudaFree(dev_L);
    cudaFree(dev_N);
    cudaEventDestroy( endEvent );
    cudaEventDestroy( beginEvent );
    return 0;
}

これは私が受け取る出力です:

[wigberto@client2 CUDA]$ ./RNG8


You generated a total of 1 numbers
CUDA Kernel Time: 0.00 ms
Your numbers are:614350480      32767   1132936976      11079   2       0       10      0       1293351837      0       -161443660      48      0       0       614350336       32767    1293351836      0       -161444681      48      614350760       32767   1132936976      11079   2       0       10      0       1057178751      0       -161443660      48       155289096       49      614350416       32767   1057178750      0       614350816       32767   614350840       32767   155210544       49      0       0       1132937352       11079   1130370784      11079   1130382061      11079   155289096       49      1130376992      11079   0       1       1610    1       1       1       1130370408      11079    614350896       32767   614350816       32767   1057178751      0       614350840       32767   0       0       -161443150      48      0       0       1132937352      11079    1       11079   0       0       1       0       614351008       32767   614351032       32767   0       0       0       0       0       0       1130369536      1       1132937352       11079   1130370400      11079   614350944       32767   1130369536      11079   1130382061      11079   1130370784      11079   1130365792      11079   6143510880       614351008       32767   -920274837      0       614351032       32767   0       0       -161443150      48      0       0       0       0       1       0       128     0-153802168      48      614350896       32767   1132839104      11079   97      0       88      0       1       0       155249184       49      1130370784      11079   0       0-1      0       1130364928      11079   2464624 0       4198536 0       4198536 0       4197546 0       372297808       0       1130373120      11079   -161427611      48      111079   0       0       1       0       -153802272      48      155249184       49      372297840       0       -1      0       -161404446      48      0       0       0       0372298000       0       372297896       0       372297984       0       0       0       0       0       1130369536      11079   84      0       1130471067      11079   6303744 0614351656       32767   0       0       -1      0       4198536 0       4198536 0       4197546 0       1130397880      11079   0       0       0       0       0       0       00       0       0       -161404446      48      0       0       4198536 0       4198536 0       6303744 0       614351280       32767   6303744 0       614351656       32767   614351640        32767   1       0       4197371 0       0       0       0       0       [wigberto@client2 CUDA]$

@Bardia - ここで何をするのが最善かアドバイスしてください。

ありがとう!

4

3 に答える 3

2

threadIdx変数によってブロック内のスレッドをアドレス指定できます。つまり、あなたの場合、おそらく設定する必要があります

Y = threadIdx.xそして使用するY=(a*Y+c)%M

しかし、一般的に、CUDA に優れた RNG を実装することは非常に困難です。したがって、練習のために独自のジェネレーターを実装するかどうかはわかりません..

それ以外の場合は、多数の疑似乱数および準乱数生成器を提供する CURAND ライブラリが利用可能です。XORWOW、MersenneTwister、Sobolなど。

于 2012-07-28T02:20:21.603 に答える
0

この回答は、質問の編集された部分に関連しています。

それが再帰アルゴリズムであることに気づきませんでした。残念ながら、再帰アルゴリズムを並列化する方法がわかりません。

これらの 256 番号を生成するための私の唯一のアイデアは、それらを個別に生成することです。つまり、最初のスレッドで 26 個、2 番目のスレッドで 26 個、というように生成します。このコードはこれを行います (これはカーネル部分のみです):

#include <iostream>
#include <math.h>

__global__ void rng(long *cont, int *L, int *N)
{

    int Y=threadIdx.x;
    Y=L[threadIdx.x];
    int a=9, c=3, i;
    long M=256;
    int length=ceil((float)M/10); //256 divided by the number of threads.
    for(i=(threadIdx.x*length);i<length;i++)
    {
        Y=(a*Y+c)%M;
        N[i]=Y;
        cont[0]++;
    }
}
于 2012-08-01T19:28:36.707 に答える
0

すべてのスレッドで同じ作業を行う必要があるため、すべてのスレッドで同じ作業を行う必要があります。スレッドをアドレス指定するときは、常にスレッドを互いに区別する必要があります。

たとえば、スレッド #1 はこのジョブを実行してここで作業を保存し、スレッド #2 はそのジョブを実行してそこで作業を保存し、ホストに移動してそのデータを使用するとします。

各ブロックに 2 次元のスレッドがある 2 次元のブロック グリッドの場合、次のコードをアドレス指定に使用します。

int X = blockIdx.x*blockDim.x+threadIdx.x;
int Y = blockIdx.y*blockDim.y+threadIdx.y;

上記のコードのXandYは、スレッドのグローバル アドレスです (1 次元のグリッドとスレッドで十分だと思います)。

printfまた、カーネルでは関数を使用できないことに注意してください。GPU は割り込みを行うことができません。これには、CUDA SDK のサンプルの 1 つである関数を使用できますがcuPrintf、正しく使用するにはその説明をお読みください。

于 2012-07-29T20:34:52.997 に答える