Skip to content

Commit 348b2a5

Browse files
docs: Document move and move! functions (#617)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent 56e3d2c commit 348b2a5

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

docs/src/data-management.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,31 @@ VRAM, etc.) the value resides, and where the value is allowed to be transferred
2626
and dereferenced. See [Processors](@ref) and [Scopes](@ref) for more details on
2727
how these properties can be used to control scheduling behavior around `Chunk`s.
2828

29+
## Data movement rules
30+
31+
Dagger utilizes a 3-argument function `Dagger.move(from_proc::Dagger.Processor, to_proc::Dagger.Processor, x)` to manage data movement between processors. This function is invoked by the scheduler for every argument of a task, including the task's function itself, before the task is executed. The purpose of `move` is to transfer the argument `x` from its current processor (`from_proc`) to the target processor (`to_proc`) where the task will run, and to perform any necessary data conversion or unwrapping before execution.
32+
33+
This `move` mechanism is fundamental to how Dagger handles `Chunk` objects. When a `Chunk` is passed as an argument to a task, the `move` function is responsible for unwrapping the `Chunk` and providing its underlying value to the task.
34+
35+
While users can define custom `move` implementations for their specific data types if needed, the default fallback implementation of `move` is designed to handle most common use cases effectively. Therefore, custom implementations are generally unnecessary.
36+
37+
Here's an example of a custom `move` implementation:
38+
39+
```julia
40+
struct MyCustomType
41+
data::Vector{Float64}
42+
end
43+
44+
# Custom move function for MyCustomType
45+
function Dagger.move(from_proc::Dagger.Processor, to_proc::Dagger.Processor, x::MyCustomType)
46+
return x.data
47+
end
48+
49+
A = MyCustomType(rand(100))
50+
s = fetch(Dagger.@spawn sum(A))
51+
@assert s == sum(A.data)
52+
```
53+
2954
## Mutation
3055

3156
Normally, Dagger tasks should be functional and "pure": never mutating their

docs/src/datadeps.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,27 @@ for writing memory-efficient, generic algorithms in Julia).
196196
- `UpperTriangular`/`LowerTriangular`/`UnitUpperTriangular`/`UnitLowerTriangular`
197197
- `Diagonal`/`Bidiagonal`/`Tridiagonal`/`SymTridiagonal` (via `Deps`, e.g. to read from the diagonal of `X`: `Dagger.@spawn sum(Deps(X, In(Diagonal)))`)
198198
- `Symbol` for field access (via `Deps`, e.g. to write to `X.value`: `Dagger.@spawn setindex!(Deps(X, InOut(:value)), :value, 42)`
199+
200+
## In-place data movement rules
201+
202+
Datadeps uses a specialized 5-argument function, `Dagger.move!(dep_mod, from_space::Dagger.MemorySpace, to_space::Dagger.MemorySpace, from, to)`, for managing in-place data movement. This function is an in-place variant of the more general `move` function (see [Data movement rules](@ref)) and is exclusively used within the Datadeps system. The `dep_mod` argument is usually just `identity`, but it can also be an access modifier function like `UpperTriangular`, which limits what portion of the data should be read from and written to.
203+
204+
The core responsibility of `move!` is to read data from the `from` argument and write it directly into the `to` argument. This is crucial for operations that modify data in place, as often encountered in numerical computing and linear algebra.
205+
206+
The default implementation of `move!` handles `Chunk` objects by unwrapping them and then recursively calling `move!` on the underlying values. This ensures that the in-place operation is performed on the actual data.
207+
208+
Users have the option to define their own `move!` implementations for custom data types. However, this is typically not necessary for types that are subtypes of `AbstractArray`, provided that these types support the standard `Base.copyto!(to, from)` function. The default `move!` will leverage `copyto!` for such array types, enabling efficient in-place updates.
209+
210+
Here's an example of a custom `move!` implementation:
211+
212+
```julia
213+
struct MyCustomArrayWrapper{T,N}
214+
data::Array{T,N}
215+
end
216+
217+
# Custom move! function for MyCustomArrayWrapper
218+
function Dagger.move!(dep_mod::Any, from_space::Dagger.MemorySpace, to_space::Dagger.MemorySpace, from::MyCustomArrayWrapper, to::MyCustomArrayWrapper)
219+
copyto!(dep_mod(to.data), dep_mod(from.data))
220+
return
221+
end
222+
```

0 commit comments

Comments
 (0)