首页 > 解决方案 > Numba CUDA 加速似乎很低

问题描述

新手从 Numba/cuda 开始。我写了这个小测试脚本来比较@jit 和@cuda.jit。速度,只是为了感受一下。它为 256 个单独的实例计算逻辑方程的 10M 步。cuda 部分大约需要 1.2 秒才能完成。cpu 'jitted' 部分在接近 5 秒内完成(cpu 上只使用了一个线程)。因此,从 GPU(专用 GTX1080TI 不做任何其他事情)开始,大约有 4 倍的加速。我预计并行处理所有 256 个实例的 cuda 部分会快得多。我究竟做错了什么?

这是工作示例:

#!/usr/bin/python3
#logistic equation on gpu/cpu comparison

import os,sys
#Set environment variables (needed for numba 0.42 to find lvvm)
os.environ['NUMBAPRO_NVVM'] = '/usr/lib/x86_64-linux-gnu/libnvvm.so'
os.environ['NUMBAPRO_LIBDEVICE'] = '/usr/lib/nvidia-cuda-toolkit/libdevice/'

from time import time
from scipy import *
from numba import cuda, jit
from numba import int64,int32, float64

@cuda.jit
def logistic_cuda(array_in,array_out):
    pos = cuda.grid(1)
    x = array_in[pos]
    for k in range(10*1000*1000):
        x = 3.9 * x * (1 - x)
    array_out[pos] = x

@jit
def logistic_cpu(array_in,array_out):
    for pos,x in enumerate(array_in):
        for k in range(10*1000*1000):
            x = 3.9 * x * (1 - x)
        array_out[pos] = x

if __name__ == '__main__':
    N=256
    in_ary = random.uniform(low=0.2,high=0.9,size=N).astype('float32')
    out_ary = zeros(N,dtype='float32')
    
    t0 = time()
    #explicit copying. not really needed
    d_in_ary = cuda.to_device(in_ary) 
    d_out_ary = cuda.to_device(out_ary)
    t1 = time()
    
    logistic_cuda[1,N](d_in_ary,d_out_ary)
    cuda.synchronize()
    t2 = time()
    out_ary = d_out_ary.copy_to_host()
    t3 = time()
    
    print(out_ary)
    print('Total time cuda: %g seconds.'%(t3-t0))
    
    out_ary2 = zeros(N)
    t4 = time()
    logistic_cpu(in_ary,out_ary2)
    t5 = time()
    print('Total time cpu: %g seconds.'%(t5-t4))
    
    print('\nDifference:')
    print(out_ary2-out_ary)
    
#Total time cuda: 1.19364 seconds.
#Total time cpu: 5.01788 seconds.

谢谢!

标签: pythonperformancenumba

解决方案


问题可能来自于非常少量的数据循环依赖。事实上,由于大量的 CUDA 内核,现代 Nvidia GPU 可以同时执行数千个 CUDA 线程(打包成 32 个线程)。array_out在您的情况下,每个线程在使用顺序循环的一个单元上执行计算。但是,只有 256 个单元格。因此,最多可以同时运行 256 个线程(8 个 warp)——这只是您的 GPU 应该能够管理的并发线程数量的一小部分。因此,如果您想要更好的加速,您需要为 GPU 提供更多的并行性(例如通过增加数据大小或同时计算多重回归)。


推荐阅读