【问题标题】:Generate all combinations of a char array inside of a CUDA __device__ kernel在 CUDA __device__ 内核中生成 char 数组的所有组合
【发布时间】:2010-12-19 15:49:43
【问题描述】:

我需要帮助。我开始用 CUDA (2.3 / 3.0beta) 编写一个常见的暴力破解器/密码猜测器。 我尝试了不同的方法来生成定义的 ASCII 字符集的所有可能的纯文本“候选”。

在此示例代码中,我想生成所有 74^4 种可能的组合(并将结果输出回主机/标准输出)。

$ ./combinations
Total number of combinations    : 29986576

Maximum output length   : 4
ASCII charset length    : 74

ASCII charset   : 0x30 - 0x7a
 "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxy"

CUDA 代码(使用 2.3 和 3.0b - sm_10 编译)-combinaions.cu:

#include <stdio.h>
#include <cuda.h>

__device__ uchar4 charset_global = {0x30, 0x30, 0x30, 0x30};
__shared__ __device__ uchar4 charset[128];

__global__ void combo_kernel(uchar4 * result_d, unsigned int N)
{
 int totalThreads = blockDim.x * gridDim.x ;
 int tasksPerThread = (N % totalThreads) == 0 ? N / totalThreads : N/totalThreads + 1;
 int myThreadIdx = blockIdx.x * blockDim.x + threadIdx.x ;
 int endIdx = myThreadIdx + totalThreads * tasksPerThread ;
 if( endIdx > N) endIdx = N;

 const unsigned int m = 74 + 0x30;

 for(int idx = myThreadIdx ; idx < endIdx ; idx += totalThreads) {
  charset[threadIdx.x].x = charset_global.x;
  charset[threadIdx.x].y = charset_global.y;
  charset[threadIdx.x].z = charset_global.z;
  charset[threadIdx.x].w = charset_global.w;
  __threadfence();

  if(charset[threadIdx.x].x < m) {
   charset[threadIdx.x].x++;

  } else if(charset[threadIdx.x].y < m) {
   charset[threadIdx.x].x = 0x30; // = 0
   charset[threadIdx.x].y++;

  } else if(charset[threadIdx.x].z < m) {
   charset[threadIdx.x].y = 0x30; // = 0
   charset[threadIdx.x].z++;

  } else if(charset[threadIdx.x].w < m) {
   charset[threadIdx.x].z = 0x30;
   charset[threadIdx.x].w++;; // = 0
  }

  charset_global.x = charset[threadIdx.x].x;
  charset_global.y = charset[threadIdx.x].y;
  charset_global.z = charset[threadIdx.x].z;
  charset_global.w = charset[threadIdx.x].w;

  result_d[idx].x = charset_global.x;
  result_d[idx].y = charset_global.y;
  result_d[idx].z = charset_global.z;
  result_d[idx].w = charset_global.w;
 }
}

#define BLOCKS 65535
#define THREADS 128

int main(int argc, char **argv)
{
 const int ascii_chars = 74;
 const int max_len = 4;
 const unsigned int N = pow((float)ascii_chars, max_len);
 size_t size = N * sizeof(uchar4);

 uchar4 *result_d, *result_h;
 result_h = (uchar4 *)malloc(size );
 cudaMalloc((void **)&result_d, size );
 cudaMemset(result_d, 0, size);

 printf("Total number of combinations\t: %d\n\n", N); 
 printf("Maximum output length\t: %d\n", max_len);
 printf("ASCII charset length\t: %d\n\n", ascii_chars);

 printf("ASCII charset\t: 0x30 - 0x%02x\n ", 0x30 + ascii_chars);
 for(int i=0; i < ascii_chars; i++)
  printf("%c",i + 0x30);
 printf("\n\n");

 combo_kernel <<< BLOCKS, THREADS >>> (result_d, N);
 cudaThreadSynchronize();

 printf("CUDA kernel done\n");
 printf("hit key to continue...\n");
 getchar();

 cudaMemcpy(result_h, result_d, size, cudaMemcpyDeviceToHost);

 for (unsigned int i=0; i<N; i++)
  printf("result[%06u]\t%c%c%c%c\n",i, result_h[i].x, result_h[i].y, result_h[i].z, result_h[i].w);

 free(result_h);
 cudaFree(result_d);
}

代码应该可以正常编译,但输出不是我所期望的。

在仿真模式下:

CUDA kernel done hit
key to continue...

    result[000000]  1000 
...
    result[000128]  5000

在发布模式下:

CUDA kernel done hit
key to continue...

    result[000000]  1000 
...
    result[012288]  5000

我还在代码的不同行上使用了 __threadfence() 和或 __syncthreads() 也没有成功...

ps。如果可能的话,我想在内核函数中生成所有内容。我还尝试在 host 主函数和 memcpy 到 device 内“预”生成可能的纯文本候选,这仅适用于非常有限的字符集大小(因为设备内存有限)。

  • 关于输出的任何想法,为什么重复(即使使用 __threadfence() 或 __syncthreads())?

  • 在 CUDA 内核中快速生成纯文本(候选)的任何其他方法 :-) (~75^8) ?

感谢一百万

问候杨

【问题讨论】:

    标签: cryptography cuda character-encoding combinations


    【解决方案1】:

    顺便说一句,您的循环绑定过于复杂。您不需要做所有这些工作来计算 endIdx,而是可以执行以下操作,从而使代码更简单。

    for(int idx = myThreadIdx ; idx < N ; idx += totalThreads)
    

    【讨论】:

      【解决方案2】:

      让我们看看:

      • 填充字符集数组时,__syncthreads() 就足够了,因为您对写入全局内存不感兴趣(稍后会详细介绍)
      • 您的 if 语句未正确重置循环迭代器:
        • z &lt; m 中,x == my == m 都必须设置为 0。
        • w 类似
      • 每个线程负责在charset 中写入一组4 个字符,但每个线程写入相同的4 个值。没有线程做任何独立的工作。
      • 您正在将每个线程的结果写入没有原子的全局内存,这是不安全的。无法保证在读取结果之前不会立即被另一个线程破坏。
      • 在将计算结果写入全局内存后,您会立即从全局内存中读取计算结果。目前尚不清楚您为什么要这样做,这是非常不安全的。
      • 最后,在 CUDA 中没有可靠的方法来实现所有块之间的同步,这似乎是您所希望的。调用__threadfence 仅适用于当前在设备上执行的块,它可以是应该为内核调用运行的所有块的子集。因此它不能用作同步原语。

      计算每个线程的 x、y、z 和 w 的初始值可能更容易。然后每个线程可以从它的初始值开始循环,直到它执行完 tasksPerThread 迭代。写出这些值可能或多或少地像您现在所拥有的那样进行。

      编辑:这是一个简单的测试程序,用于演示循环迭代中的逻辑错误:

      int m = 2;
      int x = 0, y = 0, z = 0, w = 0;
      
      for (int i = 0; i < m * m * m * m; i++)
      {
          printf("x: %d y: %d z: %d w: %d\n", x, y, z, w);
          if(x < m) {
              x++;
          } else if(y < m) {
              x = 0; // = 0
              y++;
          } else if(z < m) {
              y = 0; // = 0
              z++;
          } else if(w < m) {
              z = 0;
              w++;; // = 0
          }
      }
      

      它的输出是这样的:

      x: 0 y: 0 z: 0 w: 0
      x: 1 y: 0 z: 0 w: 0
      x: 2 y: 0 z: 0 w: 0
      x: 0 y: 1 z: 0 w: 0
      x: 1 y: 1 z: 0 w: 0
      x: 2 y: 1 z: 0 w: 0
      x: 0 y: 2 z: 0 w: 0
      x: 1 y: 2 z: 0 w: 0
      x: 2 y: 2 z: 0 w: 0
      x: 2 y: 0 z: 1 w: 0
      x: 0 y: 1 z: 1 w: 0
      x: 1 y: 1 z: 1 w: 0
      x: 2 y: 1 z: 1 w: 0
      x: 0 y: 2 z: 1 w: 0
      x: 1 y: 2 z: 1 w: 0
      x: 2 y: 2 z: 1 w: 0
      

      【讨论】:

      • 您好,感谢您的回答!我的想法是“device uchar4 charset_global”是一种主数组。每个线程块应该获取“charset_global 的当前值”到共享 charset[128],进行下一个组合(用这里设置的 char 填充一些计算),最后将“已经由线程计算的”组合写入 ​​charset_global var。 (因此下一个线程可以使用“已经完成的组合”作为偏移量)。我希望你说得对;))附言。 “你的 if 语句没有正确重置你的循环迭代器” - 应该在用户空间上正确工作 - 来源:combfunc aocp
      • 我不知道“在用户空间中正确工作”是什么意思,但是您可以使用我编辑的代码看到循环迭代确实存在问题。
      • 您描述的算法(在您的评论中)是一个串行算法。也就是说,在从前一个线程获得结果之前,任何线程都无法计算唯一密码。没有线程可以并行操作,因为它们会以相同的初始密码开始并以相同的方式排列它,从而产生重复的输出。并行化的方法是了解您将生成 74^N 种可能的组合,并且每个线程将生成 74^N/M 的这些组合,完全独立于任何其他线程的操作。
      猜你喜欢
      • 2011-08-08
      • 1970-01-01
      • 1970-01-01
      • 2019-03-14
      • 1970-01-01
      • 2014-03-06
      • 2021-12-11
      • 1970-01-01
      • 2021-11-20
      相关资源
      最近更新 更多