JuliaGPU/CUDA.jl

Adapt + strictly-typed fields can trigger confusing errors

开放

#2,384 创建于 2024年5月15日

 (0 条评论) (0 个反应) (0 位负责人)Julia (274 个派生)batch import
enhancementgood first issue

仓库指标

星标
 (1,408 个星标)
PR 合并指标
 (平均合并 5天 5小时) (30 天内合并 16 个 PR)

描述

Say, a user wants to pass a struct with CuArrays to the GPU:

julia> struct Foo
       x::CuVector{Float32}
       end

julia> @cuda Returns(nothing)(Foo(CUDA.rand(1)))
ERROR: GPU compilation of MethodInstance for (::Returns{Nothing})(::Foo) failed
KernelError: passing and using non-bitstype argument

We may tell him to define an Adapt rule to convert the CuArray to CuDeviceArray. However, because the field isn't parametric, that triggers a very confusing error:

julia> Adapt.@adapt_structure Foo

julia> @cuda Returns(nothing)(Foo(CUDA.rand(1)))
ERROR: This function is not intended for use on the CPU
Stacktrace:
  [1] error(s::String)
    @ Base ./error.jl:35
  [2] arrayref(A::CuDeviceVector{Float32, 1}, index::Int64)
    @ CUDA ~/Julia/pkg/CUDA/src/device/utils.jl:29
  [3] getindex
    @ ~/Julia/pkg/CUDA/src/device/array.jl:164 [inlined]
  [4] copyto_unaliased!
    @ ./abstractarray.jl:1088 [inlined]
  [5] copyto!
    @ ./abstractarray.jl:1068 [inlined]
  [6] copyto_axcheck!
    @ ./abstractarray.jl:1177 [inlined]
  [7] Array
    @ ./array.jl:673 [inlined]
  [8] Array
    @ ./boot.jl:501 [inlined]
  [9] convert
    @ ./array.jl:665 [inlined]
 [10] CuArray
    @ ~/Julia/pkg/CUDA/src/array.jl:406 [inlined]
 [11] CuArray
    @ ~/Julia/pkg/CUDA/src/array.jl:410 [inlined]
 [12] convert(::Type{CuArray{Float32, 1}}, a::CuDeviceVector{Float32, 1})
    @ GPUArrays ~/Julia/pkg/GPUArrays/src/host/construction.jl:4
 [13] Foo
    @ ./REPL[5]:2 [inlined]
 [14] adapt_structure(to::CUDA.KernelAdaptor, obj::Foo)
    @ Main ~/Julia/pkg/Adapt/src/macro.jl:11
 [15] adapt
    @ ~/Julia/pkg/Adapt/src/Adapt.jl:40 [inlined]
 [16] cudaconvert
    @ ~/Julia/pkg/CUDA/src/compiler/execution.jl:198 [inlined]
 [17] map(f::typeof(cudaconvert), t::Tuple{Foo})
    @ Base ./tuple.jl:291
 [18] top-level scope
    @ ~/Julia/pkg/CUDA/src/compiler/execution.jl:110

I'm not sure it makes sense to try and convert fields that aren't parametric (because it would just convert the values back again). So either we fix this in Adapt, or we provide some convert implementation that errors early and makes the issue more clear.

FWIW, to fix the actual issue the field needs to be parametric:

julia> struct Bar{T<:AbstractArray}
       x::T
       end

julia> Adapt.@adapt_structure Bar

julia> @cuda Returns(nothing)(Bar(CUDA.rand(1)))

贡献者指南