【CUDA】【pycuda】第一个案例 翻倍数组

https://github.com/inducer/pycuda

加载环境

import pycuda.driver as cuda
import pycuda.autoinit
import numpy
import struct
from pycuda.compiler import SourceModule

将多个可变长度数组加倍。
DoubleOperation 的结构体,其中包含两个成员变量:datalen 和 __padding。datalen 表示数组的长度,__padding 是为了对齐 64 位指针而添加的填充变量。结构体还包含一个名为 ptr 的 float 指针,指向要进行操作的数组。

double_array 的内核函数,它使用 global 修饰符表示在 GPU 上执行。该函数接受一个指向 DoubleOperation 结构体的指针 a。

首先将指针 a 偏移 blockIdx.x 个单位,这样每个线程块都可以处理不同的 DoubleOperation 结构体。然后,使用 threadIdx.x 作为线程索引,在数组长度范围内进行迭代。

在循环中,首先将指针 a->ptr 赋值给临时变量 a_ptr,然后通过索引 idx 访问数组元素,将其乘以 2,实现双倍操作。

blockIdx.x 用于确定线程块处理的数据的位置或标识符,从而使每个线程块可以处理不同的数据部分。它表示当前执行的线程块(block)在其所属的网格(grid)中的索引值。在 CUDA 中,线程以线程块的形式组织,并且线程块可以被划分为更小的线程块,形成线程块的层次结构。

mod = SourceModule("""
    struct DoubleOperation {
        int datalen, __padding; // so 64-bit ptrs can be aligned
        float *ptr;
    };

    __global__ void double_array(DoubleOperation *a) {
        a = &a[blockIdx.x];
        for (int idx = threadIdx.x; idx < a->datalen; idx += blockDim.x) {
            a->ptr[idx] *= 2;
        }
    }
    """)

网格中的每个块(请参阅 CUDA 文档)都会使其中一个数组加倍。for循环允许比线程多的数据元素加倍,但如果可以保证有足够数量的线程,则效率不高。接下来,创建该结构的包装类,并实例化两个数组:

class DoubleOpStruct:
    mem_size = 8 + numpy.intp(0).nbytes
    def __init__(self, array, struct_arr_ptr):
        self.data = cuda.to_device(array)
        self.shape, self.dtype = array.shape, array.dtype
        packed_args = struct.pack("ixP", array.size, numpy.uintp(self.data))
        cuda.memcpy_htod(struct_arr_ptr, packed_args)

    def __str__(self):
        return str(cuda.from_device(self.data, self.shape, self.dtype))

struct_arr = cuda.mem_alloc(2 * DoubleOpStruct.mem_size)
do2_ptr = int(struct_arr) + DoubleOpStruct.mem_size

array1 = DoubleOpStruct(numpy.array([1, 2, 3], dtype=numpy.float32), struct_arr)
array2 = DoubleOpStruct(numpy.array([0, 4], dtype=numpy.float32), do2_ptr)
print("original arrays", array1, array2)

此代码使用pycuda.driver.to_device()和 pycuda.driver.from_device()函数来分配和复制值,并演示如何使用已分配内存块的偏移量。最后就可以执行代码了;下面演示了将两个数组加倍,然后只加倍第二个:

func = mod.get_function("double_array")
func(struct_arr, block = (32, 1, 1), grid=(2, 1))
print("doubled arrays", array1, array2)

func(numpy.intp(do2_ptr), block = (32, 1, 1), grid=(1, 1))
print("doubled second only", array1, array2, "\n")

你可能感兴趣的:(CUDA,pycuda)