Hi,
I am looking for the best way to use structs inside the kernels and I am having hard time with understanding whole mutable/immutable/isbits/inline thing. My goal is to be able to pass struct as an argument to a kernel and be able modify it.
At first my struct looked like that:
mutable struct MyStruct
a :: CuArray{Float64}
b :: Int64
end
and when I wanted to modify it inside the kernel I just did:
s = MyStruct(CUDA.rand(1,100), 20)
@cuda threads=10 kernel(s.a, s.b)
As my original structure is much more complicated and have lots of field then I started wondering if I could maybe pass whole structure to a kernel without unpacking it to separate arguments.
So I created adaptor and modified struct definition accordingly:
Adapt.adapt_structure(to, s::MyStruct) = MyStruct(adapt(to, s.a), s.b)
mutable struct MyStruct{T}
a :: T
b :: Int64
end
I incorrectly assumed that MyStruct would be bits type once all its fields are (after conversion of CuArray to CuDeviceArray). But then I found out that once the struct is mutable it can’t be bitstype even in such a situtation.
This won’t be a big problem if I would modify only field a (CuArray) inside the kernel (as it is possible). Then I would just change structure to immutable:
struct MyStruct{T}
a :: T
b :: Int64
end
but I also need to modify the Integer value, which throws an error because immutable struct cannot be changed.
I had some ideas how to workaround it:
- replace all the immutable types with one-element CuArrays - it works but from my perspective looks horrible and accessing it like:
s.b[1]
requires scalar indexing… - using
b :: Base.RefValue{Int}
in struct definition (and thens.b[] = 5
for value change) which works for replacing values in immutable struct but is not bits type so it makes the structure non isbits. - using Setfield.jl which seems not to work inside kernel (although it doesn’t throw an error)
I read this topic and I think that I understood why the things with mutable/immutable structs are like that. But from my perspective and current knowledge I think that I am missing something, especially in context of CUDA.jl. For know I don’t see any possibility to pass the struct to the kernel and be able to modify all its fields. Structure passed can not be mutable as it is not isbits (which is understandable regarding the arrangement of data in it - and also we could not change it, by design), it has to be immutable (to force proper arrangement of data in memory). But then it will protect all its immutable fields (and at the same time we can modify fields which are CuArrays, because these are mutable). So basically I have to sacrifice the possibility to change my Integer field in order to be able to even pass the structure to the kernel, which seems unnecessary.
Or maybe there is some solution to this? I would be glad to find out or at least understand why it has to be like that