Cuda C语言中的统一内存和流

Cuda C语言中的统一内存和流,cuda,nvidia,Cuda,Nvidia,我正在尝试使用具有CUDA 6和C统一内存的流。我以前的流实现是这样的: for(x=0; x<DSIZE; x+=N*2){ gpuErrchk(cudaMemcpyAsync(array_d0, array_h+x, N*sizeof(char), cudaMemcpyHostToDevice, stream0)); gpuErrchk(cudaMemcpyAsync(array_d1, array_h+x+N, N*sizeof(char), cudaMemcpyHostToD

我正在尝试使用具有CUDA 6和C统一内存的流。我以前的流实现是这样的:

for(x=0; x<DSIZE; x+=N*2){

 gpuErrchk(cudaMemcpyAsync(array_d0, array_h+x, N*sizeof(char), cudaMemcpyHostToDevice, stream0));
 gpuErrchk(cudaMemcpyAsync(array_d1, array_h+x+N, N*sizeof(char), cudaMemcpyHostToDevice, stream1));


gpuErrchk(cudaMemcpyAsync(data_d0, data_h, wrap->size*sizeof(int), cudaMemcpyHostToDevice, stream0));
gpuErrchk(cudaMemcpyAsync(data_d1, data_h, wrap->size*sizeof(int), cudaMemcpyHostToDevice, stream1));

searchGPUModified<<<N/128,128,0,stream0>>>(data_d0, array_d0, out_d0 );
searchGPUModified<<<N/128,128,0,stream1>>>(data_d1, array_d1, out_d1);

gpuErrchk(cudaMemcpyAsync(out_h+x, out_d0 , N * sizeof(int), cudaMemcpyDeviceToHost, stream0));
gpuErrchk(cudaMemcpyAsync(out_h+x+N, out_d1 ,N *  sizeof(int), cudaMemcpyDeviceToHost, stream1));

} 
for(x=0;xsize*sizeof(int),cudaMemcpyHostToDevice,stream0);
gpuerchk(cudaMemcpyAsync(data_d1,data_h,wrap->size*sizeof(int),cudamemcpyhostodevice,stream1));
searchGPUModified(数据d0、数组d0、输出d0);
searchGPUModified(数据、数组、输出);
gpuErrchk(cudaMemcpyAsync(out_h+x,out_d0,N*sizeof(int),cudaMemcpyDeviceToHost,stream0));
gpuErrchk(cudaMemcpyAsync(out_h+x+N,out_d1,N*sizeof(int),cudaMemcpyDeviceToHost,stream1));
} 
但是我找不到一个使用相同技术的流和统一内存的例子,在这里数据被发送到GPU。因此,我想知道是否有办法做到这一点?

您应该阅读编程指南(最好是所有附录J)

对于统一内存,使用
cudamalocmanaged
分配的内存默认连接到所有流(“全局”),我们必须对此进行修改,以便有效利用流,例如用于计算/复制重叠。我们可以使用第J.2.2.3节所述的
cudastreamattachmeasync
功能实现这一点。通过以这种方式将每个内存“块”与流关联,UM子系统可以就何时传输每个数据项做出智能决策

以下示例演示了这一点:

#include <stdio.h>
#include <time.h>
#define DSIZE 1048576
#define DWAIT 100000ULL
#define nTPB 256

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

typedef int mytype;

__global__ void mykernel(mytype *data){

  int idx = threadIdx.x+blockDim.x*blockIdx.x;
  if (idx < DSIZE) data[idx] = 1;
  unsigned long long int tstart = clock64();
  while (clock64() < tstart + DWAIT);
}

int main(){

  mytype *data1, *data2, *data3;
  cudaStream_t stream1, stream2, stream3;
  cudaMallocManaged(&data1, DSIZE*sizeof(mytype));
  cudaMallocManaged(&data2, DSIZE*sizeof(mytype));
  cudaMallocManaged(&data3, DSIZE*sizeof(mytype));
  cudaCheckErrors("cudaMallocManaged fail");
  cudaStreamCreate(&stream1);
  cudaStreamCreate(&stream2);
  cudaStreamCreate(&stream3);
  cudaCheckErrors("cudaStreamCreate fail");
  cudaStreamAttachMemAsync(stream1, data1);
  cudaStreamAttachMemAsync(stream2, data2);
  cudaStreamAttachMemAsync(stream3, data3);
  cudaDeviceSynchronize();
  cudaCheckErrors("cudaStreamAttach fail");
  memset(data1, 0, DSIZE*sizeof(mytype));
  memset(data2, 0, DSIZE*sizeof(mytype));
  memset(data3, 0, DSIZE*sizeof(mytype));
  mykernel<<<(DSIZE+nTPB-1)/nTPB, nTPB, 0, stream1>>>(data1);
  mykernel<<<(DSIZE+nTPB-1)/nTPB, nTPB, 0, stream2>>>(data2);
  mykernel<<<(DSIZE+nTPB-1)/nTPB, nTPB, 0, stream3>>>(data3);
  cudaDeviceSynchronize();
  cudaCheckErrors("kernel fail");
  for (int i = 0; i < DSIZE; i++){
    if (data1[i] != 1) {printf("data1 mismatch at %d, should be: %d, was: %d\n", i, 1, data1[i]); return 1;}
    if (data2[i] != 1) {printf("data2 mismatch at %d, should be: %d, was: %d\n", i, 1, data2[i]); return 1;}
    if (data3[i] != 1) {printf("data3 mismatch at %d, should be: %d, was: %d\n", i, 1, data3[i]); return 1;}
    }
  printf("Success!\n");
  return 0;
}
#包括
#包括
#定义DSIZE 1048576
#定义DWAIT 100000ULL
#定义nTPB 256
#定义cudaCheckErrors(msg)\
做{\
cudaError\u t\u err=cudaGetLastError()\
如果(_err!=cudaSuccess){\
fprintf(标准,“致命错误:%s(%s位于%s:%d)\n”\
msg,cudaGetErrorString(_err)\
__文件(行)\
fprintf(stderr,“***失败-中止\n”)\
出口(1)\
} \
}而(0)
typedef int-mytype;
__全局无效mykernel(mytype*数据){
int idx=threadIdx.x+blockDim.x*blockIdx.x;
如果(idx
上面的程序使用
clock64()
创建了一个人工长时间运行的内核,以便给我们模拟计算/复制重叠的机会(模拟计算密集型内核)。我们正在启动这个内核的3个实例,每个实例都在一个单独的“块”数据上运行

当我们分析上述程序时,可以看到以下内容:

首先,请注意,第三次内核启动以黄色突出显示,它在第二次内核启动以紫色突出显示后立即开始。启动第三个内核的实际
cudaLaunch
运行时API事件在运行时API行中由鼠标指针指示,也以黄色突出显示(前面是前两个内核的cudaLaunch事件)。由于此启动发生在第一个内核的执行期间,并且从该点到第三个内核的启动之间没有中间的“空白”,因此我们可以观察到第三个内核启动的数据传输(即,
data3
)发生在内核1和2执行期间。因此,我们有有效的复制和计算重叠。(我们可以对内核2进行类似的观察)


虽然我没有在这里展示,但是如果我们省略
cudastreamattachmeasync
行,程序仍然可以正确编译和运行,但是如果我们分析它,我们会发现cudaLaunch事件和内核之间存在不同的关系。整个配置文件看起来很相似,内核背靠背执行,但是整个cudaLaunch进程现在在第一个内核开始执行之前开始和结束,并且在内核执行期间没有cudaLaunch事件。这表明(因为所有cudaMallocManaged内存都是全局的),所有数据传输都是在第一次内核启动之前进行的。程序无法将“全局”分配与任何特定内核相关联,因此必须在第一次内核启动之前传输所有此类分配的内存(即使该内核仅使用
data1
)。

映像无法加载。罗伯特能重新上传照片吗?提前感谢。图像仍在,正在加载。我认为问题可能出在你这边,你的互联网服务或机器。