首页 文章

CUDA \ NUMBA同步速度较慢

提问于
浏览
-1

我是CUDA的新手,我正在尝试用NUMBA \ CUDA来加速我的代码 . 但是,我遇到了一些麻烦,因为我的代码非常慢 . 示例代码如下所示 .

from timeit import default_timer as timer
from numba import jit, guvectorize, int32, int64, float64
from numba import cuda

@cuda.jit
def f_vec_loops(x, ret, maxiter):
    nx = len(ret)
    ny = len(ret[0])
    for k in range(maxiter):
        for i in range(nx):
            for j in range(ny):
                ret[i, j] += x[i, j]


x = 1024
y = 1024
a = np.ones([x, y], dtype='int32')
ret = np.zeros([x, y], dtype='int32')

a_cuda = cuda.to_device(a)
ret_cuda = cuda.to_device(ret)
maxiter = 100

s = timer()
cuda.synchronize()
f_vec_loops(a_cuda, ret_cuda, maxiter)
cuda.synchronize()

print(timer() - s)

s = timer()
trt = ret_cuda.copy_to_host()
print(trt)
print(timer()-s)

代码的输出是后续的:

24.132136431649194
[[100 100 100 ..., 100 100 100]
 [100 100 100 ..., 100 100 100]
 [100 100 100 ..., 100 100 100]
 ...,
 [100 100 100 ..., 100 100 100]
 [100 100 100 ..., 100 100 100]
 [100 100 100 ..., 100 100 100]]
 0.03437229066477343

正如您所看到的,与问题的复杂性相关的结果时间是巨大的 . 我试图隔离单个GPU功能,结果时间非常小:

0.1956893293540045

我实现了这个取消“cuda.synchronize()”,所以在某种程度上必须连接到线程的同步 . 但是,我不知道如何解决这个问题 . 欢迎任何帮助!

1 回答

  • 2

    这里有两个基本错误 - 您的内核是完全串行的,并且您正在运行一个线程 . 您通过删除 cuda.synchronize() 看到的明显加速只是改变您测量的结果 . 内核启动API是异步的,因此删除同步调用只是意味着您只测量内核启动时间,而不是总内核执行时间 .

    您的内核可以通过以下方式进行简单修改:

    from timeit import default_timer as timer
    from numba import jit, guvectorize, int32, int64, float64
    from numba import cuda
    import numpy as np
    import math
    
    @cuda.jit
    def f_vec_loops2(x, ret, maxiter):
        nx = len(ret)
        ny = len(ret[0])
    
        i, j = cuda.grid(2)
        if (i < nx) & (j < ny):
            value = 0
            for k in range(maxiter):
                value += x[i, j]
    
            ret[i, j] = value
    
    @cuda.jit
    def f_vec_loops(x, ret, maxiter):
        nx = len(ret)
        ny = len(ret[0])
        for k in range(maxiter):
            for i in range(nx):
                for j in range(ny):
                    ret[i, j] += x[i, j]
    
    
    x = 1024
    y = 1024
    a = np.ones([x, y], dtype='int32')
    ret = np.zeros([x, y], dtype='int32')
    
    a_cuda = cuda.to_device(a)
    ret_cuda = cuda.to_device(ret)
    maxiter = 100
    
    s = timer()
    f_vec_loops(a_cuda, ret_cuda, maxiter)
    cuda.synchronize()
    print(timer() - s)
    
    threadsperblock = (16, 16)
    blockspergrid_x = math.ceil(x / threadsperblock[0])
    blockspergrid_y = math.ceil(y / threadsperblock[1])
    blockspergrid = (blockspergrid_x, blockspergrid_y)
    
    s = timer()
    f_vec_loops2[blockspergrid, threadsperblock](a_cuda, ret_cuda, maxiter)
    cuda.synchronize()
    print(timer() - s)
    
    s = timer()
    trt = ret_cuda.copy_to_host()
    print(trt)
    print(timer()-s)
    

    跑步时你会看到类似的东西:

    In [2]: %run something.py
    24.983618166297674
    0.11915503349155188
    [[100 100 100 ..., 100 100 100]
     [100 100 100 ..., 100 100 100]
     [100 100 100 ..., 100 100 100]
     ..., 
     [100 100 100 ..., 100 100 100]
     [100 100 100 ..., 100 100 100]
     [100 100 100 ..., 100 100 100]]
    0.002271135337650776
    

    与原始(完全串行)代码相比,它提供了大约200倍的加速 .

    在CUDA中编写并行代码的基本概念在书籍,教程,博客,Stack Overflow问题以及工具包文档本身中有详细描述 . Numba Python CUDA语言非常忠实地复制了基本CUDA C语言的子集,从CUDA C学习CUDA Python的障碍非常低 . 您需要做的就是阅读 .

相关问题