Running on a Cluster#
A flowgraph is a set of independent tasks with declared dependencies, which is exactly the shape a job scheduler wants. Handing the nodes to a cluster instead of running them on your laptop is one option:
project.option.scheduler.set_name("slurm")
Everything else – the design, the flow, the target – is unchanged. The same script runs locally, on a cluster, or in containers.
What the schedulers are#
Value |
Runs each node |
|---|---|
(unset) |
As a process on the machine you launched from. The default. |
|
As a Slurm job. Needs a reachable |
|
In its own container – see Docker |
Note
lsf and sge are accepted by the schema but have no implementation
– only slurm and docker are dispatched. Setting either is not
silently ignored: the run fails at start-up, before any node executes, with
Unsupported scheduler 'lsf' for node <step>/<index>
The same applies when it is set on a single node
(set_name("lsf", step="route")) rather than on the whole run. If you
need one of them, say so on
Discussions;
the dispatch layer is small and the Slurm one is the template.
Important
The build directory must be on shared storage. Nodes pass results to each
other through build/, so every host that might run a node has to see the
same filesystem at the same path. This is the single most common reason a
working local build fails on a cluster.
project.option.set_builddir("/shared/scratch/me/build")
Asking for resources#
Per-node resource requests translate to the scheduler’s own switches:
project.option.scheduler.set_cores(16)
project.option.scheduler.set_memory(64000) # MB
project.option.scheduler.set_queue("bigmem") # partition
All three take step=/index=, which is usually what you want – routing
needs a different machine than linting does:
project.option.scheduler.set_cores(32, step="route")
project.option.scheduler.set_memory(128000, step="route")
Anything the accessors do not cover goes through
add_options(), which passes switches to the scheduler
verbatim.
Bounding the fan-out#
On a cluster the limit stops being your core count and starts being what you are allowed to occupy:
project.option.scheduler.set_maxnodes(50) # concurrent nodes
project.option.scheduler.set_maxthreads(8) # threads per tool
These compose with the flow’s own width. A sweep of 10 jobs, each with
syn_np=4, is 40 concurrent tool invocations before either of these applies –
see Parallel Job Execution, which is worth reading
first if you are about to point this at a shared machine.
Being told when it finishes#
A cluster run is one you walk away from:
project.option.scheduler.add_msgcontact("[email protected]")
project.option.scheduler.add_msgevent("end") # also: "begin", "timeout", "fail"
Job status emails covers what arrives.
Delaying the start#
set_defer() takes a time and passes it to Slurm as
--begin, so the job is queued but does not start until then – useful for
holding a long build until a shared machine is quiet.
Note
This does not detach the run. SiliconCompiler still waits for the job to finish, so the process stays alive for the delay and the build. There is currently no fire-and-forget submission; use your shell or the scheduler directly if you need one.
Setting up Slurm#
If you do not already have a cluster, Slurm setup walks through configuring a single machine as a one-host cluster, which is the right way to test that a script works under a scheduler before asking for real resources. Add hosts afterwards.
See also
Remote processing is the other way to run elsewhere – a SiliconCompiler server rather than a batch scheduler, and no shared filesystem on your side (the server may still need one behind it). Docker runs the tools locally without installing them.