长度为500的结构体数组,每个结构体中又包含数组,数据传递

有两个结构体,是这样定义的:
typedef struct vector {
double v[4];
}VECTOR;

typedef struct tle_ascii {
char t[3][71];
}TLE_ASCII;

CPU端定义:
struct tle_ascii *sat_data = NULL;
struct vector *pos = NULL;
struct vector *vel = NULL;
sat_data = (struct tle_ascii *)malloc(sizeof(struct tle_ascii) * 500);
pos = (struct vector *)malloc(sizeof(struct vector) * 500);
vel = (struct vector *)malloc(sizeof(struct vector) * 500);
然后经过度一个数据文件对这三个结构体数组各自赋值,赋值这里没有错,已经检测过每个结构体里面的数组都已经正确赋值。
GPU端定义:
struct tle_ascii *de_sat_data = NULL;
struct vector *de_pos = NULL;
struct vector *de_vel = NULL;

cudaMalloc((void **)&de_sat_data, sizeof(struct tle_ascii) * 500);
cudaMalloc((void **)&de_pos, sizeof(struct vector) * 500);
cudaMalloc((void **)&de_vel, sizeof(struct vector) * 500);

cudaMemcpy(de_sat_data, sat_data,sizeof(struct tle_ascii) * 500, cudaMemcpyHostToDevice);
cudaMemcpy(de_pos, pos,sizeof(struct vector) * 500, cudaMemcpyHostToDevice);
cudaMemcpy(de_vel, vel,sizeof(struct vector) * 500, cudaMemcpyHostToDevice);
Q1:请问对于结构体数组来说,像上面这样传递数据对吗?

然后是经过调用kernel函数,在函数中进行一些计算,计算完成后要把数据传回给主机端:
cudaMemcpy(sat_data, de_sat_data, sizeof(struct tle_ascii) * 500, cudaMemcpyDeviceToHost);
cudaMemcpy(pos, de_pos, sizeof(struct vector) * 500, cudaMemcpyDeviceToHost);
cudaMemcpy(vel, de_vel, sizeof(struct vector) * 500, cudaMemcpyDeviceToHost);
Q2:如果上面那样传递没错,这里应该也没错吧?
Q3:实际情况是将经过kernel函数计算后的数据传递回主机端后打印出来,那几个结构体的数据都变成了0.000000……
所以综合起来还是如题,如果是结构体数组,而且每个结构体也包含数组,这样的数据传递该怎么样传递?
急盼大神帮忙……⊙︿⊙

快来人啦帮帮忙啦

A1: 这样传递对。但前提是,你是在.cu里面调用的cudaMalloc/Memcpy, 并且是用的nvcc过一遍的,否则如果不是.cu,而是在.c/.cpp里面,可能实际上sizeof(你的结构体)是另外一个大小。(因为可能host compiler自己的填充、对齐等考虑和cuda的编译器考虑的不同)。

A2: 这样传递对。但同样请注意上点。

A3: 以及,请确定您的host memory和device memory等成功分配了。建议检查返回值。

这个代码是在.cu文件中的,这套程序是有两个cuh文件,一个cu文件,编译的时候就编译的cu文件,编译执行都没有报错,只是结果不对,我怀疑是数据传递出的问题,host端的三个结构体数组都成功分配,有容错处理,但是device端的显存分配我想要用printf打印,但是看不了,您也看到了那个我发的另一个帖子就是问printf的使用问题的,我也试过cuda-gdb,但是在编译的时候总是一直在编译,编译不完,我也不知道哪里出了错,麻烦您在帮我看看吧:用nvcc a.cu -o a大概编译1分钟左右,使用 nvcc -g -G a.cu -o a编译为可以用cudagdb调试的代码的时候,编译了很久很久也没有编译完成,这是怎么回事?
好激动终于有人帮我解答问题!

楼主您好,请直接检查cudaMalloc/cudaMemcpy的返回值即可:
cudaError_t result = cudaMalloc/Memcpy(…); //或者您可以使用auto result = …; 如果您的host compiler支持自动类型推导的话。
if (result != cudaSuccess) {…}
它们正常情况应该返回cudaSuccess的。如果不是,则证明出错。

关于您的第二个问题,“为何nvcc一直在编译,始终不完”,这个可能是compiler内部错误了,导致了死循环,或者,贵机器配置太差,导致极度缓慢?
如果您认为自己的机器不错,但始终编译不完。那么前者的可能性较大,您可以像NVIDIA反馈此情况,您可以直接PM驻版的"NVIDIA技术支持"。

感谢您的来访。

千军兄,我按照您的方法试过了,没有报错,说明cudaMalloc是成功的
cudaError_t result1 = cudaMalloc((void **)&de_sat_data, sizeof(struct tle_ascii) * num);
if(result1 != cudaSuccess)
{
printf(“cudaMalloc ERROR!\n”);
exit(-1);
}
编译执行都没有报错

我用的公司的工作站,配置还可以……

请您仔细看上文。所有操作都要检查的哦。

跟据您的描述,
(1)分配
(2)复制过去
(3)计算
(4)复制回来 //结果不对
如果(1)是正确的,那么可能(2)(3)(4)中的某步导致了错误,建议全部检查。

:P您可不可以告诉我怎么检测cudaMemcpy的结果,就是我把数据传递给Device端以后,我怎么查看传过去没有呢?我想用printf在kernel函数里,可是用不了,您可以告诉我怎么检查吗?

我不能确定cudaMemcpy(H TO D)这一步有没有错误,就是不知道传过去了没有,怎么检查呢?:dizzy:

只要您的参数(目标地址,源地址,传输大小)是正确的,同时该函数,如上文说的,返回了cudaSuccess, 则必然成功的。

千军兄,我的代码里用了一个for循环:
for(i = 0; i < 5; i++)
{
int model = 0;
switch (i)
{
case 0 :
model = 0;
mykernel<<<256, 1024>>>(model, de_sat_data, de_pos, de_vel, satdata);
cudaDeviceSynchronize();
cudaError_t result7 = cudaMemcpy(pos, de_pos, sizeof(struct vector) * num, cudaMemcpyDeviceToHost);
if(result7 != cudaSuccess)
{
printf(“cudaMemcpy ERROR!\n”);
exit(-1);
}

cudaError_t result8 = cudaMemcpy(vel, de_vel, sizeof(struct vector) * num, cudaMemcpyDeviceToHost);
if(result8 != cudaSuccess)
{
printf(“cudaMemcpy ERROR!\n”);
exit(-1);
}
break;
case 1 :
model = 1;
mykernel<<<256, 1024>>>(model, de_sat_data, de_pos, de_vel, satdata);
cudaDeviceSynchronize();
cudaError_t result9 = cudaMemcpy(pos, de_pos, sizeof(struct vector) * num, cudaMemcpyDeviceToHost);
if(result9 != cudaSuccess)
{
printf(“cudaMemcpy ERROR!\n”);
exit(-1);
}

cudaError_t result10 = cudaMemcpy(vel, de_vel, sizeof(struct vector) * num, cudaMemcpyDeviceToHost);
if(result10 != cudaSuccess)
{
printf(“cudaMemcpy ERROR!\n”);
exit(-1);
}
break;
case 2 :
model = 2;
还有几个case也是类似处理的。

}

编译的时候报错了:testing.cu:2532: error: jump to case label
testing.cu:2511: error: crosses initialization of ?.udaError_t result8?
testing.cu:2504: error: crosses initialization of ?.udaError_t result7?
testing.cu:2571: error: jump to case label
testing.cu:2549: error: crosses initialization of ?.udaError_t result10?
testing.cu:2542: error: crosses initialization of ?.udaError_t result9?
testing.cu:2511: error: crosses initialization of ?.udaError_t result8?
testing.cu:2504: error: crosses initialization of ?.udaError_t result7?
testing.cu:2610: error: jump to case label
testing.cu:2588: error: crosses initialization of ?.udaError_t result12?
testing.cu:2581: error: crosses initialization of ?.udaError_t result11?
testing.cu:2549: error: crosses initialization of ?.udaError_t result10?
testing.cu:2542: error: crosses initialization of ?.udaError_t result9?
testing.cu:2511: error: crosses initialization of ?.udaError_t result8?
testing.cu:2504: error: crosses initialization of ?.udaError_t result7?
testing.cu:2649: error: jump to case label
testing.cu:2627: error: crosses initialization of ?.udaError_t result14?
testing.cu:2620: error: crosses initialization of ?.udaError_t result13?
testing.cu:2588: error: crosses initialization of ?.udaError_t result12?
testing.cu:2581: error: crosses initialization of ?.udaError_t result11?
testing.cu:2549: error: crosses initialization of ?.udaError_t result10?
testing.cu:2542: error: crosses initialization of ?.udaError_t result9?
testing.cu:2511: error: crosses initialization of ?.udaError_t result8?
testing.cu:2504: error: crosses initialization of ?.udaError_t result7?

这是神马意思?是交叉初始化了吗?

将每个case的分支用{ }限定下里面的变量的作用域,然后重新编译看看。

嗯,好,明天到公司去试一下,谢谢千军兄~:P

千军兄,我试过了,加上{}以后,能编译通过,执行的时候也没有报错,但是结果还是0.000000……

那就奇怪了,根据你的测试反馈,

复制到device过去 (成功)
执行kernel (成功)
复制回来 (成功)

但是发现数据不对。那就只有一个可能的了:你设想的kernel和你实际写出的不一样。
你的手背叛了你的灵魂。

请立刻确定你的身心是一致的!

[

千军兄,我的kernel函数是把CPU端的代码改造成GPU端的,变化的地方就是结构体数组的下标,从本来的i(0~500),变成了tid(blockDim.x * blockIdx.x + threadIdx.x)加了限制条件if (tid < 500),然后做运算,本来的运算是这样的:
if(model == 1)
{
sgp4(tsince, &de_pos, &de_vel, &satdata);
}
改造成GPU端的以后是这样的:if(model == _SGP4)
{
sgp4(tsince, &de_pos[tid], &de_vel[tid], &satdata);
}
变得只是下标而已,我觉得这里应该不会出错的,如果数据都传进来……千军兄,你怎么看呢?

将东西A复制到显卡,在A上捣鼓一番,将A复制回来。

一共就三步。复制是现成的API, 参数对就不会错。只有中间那一步可能有鬼(也就是你的kernel), 您觉得呢?

[

千军兄,我现在知道出错的原因了,如果把编译选项加上-arch=sm_20就会打印吃来正确的结果了,而且耗费的时间很短,比不加这个选项大概提速200多倍,我也不理解这是为什么,难道不用makefile编译,只用nvcc来编译且不加-arch=sm_20的话,会默认成1.x的计算能力吗?是这样吗?

千军兄我还要问你一个问题,就是工作站上有台机器,我装了vs2010, cuda5.0,还有matlab2012以后,如果远程这台机器的话,cuda设备不可用,但是在这台机器本机上操作就没有任何问题,这是为什么?