Gforth’s Cilk is a framework for dividing work between multiple tasks
running on several cores, inspired by the programming language of the
same name. Use require cilk.fs
if you want to use Cilk.
The idea is that you identify subproblems that can be solved in
parallel, and the framework assigns worker tasks to these subproblems.
In particular, you use one of the spawn
words for each subtask.
Eventually you need to wait with cilk-sync
for the subproblems
to be solved.
Currently all the spawning has to happen from one task, and
cilk-sync
waits for all subproblems to complete, so using the
current Gforth Cilk for recursive algorithms is not straightforward.
Do not divide the subproblems too finely, in order to avoid overhead;
how fine is too fine depends on how uniform the run-time for the
subproblems is, but for problems with substantial run-time, having
5*cores
subproblems is probably a good starting point.
cores
( – u ) cilk “cores”
A value containing the number of worker tasks to use. By default
this is the number of hardware threads (with SMT/HT), if we can
determine that, otherwise 1. If you want to use a different
number, change cores
before calling cilk-init
.
cilk-init
( – ) cilk “cilk-init”
Start the worker tasks if not already done.
spawn
( xt – ) cilk “spawn”
Execute xt ( – ) in a worker task.
Use one-time executable closures to pass heap-allocated closures,
allowing to pass arbitrary data from the spawner to the code
running in the worker.
E.g.: ( n r ) [{: n f: r :}h1 code ;] spawn
spawn1
( x xt – ) cilk “spawn1”
Execute xt ( x – ) in a worker task.
spawn2
( x1 x2 xt – ) cilk “spawn2”
Execute xt ( x1 x2 – ) in a worker task.
cilk-sync
( – ) cilk “cilk-sync”
Wait for all subproblems to complete.
cilk-bye
( – ) cilk “cilk-bye”
Terminate all workers.