【发布时间】:2012-03-27 06:10:48
【问题描述】:
注意 4
所以代码终于修复了!原来最后一个问题是我正在将分配给每个数组的空间大小添加到 ptr,但 c 已经考虑了变量的大小,所以我基本上添加了 4 倍的空间(以字节为单位)应该有,因此只有 5 元素数组中的前两个元素会显示。 AoSoA 现在可以正常工作了。小心你的内存。如果你尝试类似的管理,我会遇到很多看似愚蠢的错误,因为我的初始代码很草率。
当心:
+ 不正确的偏移量
+ 不必要的 malloc
+ 超出范围的引用
这是工作示例代码,结果如下!
#include <stdio.h>
#define REGIONS 20
#define YEARS 5
__inline __host__ void gpuAssert(cudaError_t code, char *file, int line,
bool abort=true)
{
if (code != cudaSuccess)
{
fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code),
file, line);
if (abort) exit(code);
}
}
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
struct AnimalPopulationForYear_s
{
bool isYearEven;
int * rabbits;
int * hyenas;
};
AnimalPopulationForYear_s * dev_pop;
__global__ void RunSim(AnimalPopulationForYear_s dev_pop[],
int year)
{
int idx = blockIdx.x*blockDim.x+threadIdx.x;
int rabbits, hyenas;
int arrEl = year-1;
rabbits = (idx+1) * year * year;
hyenas = rabbits / 10;
if ( rabbits > 100000 ) rabbits = 100000;
if ( hyenas < 2 ) hyenas = 2;
if ( idx < REGIONS ) dev_pop[arrEl].rabbits[idx] = rabbits;
if ( idx < REGIONS ) dev_pop[arrEl].hyenas[idx] = hyenas;
if (threadIdx.x == 0 && blockIdx.x == 0)
dev_pop[arrEl].isYearEven = (year & 0x01 == 0x0);
}
int main()
{
//Various reused sizes...
const size_t fullArrSz = size_t(YEARS) * size_t(REGIONS) * sizeof(int);
const size_t structArrSz = size_t(YEARS) * sizeof(AnimalPopulationForYear_s);
//Vars to hold struct and merged subarray memory inside it.
AnimalPopulationForYear_s * h_pop;
int * dev_hyenas, * dev_rabbits, * h_hyenas, * h_rabbits, arrEl;
//Alloc. memory.
h_pop = (AnimalPopulationForYear_s *) malloc(structArrSz);
h_rabbits = (int *) malloc(fullArrSz);
h_hyenas = (int *) malloc(fullArrSz);
gpuErrchk(cudaMalloc((void **) &dev_pop,structArrSz));
gpuErrchk(cudaMalloc((void **) &dev_rabbits,fullArrSz));
gpuErrchk(cudaMalloc((void **) &dev_hyenas,fullArrSz));
//Offset ptrs.
for (int i = 0; i < YEARS; i++)
{
h_pop[i].rabbits = dev_rabbits+i*REGIONS;
h_pop[i].hyenas = dev_hyenas+i*REGIONS;
}
//Copy host struct with dev. pointers to device.
gpuErrchk
(cudaMemcpy(dev_pop,h_pop, structArrSz, cudaMemcpyHostToDevice));
//Call kernel
for(int i=1; i < YEARS+1; i++) RunSim<<<REGIONS/128+1,128>>>(dev_pop,i);
//Make sure nothing went wrong.
gpuErrchk(cudaPeekAtLastError());
gpuErrchk(cudaDeviceSynchronize());
gpuErrchk(cudaMemcpy(h_pop,dev_pop,structArrSz, cudaMemcpyDeviceToHost));
gpuErrchk
(cudaMemcpy(h_rabbits, dev_rabbits,fullArrSz, cudaMemcpyDeviceToHost));
gpuErrchk(cudaMemcpy(h_hyenas,dev_hyenas,fullArrSz, cudaMemcpyDeviceToHost));
for(int i=0; i < YEARS; i++)
{
h_pop[i].rabbits = h_rabbits + i*REGIONS;
h_pop[i].hyenas = h_hyenas + i*REGIONS;
}
for(int i=1; i < YEARS+1; i++)
{
arrEl = i-1;
printf("\nYear %i\n=============\n\n", i);
printf("Rabbits\n-------------\n");
for (int j=0; j < REGIONS; j++)
printf("Region: %i Pop: %i\n", j, h_pop[arrEl].rabbits[j]);;
printf("Hyenas\n-------------\n");
for (int j=0; j < REGIONS; j++)
printf("Region: %i Pop: %i\n", j, h_pop[arrEl].hyenas[j]);
}
//Free on device and host
cudaFree(dev_pop);
cudaFree(dev_rabbits);
cudaFree(dev_hyenas);
free(h_pop);
free(h_rabbits);
free(h_hyenas);
return 0;
}
[终于]正确的结果:
第一年
=============
兔子
-------------
地区:0 流行:1
地区:1 流行:2
地区:2 流行:3
地区:3 流行:4 地区:4 流行:5
地区:5 流行:6
地区:6 流行:7
地区:7 流行:8
地区:8 流行:9
地区:9 流行:10
地区:10 流行: 11
地区:11 流行:12
地区:12 流行:13
地区:13 流行:14
地区:14 流行:15
地区:15 流行:16
地区: 16 流行:17
地区:17 流行:18
地区:18 流行:19
地区:19 流行:20
鬣狗
-------------
地区:0 流行:2
地区:1 流行:2
地区:2 流行:2
地区:3 流行:2 地区:4 流行:2
地区:5 流行:2
地区:6 流行:2
地区:7 流行:2
地区:8 流行:2
地区:9 流行:2
地区:10 流行:2
地区:11 流行:2
地区:12 流行:2
地区:13 流行: 2
地区:14 流行:2
地区:15 流行:2
地区:16 流行:2
地区:17 流行:2
地区:18 流行:2
地区:19 流行:2
第 2 年
=============
兔子
-------------
地区:0 流行:4
地区:1 流行:8
地区:2 流行:12
地区:3 流行:16 地区:4 流行: 20
地区:5 流行:24
地区:6 流行:28
地区:7 流行:32
地区:8 流行:36
地区:9 流行:40
地区: 10 流行:44
地区:11 流行:48
地区:12 流行:52
地区:13 流行:56
地区:14 流行:60
地区:15 流行: 64
地区:16 流行:68
地区:17 流行:72
地区:18 流行:76
地区:19 流行:80
鬣狗
-------------
地区:0 流行:2
地区:1 流行:2
地区:2 流行:2
地区:3 流行:2 地区:4 流行:2
地区:5 流行:2
地区:6 流行:2
地区:7 流行:3
地区:8 流行:3
地区:9 流行:4
地区:10 流行:4
地区:11 流行:4
地区:12 流行:5
地区:13 流行: 5
地区:14 流行:6
地区:15 流行:6
地区:16 流行:6
地区:17 流行:7
地区:18 流行:7
地区:19 ...
注意 3:
在我的代码中,talonmies 清理了多个数组索引不一致等问题。
对于 AoSoA 中的前两个位置,结果似乎是正确的 SoA(请参阅新输出)。出于某种原因,第三点 (year 3) 的结果现在给出了错误的结果,尽管 GPU 没有错误代码。我要看看指针(h_pop[year-1].rabbits,h_pop[year-1].hyenas),看看是否有什么发现。
我对其他尝试 AoSoA 的人的唯一建议——非常小心你的索引和内存分配。当然,一般来说这是一个很好的建议,但由于所有内存都在复杂的多级数据容器(如 AoSoA)中四处飞散,如果你马虎,出错的趋势会成倍增加。感谢您的耐心等待,talonmies。
注意 2:
所以按照 talonmies 的建议,我修复了循环 #ing,包装了我的 cuda 调用 w。错误检查并通过重用dev_rabbits/dev_hyenas 压缩了我的cudaMemcpy 调用。还将第一个字母的大小写切换为小写,因为我正在考虑 [djmj][4] 对大小写的抱怨,我意识到 NVIDIA 确实将其常量中的第一个字母小写,所以 [djmj][4] 是是的,从某种意义上说,我应该这样设计我的代码以保持一致性,无论我的个人偏好/经验如何。
通常还清理了代码,因为我写的时候睡得很少,而且有点害怕@它是多么的草率。
现在我遇到了一个新问题……我的程序挂起@第一个cudaMemcpy,并且没有返回(因此talonmies 的方便包装器没有捕获任何东西)。我不太清楚这是为什么...我已经编译了几个程序,包括设备上更大/运行时间更长的程序,它们都运行良好。
此时我很困惑。如果它仍然不起作用,可能会在早上发布一些东西。
注 1
第一个答案似乎真的没有抓住重点。这只是一个玩具代码,并不代表真正的程序。它的唯一目的是尝试设置内存,向其中写入一些垃圾并读回它,以验证 AoSoA 是否正常工作。
因此,就共享内存等向我发表评论不会有成效。这不是这个线程的重点。当然,如果这是一个真正的代码,我会在我的内核中消除分支、使用共享内存、对齐我的数据、使用扭曲级别求和等。我已经在过去的代码中完成了所有这些并让它工作。
此代码是玩具,概念验证代码,仅此而已,旨在尝试使 AoSoA 正常工作。这是它的唯一目的,它不是真正的代码。这是一个概念证明。
至于 var 名称的大小写,我曾在两个不同的地方工作,它们在其编码标准中使用完全大小写的 var 名称(他们使用标签,我在 structs/typedefs 上使用 _s),所以很友好卡住了。对不起,你不喜欢它。至于缩进,我稍后会尝试修复它……Windows 和 Linux 玩得不太好。
还有一点需要注意,如果您对设备指针偏移感到困惑,请在此处查看Anycom 的答案:
Pointers in structs passed to CUDA
我编写了以下代码来测试 CUDA 中包含数组的结构数组....
编辑:固定代码——在meh 之后和hi 之前挂起,大概在cudaMemcpy...不确定原因!
...知道这里发生了什么以及如何解决它吗?
注意:
我担心cudaFrees 可能会把事情搞砸,但删除它们什么也没做。
[4]:
【问题讨论】:
-
这是作业吗?这是一种奇怪的缩进方案。我建议使用常规缩进,甚至在单个语句块周围使用大括号。我认为 __syncthreads() 在你拥有它的地方没有任何好处,因为内核已经存储了它的结果。
-
不,这是研究项目的游戏代码。只是试图使用简单的模棱两可的代码来验证概念,然后扩大规模......缩进来自 eMac 和 NotePad++ 之间的过渡,搞砸了一些事情......为此道歉。不过,对这个问题有什么想法吗?
-
如果大约 6 小时左右没有人回答,我会在本地运行并仔细查看。如果你在那之前弄清楚了,请告诉我......
-
您需要对该代码进行一些错误检查。每个 API 调用都会返回一个状态。全部检查。您的内核很可能永远不会运行完成,而您只是在查看未初始化的内存。
-
@JasonR.Mick:我真的不明白。您现在已经用一个严重错误的新版本替换了 100% 正确的原始版本中的代码并且您还没有解决基本问题,即简单的 1 索引与 0 索引内核中的错误,同时也以新的方式破坏内核。
标签: c arrays struct cuda malloc