JuliaGPU / JuliaGPU/KernelAbstractions.jl

Inconsistent behavior with multiple GPU

Open
#289 6 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Julia
Stars
523
Forks
88
Avg merge
1d 11h
Merged PRs (30d)
25

Description

Hello!

I am recently trying to exploit the single-process multi GPU capabilities of CUDA.jl 3.8.0 to run on multiple GPU.

Unfortunately, for some weird reason, my kernel fails with ERROR: LoadError: CUDA error: invalid resource handle (code 400, ERROR_INVALID_HANDLE)
I double checked that the CuArrays are allocated on the correct device. Also, the kernel does not fail at the first run but after iterating a couple of times. This might suggest I have problems of synchronization? On the other hand, using @cuda does not show the same problem.

Here a MWE

using KernelAbstractions, CUDA, CUDAKernels, Test

function cuda_add_1!(c)
    i = threadIdx().x 
    j = blockIdx().x
    @inbounds c[i, j] += 1
    return nothing
end

@kernel function kernel_add_1!(c)
    i, j = @index(Global, NTuple)
    @inbounds c[i, j] += 1
end

function single_gpu_add1!(c, method) 
    if method == :cuda
        @cuda threads=5 blocks=5 cuda_add_1!(c)
        event = Event(CUDAKernels.CUDADevice())
    else
        test! = kernel_add_1!(CUDADevice(), 1)
        event = test!(c, ndrange=size(c))
    end

    return event
end

function multi_gpu_add_1(method, devices)
    r = []
    for dev in devices
        CUDA.device!(dev)
        push!(r, CuArray(rand(5, 5)))
    end
    for dev in devices
        CUDA.device!(dev)
        CUDA.synchronize()
    end
    for (i, dev) in enumerate(devices)
        CUDA.device!(dev)
        event = single_gpu_add1!(r[i], method)
        wait(CUDADevice(), event)
    end
    for (i, dev) in enumerate(devices)
        CUDA.device!(dev)
        CUDA.synchronize()
        @test all(Array(r[i]) .> 1)
    end
end

devices = ((CuDevice(0), ),
           (CuDevice(0), CuDevice(0)), 
           (CuDevice(0), CuDevice(1)))
for dev in devices, method in (:cuda, :kernel)
    @info "Running $method on $dev"
    for test_num in 1:10
        multi_gpu_add_1(method, dev) 
    end
end

Maybe I am doing something stupid but I don't really understand the output

julia> include("test-kernel-abstractions.jl")
[ Info: Running cuda on (CuDevice(0),)
[ Info: Running kernel on (CuDevice(0),)
[ Info: Running cuda on (CuDevice(0), CuDevice(0))
[ Info: Running kernel on (CuDevice(0), CuDevice(0))
[ Info: Running cuda on (CuDevice(0), CuDevice(1))
[ Info: Running kernel on (CuDevice(0), CuDevice(1))
ERROR: LoadError: CUDA error: invalid resource handle (code 400, ERROR_INVALID_HANDLE)
Stacktrace:
  [1] throw_api_error(res::CUDA.cudaError_enum)
    @ CUDA ~/.julia/packages/CUDA/bki2w/lib/cudadrv/error.jl:91
  [2] macro expansion
    @ ~/.julia/packages/CUDA/bki2w/lib/cudadrv/error.jl:101 [inlined]
  [3] cuLaunchKernel(f::CuFunction, gridDimX::UInt32, gridDimY::UInt32, gridDimZ::UInt32, blockDimX::UInt32, blockDimY::UInt32, blockDimZ::UInt32, sharedMemBytes::Int64, hStream::CuStream, kernelParams::Vector{Ptr{Nothing}}, extra::Ptr{Nothing})
    @ CUDA ~/.julia/packages/CUDA/bki2w/lib/utils/call.jl:26
  [4] #35
    @ ~/.julia/packages/CUDA/bki2w/lib/cudadrv/execution.jl:69 [inlined]
  [5] macro expansion
    @ ~/.julia/packages/CUDA/bki2w/lib/cudadrv/execution.jl:33 [inlined]
  [6] macro expansion
    @ ./none:0 [inlined]
  [7] pack_arguments(::CUDA.var"#35#36"{Bool, Int64, CuStream, CuFunction, CuDim3, CuDim3}, ::CUDA.KernelState, ::KernelAbstractions.CompilerMetadata{KernelAbstractions.NDIteration.DynamicSize, KernelAbstractions.NDIteration.DynamicCheck, Nothing, CartesianIndices{2, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}, KernelAbstractions.NDIteration.NDRange{2, KernelAbstractions.NDIteration.DynamicSize, KernelAbstractions.NDIteration.StaticSize{(1, 1)}, CartesianIndices{2, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}, Nothing}}, ::CuDeviceMatrix{Float64, 1})
    @ CUDA ./none:0
  [8] #launch#34
    @ ~/.julia/packages/CUDA/bki2w/lib/cudadrv/execution.jl:62 [inlined]
  [9] #40
    @ ~/.julia/packages/CUDA/bki2w/lib/cudadrv/execution.jl:136 [inlined]
 [10] macro expansion
    @ ~/.julia/packages/CUDA/bki2w/lib/cudadrv/execution.jl:95 [inlined]
 [11] macro expansion
    @ ./none:0 [inlined]
 [12] convert_arguments
    @ ./none:0 [inlined]
 [13] #cudacall#39
    @ ~/.julia/packages/CUDA/bki2w/lib/cudadrv/execution.jl:135 [inlined]
 [14] macro expansion
    @ ~/.julia/packages/CUDA/bki2w/src/compiler/execution.jl:204 [inlined]
 [15] macro expansion
    @ ./none:0 [inlined]
 [16] call(::CUDA.HostKernel{typeof(Cassette.overdub), Tuple{Cassette.Context{nametype(CUDACtx), Nothing, Nothing, KernelAbstractions.var"##PassType#257", Nothing, Cassette.DisableHooks}, typeof(gpu_kernel_add_1!), KernelAbstractions.CompilerMetadata{KernelAbstractions.NDIteration.DynamicSize, KernelAbstractions.NDIteration.DynamicCheck, Nothing, CartesianIndices{2, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}, KernelAbstractions.NDIteration.NDRange{2, KernelAbstractions.NDIteration.DynamicSize, KernelAbstractions.NDIteration.StaticSize{(1, 1)}, CartesianIndices{2, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}, Nothing}}, CuDeviceMatrix{Float64, 1}}}, ::Cassette.Context{nametype(CUDACtx), Nothing, Nothing, KernelAbstractions.var"##PassType#257", Nothing, Cassette.DisableHooks}, ::typeof(gpu_kernel_add_1!), ::KernelAbstractions.CompilerMetadata{KernelAbstractions.NDIteration.DynamicSize, KernelAbstractions.NDIteration.DynamicCheck, Nothing, CartesianIndices{2, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}, KernelAbstractions.NDIteration.NDRange{2, KernelAbstractions.NDIteration.DynamicSize, KernelAbstractions.NDIteration.StaticSize{(1, 1)}, CartesianIndices{2, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}, Nothing}}, ::CuDeviceMatrix{Float64, 1}; call_kwargs::Base.Iterators.Pairs{Symbol, Any, Tuple{Symbol, Symbol, Symbol}, NamedTuple{(:threads, :blocks, :stream), Tuple{Int64, Int64, CuStream}}})
    @ CUDA ./none:0
 [17] (::CUDA.HostKernel{typeof(Cassette.overdub), Tuple{Cassette.Context{nametype(CUDACtx), Nothing, Nothing, KernelAbstractions.var"##PassType#257", Nothing, Cassette.DisableHooks}, typeof(gpu_kernel_add_1!), KernelAbstractions.CompilerMetadata{KernelAbstractions.NDIteration.DynamicSize, KernelAbstractions.NDIteration.DynamicCheck, Nothing, CartesianIndices{2, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}, KernelAbstractions.NDIteration.NDRange{2, KernelAbstractions.NDIteration.DynamicSize, KernelAbstractions.NDIteration.StaticSize{(1, 1)}, CartesianIndices{2, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}, Nothing}}, CuDeviceMatrix{Float64, 1}}})(::Cassette.Context{nametype(CUDACtx), Nothing, Nothing, KernelAbstractions.var"##PassType#257", Nothing, Cassette.DisableHooks}, ::Vararg{Any, N} where N; threads::Int64, blocks::Int64, kwargs::Base.Iterators.Pairs{Symbol, CuStream, Tuple{Symbol}, NamedTuple{(:stream,), Tuple{CuStream}}})
    @ CUDA ~/.julia/packages/CUDA/bki2w/src/compiler/execution.jl:462
 [18] (::KernelAbstractions.Kernel{CUDADevice, KernelAbstractions.NDIteration.StaticSize{(1,)}, KernelAbstractions.NDIteration.DynamicSize, typeof(gpu_kernel_add_1!)})(args::CuArray{Float64, 2, CUDA.Mem.DeviceBuffer}; ndrange::Tuple{Int64, Int64}, dependencies::CUDAKernels.CudaEvent, workgroupsize::Nothing, progress::Function)
    @ CUDAKernels ~/.julia/packages/CUDAKernels/kCOA4/src/CUDAKernels.jl:223
 [19] single_gpu_add1!(c::CuArray{Float64, 2, CUDA.Mem.DeviceBuffer}, method::Symbol)
    @ Main ~/test-architectures/test-kernel-abstractions.jl:21
 [20] multi_gpu_add_1(method::Symbol, devices::Tuple{CuDevice, CuDevice})
    @ Main ~/test-architectures/test-kernel-abstractions.jl:39
 [21] top-level scope
    @ ~/test-architectures/test-kernel-abstractions.jl:54
 [22] include(fname::String)
    @ Base.MainInclude ./client.jl:444
 [23] top-level scope
    @ REPL[4]:1
 [24] top-level scope
    @ ~/.julia/packages/CUDA/bki2w/src/initialization.jl:52

I am using

      Status `~/.julia/environments/v1.6/Project.toml`
  [052768ef] CUDA v3.8.0
  [72cfdca4] CUDAKernels v0.3.3
  [63c18a36] KernelAbstractions v0.7.2

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the MWE in test-kernel-abstractions.jl and reproduce the multi-device case that fails in CUDAKernels.jl while the direct @cuda path succeeds. Compare the device and stream handling around the KernelAbstractions launch, then verify that repeated runs on CuDevice(0) and CuDevice(1) complete without ERROR_INVALID_HANDLE and that the existing assertions pass.

Written by the indexing model from the issue text.

Assessment

Domain
hpc
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.