# Converting entire custom structure from cpu to gpu and viceversa

**URL:** <https://discourse.julialang.org/t/converting-entire-custom-structure-from-cpu-to-gpu-and-viceversa/93203>\
**Category:** GPU\
**Tags:** convert, adapt\
**Created:** [January 19, 2023, 10:25am UTC](https://discourse.julialang.org/t/converting-entire-custom-structure-from-cpu-to-gpu-and-viceversa/93203 "2023-01-19T10:25:36Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![carlogalli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carlogalli/32/7948_2.png) [@carlogalli](https://discourse.julialang.org/u/carlogalli)\
**Post date:** [January 19, 2023, 10:25am UTC](https://discourse.julialang.org/t/converting-entire-custom-structure-from-cpu-to-gpu-and-viceversa/93203/1 "2023-01-19T10:25:36Z")

</div>

Hi!

I am looking for a good way to convert a custom structure of Arrays to CuArrays and viceversa. I suspect the answer is related to them and to [this topic](https://discourse.julialang.org/t/passing-mutable-struct-to-kernel/71948), but I am not well versed in the usage of `convert` and `adapt` so I don’t really understand what I should do.

In my code, I have the following custom structure where `A` is either `Array` or `CuArray`

```julia
struct MyStruct{A}
    x::A
    y::A
end

```

I first create a GPU version of it

```julia
n = 3
a_gpu = CUDA.rand(n)
b_gpu = CUDA.rand(n)
MS_gpu = MyStruct(a_gpu, b_gpu)

```

and then perform operations with this on the GPU (thank you for `CUDA.jl`, it’s amazing!).

But then I need to perform operations with scalar indexing on these objects, so my understanding is that it is more efficient to “bring” the structure to the CPU for that. What I currently do is the following.

First I create a CPU version

```julia
a_cpu = zeros(n)
b_cpu = zeros(n)
MS_cpu = MyStruct(a_cpu, b_cpu)

```

Then I created the following function (my structures are various and larger, so it made sense to have a somewhat automated way to do this)

```julia
function convert_to_cpu!(struct_gpu::T_gpu, struct_cpu::T_cpu) where {T_gpu<:MyStruct, T_cpu<:MyStruct}
    names = fieldnames(T_gpu)
    types_cpu = fieldtypes(T_cpu)

    for i in 1:lastindex(names)
        getfield(struct_cpu, names[i]) .= convert(types_cpu[i], getfield(struct_gpu, names[i]))
    end
    return nothing
end

```

and use it to copy the GPU stuff into the CPU structure

```julia
convert_to_cpu!(MS_gpu, MS_cpu)

```

I do get the desired final result, which is to have a structure of normal `Array`s on the CPU with the values I calculated on the GPU, but I am not sure this is the proper way to do it.

PS: I marked the topic as GPU domain but I suppose this question has a much more general answer, apologies for that!

---

<div class="post-metadata">

**Author:** ![mtfishman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mtfishman/32/30755_2.png) [@mtfishman](https://discourse.julialang.org/u/mtfishman)\
**Post date:** [January 19, 2023, 2:24pm UTC](https://discourse.julialang.org/t/converting-entire-custom-structure-from-cpu-to-gpu-and-viceversa/93203/2 "2023-01-19T14:24:41Z")

</div>

You should be able to use `Adapt.jl` for this, it should be sufficient to define an overload of `Adapt.adapt_structure` for you custom struct as described in the README and docstring of `Adapt.adapt`, or use the macro `Adapt.@adapt_structure MyStruct` which will do the same thing automatically. Then you can use `adapt(CuArray, MS_cpu)` or `adapt(Array, MS_gpu)` to transfer your object back and forth between CPU and GPU.

---

<div class="post-metadata">

**Author:** ![carlogalli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carlogalli/32/7948_2.png) [@carlogalli](https://discourse.julialang.org/u/carlogalli)\
**Post date:** [January 19, 2023, 2:40pm UTC](https://discourse.julialang.org/t/converting-entire-custom-structure-from-cpu-to-gpu-and-viceversa/93203/3 "2023-01-19T14:40:56Z")

</div>

Thank you, it works!

I had seen the documentation of `Adapt.adapt` but had never understood that `to` had to be replaced by a type and would just work out of the box.

Indeed, I defined

```julia
function Adapt.adapt_structure(to, MS::MyStruct)
    x = adapt(to, MS.x)
    y = adapt(to, MS.y)
    return MyStruct(x, y)
end

```

and now the commands `adapt(CuArray, MS_cpu)` and `adapt(Array, MS_gpu)` do precisely what I was after.
