On AcceleratedKernels v0.4.3, CUDA.jl v6.4.0 and Julia 1.13.0:
import AcceleratedKernels as AK
using CUDA
# Exclusive prefix sum: out[i] = v[1] + ... + v[i-1]
exclusive_cumsum(v) = cumsum(v) .- v
# 1024 elements = 2 GPU blocks at the default block_size=256 (512 elements per block)
v = zeros(Int32, 1024)
v[512] = 1 # last element of the first block
v[600] = 1 # an element in the second block
expected = exclusive_cumsum(v)
cpu = AK.accumulate!(+, copy(v); init=Int32(0), inclusive=false)
println("CPU matches: ", cpu == expected)
for alg in (AK.ScanPrefixes(), AK.DecoupledLookback())
gpu = Array(AK.accumulate!(+, CuArray(v); init=Int32(0), inclusive=false, alg=alg))
println(nameof(typeof(alg)), " GPU matches: ", gpu == expected)
println(" index ", [511, 512, 513, 600, 601])
println(" expected ", expected[[511, 512, 513, 600, 601]])
println(" got ", gpu[[511, 512, 513, 600, 601]])
end
CPU matches: true
ScanPrefixes GPU matches: false
index [511, 512, 513, 600, 601]
expected [0, 0, 1, 1, 2]
got Int32[0, 0, 0, 1, 1]
DecoupledLookback GPU matches: false
index [511, 512, 513, 600, 601]
expected [0, 0, 1, 1, 2]
got Int32[0, 0, 0, 1, 1]
There appear to be two issues: the running total carried out of the first block leaves out that block's last element, and every element after the first block includes its own value. The two cancel when the input is all ones.
On AcceleratedKernels v0.4.3, CUDA.jl v6.4.0 and Julia 1.13.0:
There appear to be two issues: the running total carried out of the first block leaves out that block's last element, and every element after the first block includes its own value. The two cancel when the input is all ones.