cudaMemcpyToSymbol vs cudaMemcpy

时间:2013-03-13 16:44:47

标签: cuda

我正在试图找出为什么 cudaMemcpyToSymbol 不适合我。 (但 cudaMemcpy 确实如此。)

// symbols:
__constant__ float flt[480];   // 1920 bytes
__constant__ int   ints[160];  // 640 bytes

// func code follows:
float* pFlts;
cudaMalloc((void**)&pFlts, 1920+640);  // chunk of gpu mem  (floats & ints)

// This does NOT work properly:
cudaMemcpyToSymbol(flt,pFlts,1920,0,cudaMemcpyDeviceToDevice);  // first copy
cudaMemcpyToSymbol(ints,pFlts,640,1920,cudaMemcpyDeviceToDevice);  // second copy

第二个副本正在废弃第一个副本(flt)的内容,第二个副本不会发生。 (如果我删除了第二个副本,则第一个副本可以正常工作。)

结果:

GpuDumpFloatMemory<<<1,1>>>(0x500500000, 13, 320)  TotThrds=1   ** Source of 1st copy
  0x500500500: float[320]= 1.000
  0x500500504: float[321]= 0.866
  0x500500508: float[322]= 0.500
  0x50050050c: float[323]= -0.000
  0x500500510: float[324]= -0.500
  0x500500514: float[325]= -0.866
  0x500500518: float[326]= -1.000
  0x50050051c: float[327]= -0.866
  0x500500520: float[328]= -0.500
  0x500500524: float[329]= 0.000
  0x500500528: float[330]= 0.500
  0x50050052c: float[331]= 0.866
  0x500500530: float[332]= 1.000
  GpuDumpFloatMemory<<<1,1>>>(0x500100a98, 13, 320)  TotThrds=1     ** Dest of 1st copy
  0x500100f98: float[320]= 0.000
  0x500100f9c: float[321]= 0.500
  0x500100fa0: float[322]= 0.866
  0x500100fa4: float[323]= 1.000
  0x500100fa8: float[324]= 0.866
  0x500100fac: float[325]= 0.500
  0x500100fb0: float[326]= -0.000
  0x500100fb4: float[327]= -0.500
  0x500100fb8: float[328]= -0.866
  0x500100fbc: float[329]= -1.000
  0x500100fc0: float[330]= -0.866
  0x500100fc4: float[331]= -0.500
  0x500100fc8: float[332]= 0.000
  GpuDumpIntMemory<<<1,1>>>(0x500500780, 13, 0)  TotThrds=1      ** Source of 2nd copy
  0x500500780: int[0]= 1
  0x500500784: int[1]= 1
  0x500500788: int[2]= 1
  0x50050078c: int[3]= 1
  0x500500790: int[4]= 1
  0x500500794: int[5]= 1
  0x500500798: int[6]= 1
  0x50050079c: int[7]= 1
  0x5005007a0: int[8]= 1
  0x5005007a4: int[9]= 1
  0x5005007a8: int[10]= 1
  0x5005007ac: int[11]= 1
  0x5005007b0: int[12]= 0
  GpuDumpIntMemory<<<1,1>>>(0x500100818, 13, 0)  TotThrds=1      ** Dest of 2nd copy
  0x500100818: int[0]= 0
  0x50010081c: int[1]= 0
  0x500100820: int[2]= 0
  0x500100824: int[3]= 0
  0x500100828: int[4]= 0
  0x50010082c: int[5]= 0
  0x500100830: int[6]= 0
  0x500100834: int[7]= 0
  0x500100838: int[8]= 0
  0x50010083c: int[9]= 0
  0x500100840: int[10]= 0
  0x500100844: int[11]= 0
  0x500100848: int[12]= 0

以下工作正常:

cudaMemcpyToSymbol(flt,pFlts,1920,0,cudaMemcpyDeviceToDevice);  // first copy
int* pTemp;
cudaGetSymbolAddress((void**) &pTemp, ints);
cudaMemcpy(ints,pFlts+480,640,cudaMemcpyDeviceToDevice);  // second copy

结果:

  GpuDumpFloatMemory<<<1,1>>>(0x500500000, 13, 320)  TotThrds=1   ** Source of first copy
  0x500500500: float[320]= 1.000
  0x500500504: float[321]= 0.866
  0x500500508: float[322]= 0.500
  0x50050050c: float[323]= -0.000
  0x500500510: float[324]= -0.500
  0x500500514: float[325]= -0.866
  0x500500518: float[326]= -1.000
  0x50050051c: float[327]= -0.866
  0x500500520: float[328]= -0.500
  0x500500524: float[329]= 0.000
  0x500500528: float[330]= 0.500
  0x50050052c: float[331]= 0.866
  0x500500530: float[332]= 1.000
  GpuDumpFloatMemory<<<1,1>>>(0x500100a98, 13, 320)  TotThrds=1    ** Dest of first copy
  0x500100f98: float[320]= 1.000
  0x500100f9c: float[321]= 0.866
  0x500100fa0: float[322]= 0.500
  0x500100fa4: float[323]= -0.000
  0x500100fa8: float[324]= -0.500
  0x500100fac: float[325]= -0.866
  0x500100fb0: float[326]= -1.000
  0x500100fb4: float[327]= -0.866
  0x500100fb8: float[328]= -0.500
  0x500100fbc: float[329]= 0.000
  0x500100fc0: float[330]= 0.500
  0x500100fc4: float[331]= 0.866
  0x500100fc8: float[332]= 1.000
  GpuDumpIntMemory<<<1,1>>>(0x500500780, 13, 0)  TotThrds=1    ** Source of 2nd copy
  0x500500780: int[0]= 1
  0x500500784: int[1]= 1
  0x500500788: int[2]= 1
  0x50050078c: int[3]= 1
  0x500500790: int[4]= 1
  0x500500794: int[5]= 1
  0x500500798: int[6]= 1
  0x50050079c: int[7]= 1
  0x5005007a0: int[8]= 1
  0x5005007a4: int[9]= 1
  0x5005007a8: int[10]= 1
  0x5005007ac: int[11]= 1
  0x5005007b0: int[12]= 0
  GpuDumpIntMemory<<<1,1>>>(0x500100818, 13, 0)  TotThrds=1    ** Destination of 2nd copy
  0x500100818: int[0]= 1
  0x50010081c: int[1]= 1
  0x500100820: int[2]= 1
  0x500100824: int[3]= 1
  0x500100828: int[4]= 1
  0x50010082c: int[5]= 1
  0x500100830: int[6]= 1
  0x500100834: int[7]= 1
  0x500100838: int[8]= 1
  0x50010083c: int[9]= 1
  0x500100840: int[10]= 1
  0x500100844: int[11]= 1
  0x500100848: int[12]= 0

当我看到坏情况时,似乎符号表中发生了某些事情。如同,第一个复制目的地的数据非常熟悉。不喜欢它已被覆盖,只是感动。就像指针错了。

1 个答案:

答案 0 :(得分:3)

第二份副本对我来说很糟糕。您已定义此数组:

__constant__ int   ints[160];  // 640 bytes
正确指出的

是640字节长。

你的第二份副本是这样的:

cudaMemcpyToSymbol(ints,pFlts,640,1920,cudaMemcpyDeviceToDevice);  // second copy

其中说,“从pFlts数组到ints数组共复制640个字节,ints数组中的存储位置从开始时的1920字节开始阵“。

这不起作用。 ints数组只有640个字节长。你不能选择一个1920字节的位置作为你的目的地。

来自cudaMemcpyToSymbol的文档:

  

offset-以符号开头的偏移量(以字节为单位)

在这种情况下,符号为ints

你想要的可能是:

cudaMemcpyToSymbol(ints,pFlts+480,640,0,cudaMemcpyDeviceToDevice);  // second copy

修改 在回答关于错误检查的评论中的问题时,我精心设计了这个简单的测试程序:

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

__constant__ int ints[160];

int main(){

  int *d_ints;
  cudaError_t mystatus;

  cudaMalloc((void **)&d_ints, sizeof(int)*160);
  cudaCheckErrors("cudamalloc fail");
  mystatus = cudaMemcpyToSymbol(ints, d_ints, 160*sizeof(int), 1920, cudaMemcpyDeviceToDevice);
  if (mystatus != cudaSuccess) printf("returned value was not cudaSuccess\n");
  cudaCheckErrors("cudamemcpytosymbol fail");

  printf("OK!\n");
  return 0;
}

当我编译并运行它时,我得到以下输出:

returned value was not cudaSuccess
Fatal error: cudamemcpytosymbol fail (invalid argument at t94.cu:26)
*** FAILED - ABORTING

这表示两者来自cudaMemcpyToSymbol函数调用的错误返回值和 cudaGetLastError()方法在这种情况下返回错误。如果在此测试用例中将1920参数更改为零,则错误消失。