【问题标题】:CUDA brute force funCUDA蛮力乐趣
【发布时间】: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 current max average save loop index 这样我就可以得到玩家姓名和平均分数,以便稍后与其他线程进行比较。

    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 &lt;&lt;&lt;2048, 1&gt;&gt;&gt;?或者更像addKernel &lt;&lt;&lt;2048, 1024&gt;&gt;&gt;?然后我可以调整 for 循环间隙的大小以适应这个形状。

如果需要,很高兴发布代码(它很长,所以不想在这个大帖子中添加更多内容)。

【问题讨论】:

    标签: c++ arrays cuda brute-force


    【解决方案1】:

    首先,由于有预算,这是一个背包问题。蛮力是不必要的。 CPU 可以使用适当的算法几乎立即计算出来。

    https://en.m.wikipedia.org/wiki/Knapsack_problem

    【讨论】:

    • 我一开始就尝试了背包优化,但一定错过了一些东西,因为在这种情况下我看不到它如何实现加速,因为每个组合都需要评估。例如在 wiki 示例中,w[] 是 8 维的,n = 286,853,510,505,870。 for i from 1 to n do: for j from 0 to W do: if w[i-1] > j then: m[i, j] := m[i-1, j] else: m[i, j ] := max(m[i-1, j], m[i-1, jw[i-1]] + v[i-1])
    • @matt 请阅读有关动态编程的更多信息。你的问题是0/1背包问题。在您的情况下,n = 266。你只需要计算m[i,W],其中i=8,W是你的预算,m[i,W]是8个玩家的最高点和预算W。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-08
    • 2013-04-11
    • 2021-02-22
    • 2015-11-11
    相关资源
    最近更新 更多