美文网首页
julia GPU编程之CUDA使用

julia GPU编程之CUDA使用

作者: 昵称违法 | 来源:发表于2021-06-11 14:14 被阅读0次

本文使用的是CUDA.jl

一、数据在内存和显存之间移动

如下代码所示,a、b是在内存中的两个vec

N = 2^10
a = fill(1.0f0,N)
b = fill(2.0f0,N)

如何把a、b加载到GPU内存中去?用CuArray()

a_gpu = CuArray(a)
b_gpu = CuArray(b)

如何把GPU中的array数据拷贝会内存中来?用Array()

a_cpu = Array(a_gpu)
b_cpu = Array(b_gpu)

二、案例练习:如何用GPU来完成 【a_gpu + b_gpu】的操作

【1】直接用向量化的【+】操作符完成 :a_gpu .+ b_gpu

 a_gpu .+ b_gpu

总结:表达上比较自然、和蔼可亲

【2】用【map】和【+】完成

c_gpu = CUDA.map(+,a_gpu,b_gpu)

总结:表达上比较自然、符合常见的编程习惯

【3】用【map】和匿名函数完成

c_cpu = CUDA.map((x,y)->x+y,a_gpu,b_gpu)

总结:匿名函数增加了逻辑操作的丰富程度,比如你可以使用三元操作

【4】用【map】和自定义函数完成

#自定义一个add函数
function fn_add(x,y)
    #bula bula 你还可以添加一大堆逻辑
    return x+y
end
c_cpu = CUDA.map(fn_add,a_gpu,b_gpu)

总结:自定义function的好处就是,里面你可以写一些更复杂的逻辑,比如下面的例子:

function fn_format(x,y)
    x>y ? '大' : '小'
end
c_cpu = CUDA.map(fn_format,a_gpu,b_gpu)
@show(c_cpu)

【5】自己写cuda 的kernel函数来完成

你在写CUDA核函数的时候,你需要补充一些基础知识。
以下概念你需要弄清楚:流处理器,warps,CUDA核心。Grid,blocks,threads。

function cuda_add!(a,b,c)
    #blockDim().x  【线程块】的总数量
    #blockIdx().x   当前【线程块】的编号
    #threadIdx().x  当前【线程】在当前【线程块】中的编号
    #注意cuda核函数,return nothing

    index = (blockIdx().x - 1) * blockDim().x + threadIdx().x  #计算下标(index)
    @inbounds c[index] = a[index] + b[index]
    return nothing
end

numblocks = ceil(Int, N/256) #分成多少个线程块

@cuda threads=256 blocks=numblocks cuda_add!(a_gpu,b_gpu,res)
@show(res)

注意:
(1)kernel函数不能返回具体的值,只能返回nothing
(2)函数带一个【!】叹号,代表变量会被就地更新
(3)CUDA kernel编程请参考https://github.com/JuliaGPU/CUDA.jl

三、一些奇怪的问题

下面的代码中,fn_format1和fn_format2的功能是一样的,但为红色代码出会出现报错呢?是精度导致的计算分支的问题吗?


image.png
a_d = CUDA.rand(1024)
b_d = CUDA.rand(1024)

function fn_format1(a,b)    
    if a > b
        a+b
    elseif a <=b
        a*b
    end
end

function fn_format2(a,b)
    a>b ? a+b : a*b
end

CUDA.map(fn_format1,a_d,b_d) #此行报错
CUDA.map(fn_format2,a_d,b_d)

把if加一个else分支后,不再出问题。


image.png

相关文章

网友评论

      本文标题:julia GPU编程之CUDA使用

      本文链接:https://www.haomeiwen.com/subject/vxzmeltx.html