cuda - 如何使用 CUDA C 快速压缩稀疏数组?

标签 cuda gpgpu sparse-array

摘要

设备内存中的数组 [A - B - - - C] 但想要 [A B C] - 使用 CUDA C 最快的方法是什么?

上下文

我在设备 (GPU) 内存上有一个整数数组 A。在每次迭代中,我随机选择一些大于 0 的元素并从中减去 1。我维护一个排序查找数组 L ,其中包含等于 0 的元素:

Array A:
       @ iteration i: [0 1 0 3 3 2 0 1 2 3]
   @ iteration i + 1: [0 0 0 3 2 2 0 1 2 3]

Lookup for 0-elements L:
       @ iteration i: [0 - 2 - - - 6 - - -]  ->  want compacted form: [0 2 6]
   @ iteration i + 1: [0 1 2 - - - 6 - - -]  ->  want compacted form: [0 1 2 6]

(这里,我随机选择元素 14 来减去 1。在 CUDA C 中的实现中,每个线程映射到 A,因此查找数组是稀疏的,以防止数据竞争并保持排序顺序(例如 [0 1 2 6] 而不是 [0 2 6 1 ]).)

稍后,我将仅对那些等于 0 的元素进行一些操作。因此,我需要压缩稀疏查找数组 L,以便我可以将线程映射到 0 元素。

因此,使用 CUDA C 在设备内存上压缩稀疏数组的最有效方法是什么?

非常感谢。

最佳答案

假设我有:

int V[] = {1, 2, 0, 0, 5};

我想要的结果是:

int R[] = {1, 2, 5}

实际上,我们正在删除零元素,或者仅复制非零元素。

#include <thrust/device_ptr.h>
#include <thrust/copy.h>
#include <stdio.h>
#define SIZE 5

#define cudaCheckErrors(msg) \
    do { \
        cudaError_t __err = cudaGetLastError(); \
        if (__err != cudaSuccess) { \
            fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
                msg, cudaGetErrorString(__err), \
                __FILE__, __LINE__); \
            fprintf(stderr, "*** FAILED - ABORTING\n"); \
            exit(1); \
        } \
    } while (0)

  struct is_not_zero
  {
    __host__ __device__
    bool operator()(const int x)
    {
      return (x != 0);
    }
  };



int main(){

  int V[] = {1, 2, 0, 0, 5};
  int R[] = {0, 0, 0, 0, 0};
  int *d_V, *d_R;

  cudaMalloc((void **)&d_V, SIZE*sizeof(int));
  cudaCheckErrors("cudaMalloc1 fail");
  cudaMalloc((void **)&d_R, SIZE*sizeof(int));
  cudaCheckErrors("cudaMalloc2 fail");

  cudaMemcpy(d_V, V, SIZE*sizeof(int), cudaMemcpyHostToDevice);
  cudaCheckErrors("cudaMemcpy1 fail");

  thrust::device_ptr<int> dp_V(d_V);
  thrust::device_ptr<int> dp_R(d_R);
  thrust::copy_if(dp_V, dp_V + SIZE, dp_R, is_not_zero());

  cudaMemcpy(R, d_R, SIZE*sizeof(int), cudaMemcpyDeviceToHost);
  cudaCheckErrors("cudaMemcpy2 fail");

  for (int i = 0; i<3; i++)
    printf("R[%d]: %d\n", i, R[i]);

  return 0;


}

结构定义为我们提供了一个测试零元素的仿函数。请注意,在推力中,没有内核,我们也没有直接编写设备代码。所有这一切都发生在幕后。我绝对建议您熟悉 quick start guide ,以免把这个问题变成推力教程。

查看评论后,我认为此代码的修改版本将解决 cuda 4.0 问题:

#include <thrust/device_ptr.h>
#include <thrust/copy.h>
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <stdio.h>
#define SIZE 5

  struct is_not_zero
  {
    __host__ __device__
    bool operator()(const int x)
    {
      return (x != 0);
    }
  };



int main(){

  int V[] = {1, 2, 0, 0, 5};
  int R[] = {0, 0, 0, 0, 0};

  thrust::host_vector<int> h_V(V, V+SIZE);
  thrust::device_vector<int> d_V = h_V;
  thrust::device_vector<int> d_R(SIZE, 0);

  thrust::copy_if(d_V.begin(), d_V.end(), d_R.begin(), is_not_zero());
  thrust::host_vector<int> h_R = d_R;

  thrust::copy(h_R.begin(), h_R.end(), R);

  for (int i = 0; i<3; i++)
    printf("R[%d]: %d\n", i, R[i]);

  return 0;


}

关于cuda - 如何使用 CUDA C 快速压缩稀疏数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14258210/

相关文章:

python - 有没有类似 coo_matrix 的东西,但是对于稀疏向量?

c - 如何按升序创建链表

c++ - cuda浮点精度

visual-studio-2008 - OpenCV 2.4.3rc 和 CUDA 4.2 : "OpenCV Error: No GPU support"

Cuda 重用事件来确定多个部分的执行时间

c++ - 具有 PBO 支持的高级 OpenGL 库

wolfram-mathematica - 在Mathematica中对稀疏数组的有效替代(Outer)吗?

c++ - CUDA:分配 1d 设备内存以将 2d 指针到指针主机数组复制到 GPU 或从 GPU 复制

arrays - 如何读回 CUDA 纹理进行测试?

gcc - GCC 中的 OpenMP 4.0 : offload to nVidia GPU