Skip to content

Commit b441cc7

Browse files
committed
docs: add section on ThunkOptions occupancy
1 parent 2c3fa3b commit b441cc7

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

docs/src/task-spawning.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ its result will be passed into the function receiving the argument. If the
2727
argument is *not* an [`DTask`](@ref) (instead, some other type of Julia object),
2828
it'll be passed as-is to the function `f` (with some exceptions).
2929

30+
!!! note "Task / thread occupancy"
31+
By default, `Dagger` assumes that tasks saturate the thread they are running on and does not try to schedule other tasks on the thread.
32+
This default can be controlled by specifying [`Sch.ThunkOptions`](@ref) (more details can be found under [Scheduler and Thunk options](@ref)).\
33+
The section [Changing the thread occupancy for low-utilization tasks](@ref) shows a runnable example of how to achieve this.
34+
3035
## Options
3136

3237
The [`Options`](@ref Dagger.Options) struct in the second argument position is
@@ -215,3 +220,55 @@ Dagger.spawn(+, Dagger.Options(;single=1), 1, 2)
215220

216221
delayed(+; single=1)(1, 2)
217222
```
223+
224+
### Changing the thread occupancy for low-utilization tasks
225+
226+
One of the supported [`Sch.ThunkOptions`](@ref) is the `occupancy` keyword.
227+
The basic usage looks like this:
228+
229+
```julia
230+
Dagger.@spawn occupancy=Dict(Dagger.ThreadProc=>0) fn
231+
```
232+
233+
Consider the following function definitions:
234+
235+
```@example sleep
236+
using Dagger
237+
238+
function inner()
239+
sleep(0.1)
240+
end
241+
242+
function outer_full_occupancy()
243+
@sync for _ in 1:2
244+
# By default, full occupancy is assumed
245+
Dagger.@spawn inner()
246+
end
247+
end
248+
249+
function outer_low_occupancy()
250+
@sync for _ in 1:2
251+
# Here, we're explicitly telling the scheduler to assume low occupancy
252+
Dagger.@spawn occupancy=Dict(Dagger.ThreadProc => 0) inner()
253+
end
254+
end
255+
nothing #hide
256+
```
257+
258+
When running the first outer function N times in parallel, you should see parallelization until all threads are blocked:
259+
260+
```@example sleep
261+
fetch.([Dagger.@spawn outer_full_occupancy() for _ in 1:1]); # hide
262+
for N in [1, 2, 4, 8, 16]
263+
@time fetch.([Dagger.@spawn outer_full_occupancy() for _ in 1:N])
264+
end
265+
```
266+
267+
Whereas running the outer function that communicates a low occupancy (`outer_low_occupancy`) should run fully in parallel:
268+
269+
```@example sleep
270+
fetch.([Dagger.@spawn outer_low_occupancy() for _ in 1:1]); # hide
271+
for N in [1, 2, 4, 8, 16]
272+
@time fetch.([Dagger.@spawn outer_low_occupancy() for _ in 1:N])
273+
end
274+
```

0 commit comments

Comments
 (0)