3

私がこのクラスを持っているとしましょう:

class Particle
{
    double *_w;
};

そして、 nParticlesオブジェクトをParticleカーネルに送信したいと思います。これらのオブジェクトにスペースを割り当てるのは簡単です:

Particle *dev_p;
cudaStatus = cudaMalloc((void**)&dev_P, nParticles * sizeof(Particle));
if (cudaStatus != cudaSuccess) {
    fprintf(stderr, "cudaMalloc failed!");
    goto Error;
}

また、 nParticlesが100であると仮定し ます。ここで、オブジェクトのそれぞれに300のdoubleを割り当てる必要があります。これどうやってするの?私はこのコードを試しました:_wParticle

for( int i = 0; i < nParticles; i++){
    cudaStatus = cudaMalloc((void**)&(dev_P[i]._w), 300 * sizeof(double));
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMalloc failed!");
        goto Error;
    }
}

しかし、dev_p [i] ._ w [j]にアクセスすると、Nsightを使用したデバッグが停止します。

4

2 に答える 2

11

おそらく、完全な簡単な例を含める必要があります。(上記のコードをコンパイルして単独で実行すると、Linuxでは2番目のcudaMalloc操作でセグメンテーション違反が発生します)。私が見る1つの問題は、最初のステップでデバイスメモリにパーティクルオブジェクトを割り当てたため、_wポインタを割り当てるときに、すでにデバイスメモリにあるcudaMallocにポインタを渡していることです。ホストベースのポインタをcudaMallocに渡すことになっています。このポインタは、デバイス(グローバル)メモリの割り当てられた領域に割り当てられます。

私がyoruの例で見たものに一致すると思う1つの可能な解決策は次のとおりです。

#include <stdio.h>

#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)

class Particle
{
    public:
    double *_w;
};

__global__ void test(Particle *p){

  int idx=threadIdx.x + blockDim.x*blockIdx.x;

  if (idx == 2){
    printf("dev_p[2]._w[2] = %f\n", p[idx]._w[2]);
    }
}


int main() {
  int nParticles=100;
  Particle *dev_p;
  double *w[nParticles];
  cudaMalloc((void**)&dev_p, nParticles * sizeof(Particle));
  cudaCheckErrors("cudaMalloc1 fail");

  for( int i = 0; i < nParticles; i++){
    cudaMalloc((void**)&(w[i]), 300 * sizeof(double));
    cudaCheckErrors("cudaMalloc2 fail");
    cudaMemcpy(&(dev_p[i]._w), &(w[i]), sizeof(double *), cudaMemcpyHostToDevice);
    cudaCheckErrors("cudaMemcpy1 fail");
    }
  double testval = 32.7;
  cudaMemcpy(w[2]+2, &testval, sizeof(double), cudaMemcpyHostToDevice);
  cudaCheckErrors("cudaMemcpy2 fail");
  test<<<1, 32>>>(dev_p);
  cudaDeviceSynchronize();
  cudaCheckErrors("kernel fail");
  printf("Done!\n");

}

ここでは、cudaMallocの目的で使用するために、ホスト上に別個のポインターセットを作成し、それらの割り当てられたポインターをデバイスにコピーして、デバイスポインターとして使用します(これはUVAで有効です)。

別のアプローチは、デバイス側に_wポインタを割り当てることです。これはあなたの目的にも役立つかもしれません。

上記のすべては、cc2.0以上を想定しています。

ここで説明するのと同様の方法を使用すると、ループで実行されるデバイス側の割り当てを単一の割り当てにまとめることができる場合があります。

cudaMalloc(&(w[0]), nParticles*300*sizeof(double));
cudaCheckErrors("cudaMalloc2 fail");
cudaMemcpy(&(dev_p[0]._w), &(w[0]), sizeof(double *), cudaMemcpyHostToDevice);
cudaCheckErrors("cudaMemcpy1 fail");
for( int i = 1; i < nParticles; i++){
  w[i] = w[i-1] + 300;
  cudaMemcpy(&(dev_p[i]._w), &(w[i]), sizeof(double *), cudaMemcpyHostToDevice);
  cudaCheckErrors("cudaMemcpy1 fail");
  }

操作はcudaMemcpy引き続き個別に実行する必要があります。

于 2013-01-11T20:44:44.160 に答える
1

それを行うには2つの方法があります。最初の1つ-パーティクルオブジェクトのホスト配列を埋めるホストにメモリを割り当てます。完了したら、を介してホストアレイをデバイスにコピーしますcudaMemcpy

2番目の方法-Fermi以降では、カーネルを呼び出して、カーネルから配列をmalloc埋めることができます。dev_P

于 2013-01-11T20:19:24.407 に答える