【发布时间】:2016-11-05 02:42:01
【问题描述】:
我是 CUDA 新手,刚开始学习如何编写 CUDA 来解决这个问题。希望对我如何改进代码和 GPU 利用率提出一些意见。顺便说一句,运行 GTX 980。
我创建了一个有趣的问题,需要 266 名玩家中的任意 8 名玩家组成一个团队。目标是在预算限制(每个球员花费特定金额)的情况下为球队获得最高的总平均分(每个球员都有一个特定的平均分)。有点像梦幻运动队的问题。
我想看看我能以多快的速度暴力破解大量组合(现阶段对优化算法并不真正感兴趣)。
我目前正在为玩家详细信息创建数组。
ifstream file("D:\\Players.txt");
string content;
while (file >> content){
if (j == 0){
name[i] = content;
}
else if (j == 1){
price[i] = stoi(content);
}
else if (j == 2){
avg[i] = stoi(content);
}
else if (j == 3){
tot[i] = stoi(content);
}
j++;
if (j == 4){ j = 0; i++; }
}
然后生成8个数组,作为8个嵌套for循环的起始索引(之前生成的list.txt)。
while (output >> content){ //33002854 number of rows row ind
if (j == 0) pos[ind] = stoi(content);
else if (j == 1) pos1[ind] = stoi(content);
else if (j == 2) pos2[ind] = stoi(content);
else if (j == 3) pos3[ind] = stoi(content);
else if (j == 4) pos4[ind] = stoi(content);
else if (j == 5) pos5[ind] = stoi(content);
else if (j == 6) pos6[ind] = stoi(content);
else if (j == 7) pos7[ind] = stoi(content);
j++;
if (j == 8){ j = 0; ind++; }
}
然后将所有这些传递给内核。每个线程首先从该数组中读取它的起点。
for (q = 0; q < rowcount - 7; q++){
if (stopper == 0) q = pos[x];
for (w = q + 1; w < rowcount - 6; w++){
if (stopper == 0) w = pos1[x];
for (e = w + 1; e < rowcount - 5; e++){
if (stopper == 0) e = pos2[x];
for (r = e + 1; r < rowcount - 4; r++){
if (stopper == 0) r = pos3[x];
for (t = r + 1; t < rowcount - 3; t++){
if (stopper == 0) t = pos4[x];
for (y = t + 1; y < rowcount - 2; y++){
if (stopper == 0) y = pos5[x];
for (u = y + 1; u < rowcount - 1; u++){
if (stopper == 0) u = pos6[x];
for (i = u + 1; i < rowcount; i++){
if (stopper == 0) {
i = pos7[x]; stopper = 1;
}
其中 x = threadIdx.x,行数 = 266。
如果您在一个线程上从头到尾执行,总共需要完成大约 286,853,510,505,870 个循环。我作弊了一点,并添加了一些技巧,通过对数据进行排序,在嵌套循环中向前跳,所以如果价格 > 预算在任何位置跳到下一个位置,则不会是 > 预算。
然后评估循环和 if price
for (i = u + 1; i < rowcount; i++){
if (stopper == 0) {
i = pos7[x]; stopper = 1;
}
p[0] = price[q] + price[w] + price[e] + price[r] + price[t] + price[y] + price[u] + price[i];
if (p[0] < budget){
a[0] = avg[q] + avg[w] + avg[e] + avg[r] + avg[t] + avg[y] + avg[u] + avg[i];
if (a[0] > maxavg[x]){
thread[x] = loopcounter;
maxavg[x] = a[0];
}
loopcounter++;
}
else {
loopcounter = loopcounter + rowcount - i;
i = rowcount;
}
if (loopcounter >= count){return;}
}
count = 16936750,即每个线程之间的循环数。
将 thread[] 和 maxavg[] 传回主机,然后通过 maxavg[i] 进行 for 循环以找到最大值并打印 thread[]。
问题 1
我很好奇这条线有多安全
thread[x] = loopcounter;
maxavg[x] = a[0];
如果没有原子函数,这会发生冲突吗?当我写它时,我认为这是一个很好的方法,可以让每个线程与全局内存共享其解决方案,而不会出现任何减速/冲突。是否可以将另一个线程中的 a[0] 写入 maxavg[x] 或 loopcounter?
问题 2
如何加快速度?要完成这需要 33002854 个线程。
addKernel <<<32230, 1024>>>(dprice, davg, dpos, dpos1, dpos2, dpos3, dpos4, dpos5, dpos6, dpos7, dthread, dmaxavg);
我昨晚跑了 1024 个块和线程
addKernel <<<1024, 1024>>>(dprice, davg, dpos, dpos1, dpos2, dpos3, dpos4, dpos5, dpos6, dpos7, dthread, dmaxavg);
我在 13 小时内未完成后停止了它。由于我有 2048 个 CUDA 内核,这是否意味着如果 100% 被利用,我应该能够同时运行 2048 个线程addKernel <<<2048, 1>>>?或者更像addKernel <<<2048, 1024>>>?然后我可以调整 for 循环间隙的大小以适应这个形状。
如果需要,很高兴发布代码(它很长,所以不想在这个大帖子中添加更多内容)。
【问题讨论】:
标签: c++ arrays cuda brute-force