6.27.2 Cilk

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.