SLURM workload manager¶
SLURM is the job scheduler and resource manager on all DIPC clusters. You write a batch script describing what resources you need and what to run, submit it with sbatch, and SLURM queues it until resources are available.
Batch scripts¶
A batch script is a shell script with #SBATCH directives that tell SLURM what resources to allocate. Here is a minimal example:
#!/bin/bash
#SBATCH --job-name=my_job
#SBATCH --partition=general
#SBATCH --qos=regular
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=1
#SBATCH --mem=4gb
#SBATCH --time=01:00:00
#SBATCH --output=%x.%j.out
#SBATCH --error=%x.%j.err
module load some_software/1.0
srun ./my_program < input.dat
Each #SBATCH line is a resource directive. SLURM reads them before executing the script body.
Common directives¶
| Directive | Example | Description |
|---|---|---|
--partition |
--partition=general |
Node pool to submit to (default: general) |
--qos |
--qos=regular |
Quality of Service (see below) |
--nodes |
--nodes=2 |
Number of nodes |
--ntasks |
--ntasks=8 |
Total number of tasks (MPI processes) |
--ntasks-per-node |
--ntasks-per-node=4 |
Tasks per node |
--cpus-per-task |
--cpus-per-task=8 |
CPU cores per task (OpenMP threads) |
--mem |
--mem=32gb |
Memory per node |
--mem-per-cpu |
--mem-per-cpu=4gb |
Memory per CPU core |
--time |
--time=1-00:00:00 |
Walltime limit (D-HH:MM:SS) |
--gres |
--gres=gpu:2 |
Generic resources (e.g. GPUs) |
--job-name |
--job-name=simulation |
Job name |
--output |
--output=%x.%j.out |
File for stdout (%x = job name, %j = job ID) |
--error |
--error=%x.%j.err |
File for stderr |
--mail-user |
--mail-user=you@dipc.org |
Email for notifications |
--mail-type |
--mail-type=END,FAIL |
When to send email (BEGIN, END, FAIL, ALL) |
Estimating resources
If you do not know how much memory or time your jobs need, overestimate on the first runs and then use seff <jobid> on completed jobs to see actual usage. Tighten your requests accordingly (smaller requests get scheduled faster).
Submitting and running jobs¶
sbatch - batch submission¶
Submit a script to the queue:
sbatch my_script.slurm
Submitted batch job 123456
The job runs asynchronously. Output goes to the files specified with --output and --error (or slurm-<jobid>.out by default).
Environment propagation
By default, all environment variables from your shell are propagated to the job. To prevent unexpected behavior, add #SBATCH --export=NONE to your script and explicitly load modules inside it.
salloc interactive allocation¶
Request resources without a batch script. SLURM grants an allocation and drops you into a subshell:
$ salloc --qos=test --nodes=1 --mem=20gb --time=00:10:00
salloc: Granted job allocation 1999
$ srun hostname
hyperion-125
$ exit
salloc: Relinquishing job allocation 1999
To get a shell directly on the compute node, append srun --pty bash:
$ salloc --qos=test --time=00:10:00 srun --pty bash
salloc: Granted job allocation 1477543
salloc: Nodes hyperion-125 are ready for job
user@hyperion-125:~$
Info
With srun --pty bash, logging out from the compute node terminates the job. If you connect manually via SSH instead, the allocation persists after you disconnect from the node.
srun - direct execution¶
Run a command on allocated resources. Useful for quick tests:
$ srun --qos=test --mem=1gb --time=00:05:00 bash -c 'echo "Hello from $(hostname)"'
Hello from atlas-281
srun blocks until the command finishes. If your terminal disconnects, the job ends. For anything longer than a quick test, wrap srun in a batch script and use sbatch.
Within a batch script, srun is used to launch your program on the allocated resources. It automatically inherits the resource allocation from the #SBATCH directives.
Partitions and QoS¶
Each cluster organizes nodes into partitions and associates them with Quality of Service levels (QoS) that set limits on walltime, node count, and running jobs.
Partitions:
| Partition | Description |
|---|---|
general (default) |
All publicly available nodes |
preemption |
Nodes owned by specific groups, publicly available with restrictions |
preemption-gpu |
A100 SXM4 nodes for small GPU jobs, preemptible |
QoS for general and preemption partitions:
QoS |
Priority | Max walltime | Max nodes/user | Max running jobs/user | Max submitted | Max TRES |
|---|---|---|---|---|---|---|
regular (default) |
200 | 1 day | 60 | 180 | ||
test |
1000 | 10 min | 2 | 2 | 2 | |
long |
200 | 2 days | 25 | 40 | ||
xlong |
200 | 8 days | 20 | 20 | 200 | |
serial |
200 | 2 days | 1000 | 2000 | CPUs=1, GPUs=0, nodes=1 |
QoS for preemption-gpu partition:
| QoS | Priority | Max walltime | Max TRES |
|---|---|---|---|
preemption-gpu (default) |
200 | 8 days | GPUs=3, nodes=1 |
Global submission limit
A global limit of 1000 submitted jobs applies across all QoSs (sum of all queued and running jobs). The serial QoS is an exception, allowing up to 2000.
Info
Do not specify QoSs from the general partition when submitting to preemption-gpu. Use the partition's default QoS.
Atlas EDR and Atlas FDR share a single SLURM instance: same partitions, same QoS limits. The key differences are:
- Nodes: Jobs submitted from Atlas EDR login nodes run exclusively on EDR compute nodes, and jobs from Atlas FDR login nodes run on FDR compute nodes.
- Storage: Each cluster has its own
/scratchfilesystem. - Software: The available module stack differs between EDR and FDR (see Atlas EDR and Atlas FDR).
- GPUs: Only Atlas EDR has GPU nodes. Atlas FDR has no GPUs.
- MPI launcher: On Atlas FDR, use
mpiruninstead ofsrunto launch MPI programs (see MPI template note below).
Partitions:
| Partition | Description |
|---|---|
general (default) |
All publicly available nodes |
preemption |
Nodes owned by specific groups, publicly available with restrictions |
QoS:
| QoS | Priority | Max walltime | Max nodes/user | Max running jobs/user | Max submitted | Max TRES |
|---|---|---|---|---|---|---|
regular (default) |
200 | 1 day | 24 | 50 | ||
test |
1000 | 10 min | 2 | 2 | 2 | |
long |
200 | 2 days | 24 | 20 | ||
xlong |
200 | 8 days | 12 | 10 | ||
serial |
200 | 2 days | 500 | cpu=1, gpu=1, node=1 |
Tip
If your jobs require longer execution times or more nodes than these limits allow, contact support-hpc@dipc.org. Limits can be adjusted and custom QoS/partitions can be temporarily created.
The preemption partition¶
All clusters have a preemption partition containing nodes owned by specific research groups. These nodes are often idle and are made available to all users, with one condition: if the owner group submits a job that needs its nodes, preemption jobs running on those nodes will be canceled and requeued.
The submission procedure is:
#SBATCH --partition=preemption
#SBATCH --qos=regular # use any QoS from the general partition
Design preemption-safe jobs
Jobs on the preemption partition can be killed and restarted at any time. If your code does not save checkpoints, it will start from scratch. See the requeuing policy section.
Job templates¶
These templates work on all clusters unless noted otherwise. Adjust --ntasks-per-node and --cpus-per-task to match the core count of your target nodes (see the specifications page of each cluster).
Where to run
Submit jobs from and direct output to your /scratch directory.
MPI¶
#!/bin/bash
#SBATCH --qos=regular
#SBATCH --job-name=mpi_job
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=48
#SBATCH --cpus-per-task=1
#SBATCH --mem=200gb
#SBATCH --time=1-00:00:00
#SBATCH --output=%x.%j.out
#SBATCH --error=%x.%j.err
module load program/version
srun ./binary < input
This runs 96 MPI processes (2 nodes x 48 tasks/node). srun handles process placement and inherits the SLURM allocation automatically.
Atlas FDR: use mpirun instead of srun
Atlas FDR does not have full SLURM-MPI integration. On this cluster, replace the srun line with:
mpirun -np ${SLURM_NTASKS} ./binary < input
This applies to all MPI jobs on Atlas FDR, including hybrid MPI+OpenMP. On Hyperion and Atlas EDR, always prefer srun.
For more details on MPI compilation and execution, see MPI.
OpenMP¶
#!/bin/bash
#SBATCH --qos=regular
#SBATCH --job-name=omp_job
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=48
#SBATCH --mem=200gb
#SBATCH --time=1-00:00:00
#SBATCH --output=%x.%j.out
#SBATCH --error=%x.%j.err
module load program/version
export OMP_NUM_THREADS=${SLURM_CPUS_PER_TASK}
srun ./binary < input
Always set OMP_NUM_THREADS from SLURM_CPUS_PER_TASK to ensure the thread count matches the allocation. See OpenMP for thread affinity and tuning.
Hybrid MPI + OpenMP¶
#!/bin/bash
#SBATCH --qos=regular
#SBATCH --job-name=hybrid_job
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=4
#SBATCH --cpus-per-task=12
#SBATCH --mem=200gb
#SBATCH --time=1-00:00:00
#SBATCH --output=%x.%j.out
#SBATCH --error=%x.%j.err
module load program/version
export OMP_NUM_THREADS=${SLURM_CPUS_PER_TASK}
srun ./binary < input
This runs 8 MPI processes (4 per node), each with 12 OpenMP threads, using 48 cores per node total. On Atlas FDR, replace srun with mpirun -np ${SLURM_NTASKS} (see MPI note above). See MPI: Hybrid MPI+OpenMP for details.
GPU¶
GPU request syntax differs between clusters. Atlas FDR has no GPUs. For a complete guide including available hardware, constraints, and multi-GPU training, see GPU accelerators.
#!/bin/bash
#SBATCH --qos=regular
#SBATCH --job-name=gpu_job
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=8
#SBATCH --gres=gpu:1
#SBATCH --constraint=rtx3090
#SBATCH --mem=32gb
#SBATCH --time=04:00:00
#SBATCH --output=%x.%j.out
#SBATCH --error=%x.%j.err
module load CUDA/12.4.0
srun ./my_gpu_program
On Hyperion, use --gres=gpu:N for the number of GPUs and --constraint to select the type (rtx3090, a100-sxm4, a100-pcie, a6000).
#!/bin/bash
#SBATCH --qos=regular
#SBATCH --job-name=gpu_job
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=4
#SBATCH --gres=gpu:p40:1
#SBATCH --mem=32gb
#SBATCH --time=04:00:00
#SBATCH --output=%x.%j.out
#SBATCH --error=%x.%j.err
module load CUDA/11.7.0
srun ./my_gpu_program
On Atlas EDR, the GPU type goes directly in the --gres flag: --gres=gpu:p40:1 or --gres=gpu:rtx3090:2.
Node selection¶
Hyperion: microarchitecture constraints¶
Hyperion has three CPU microarchitectures. By default, SLURM ensures all nodes in a job share the same architecture (no mixing), but you can request a specific one:
#SBATCH --constraint=icelake
#SBATCH --constraint=cascadelake
#SBATCH --constraint=emerald
This constraint works with sbatch, srun, and salloc. Requesting a GPU type via --constraint implicitly selects the CPU architecture of those nodes. See GPU accelerators: GPU and CPU microarchitecture for the mapping.
Atlas EDR and Atlas FDR¶
These clusters have homogeneous CPU architectures within each cluster, so no microarchitecture constraint is needed. See the Atlas EDR specifications and Atlas FDR specifications for node details.
Job arrays¶
Job arrays submit multiple instances of the same job, each with a unique index. They are ideal when you need to run the same computation on many different inputs. See the Job arrays page for a full guide with practical examples.
Dependency chains¶
Start a job only after another job reaches a certain state:
$ sbatch first_job.slurm
Submitted batch job 1000
$ sbatch --dependency=afterok:1000 second_job.slurm
Submitted batch job 1001
Available dependency types:
| Dependency | Behavior |
|---|---|
after:jobid |
Start after jobid begins execution |
afterany:jobid |
Start after jobid terminates (any exit status) |
afterok:jobid |
Start after jobid completes successfully |
afternotok:jobid |
Start after jobid fails (non-zero exit) |
singleton |
Start after any previous job with the same name and user terminates |
The singleton dependency is useful for chaining restartable jobs: submit the same script multiple times and each instance waits for the previous one to finish.
Managing jobs¶
squeue - view the queue¶
# All your jobs
squeue -u $USER
# Only running jobs
squeue -u $USER -t RUNNING
# Only pending jobs
squeue -u $USER -t PENDING
# Jobs in a specific partition
squeue -u $USER -p preemption
scancel - cancel jobs¶
# Cancel a specific job
scancel 123456
# Cancel all your jobs
scancel -u $USER
# Cancel all your pending jobs
scancel -t PENDING -u $USER
sacct - job accounting (completed jobs)¶
After a job finishes, sacct shows what actually happened:
sacct -j 123456 --format=JobID,JobName,MaxRSS,Elapsed,State,NodeList
sstat - live job statistics¶
For a currently running job:
sstat --format=JobID,AveCPU,AveRSS,MaxRSS -j 123456
seff - efficiency report¶
Quick summary of CPU and memory efficiency for a completed job:
$ seff 123456
Job ID: 123456
State: COMPLETED
Cores: 48
CPU Utilized: 12:34:56
CPU Efficiency: 87.5%
Memory Utilized: 24.5 GB
Memory Efficiency: 51.0% of 48.00 GB
Tip
Run seff on your completed jobs regularly. If CPU efficiency is consistently low, you may be requesting too many cores. If memory efficiency is very low, reduce --mem to let your jobs schedule faster.
Warning
seff numbers are only meaningful for successfully completed jobs. Do not use them for running or failed jobs.
Local scratch for I/O-intensive jobs¶
Every compute node has a local disk mounted at /lscratch. It is faster than the shared /scratch filesystem because I/O does not travel over the network. Use it when your job reads or writes many small files (e.g., molecular dynamics restarts, image datasets, temporary databases).
The pattern is simple: copy your input to /lscratch at the start of the job, run there, and copy the results back to /scratch at the end.
#!/bin/bash
#SBATCH --qos=regular
#SBATCH --job-name=io_job
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=8
#SBATCH --mem=16gb
#SBATCH --time=06:00:00
#SBATCH --output=%x.%j.out
#SBATCH --error=%x.%j.err
WORKDIR=/lscratch/${USER}/${SLURM_JOB_ID}
mkdir -p ${WORKDIR}
# Copy input data to local disk
cp /scratch/${USER}/project/input.dat ${WORKDIR}/
# Run from local disk
cd ${WORKDIR}
srun ./my_program < input.dat
# Copy results back to shared storage
cp ${WORKDIR}/output.dat /scratch/${USER}/project/
# Clean up
rm -rf ${WORKDIR}
Warning
/lscratch is local to each node and is not shared between nodes. Do not use it for multi-node MPI jobs that need shared file access. Also, if your job is killed (timeout, preemption, node failure), the cleanup step will not run and files on /lscratch will remain until the next reboot.
Tip
Use $SLURM_JOB_ID in the directory name to avoid collisions if multiple jobs run on the same node.
Requeuing policy¶
If a node fails (freeze, reboot, memory error), SLURM will attempt to requeue your job by default. This is useful for checkpoint-based workflows but dangerous otherwise, because the restarted job will overwrite output files.
To prevent automatic requeuing:
#SBATCH --no-requeue
Warning
Add #SBATCH --no-requeue to your batch scripts unless your code is specifically designed to resume from checkpoints.
SLURM environment variables¶
These variables are available inside your batch script at runtime:
| Variable | Description |
|---|---|
SLURM_JOB_ID |
Job ID |
SLURM_JOB_NAME |
Job name |
SLURM_SUBMIT_DIR |
Directory from which the job was submitted |
SLURM_JOB_NODELIST |
List of nodes assigned to the job |
SLURM_NNODES |
Number of nodes |
SLURM_NTASKS |
Total number of tasks |
SLURM_CPUS_PER_TASK |
CPUs per task |
SLURM_ARRAY_JOB_ID |
Job array parent ID |
SLURM_ARRAY_TASK_ID |
Job array task index |
Use these to make your scripts portable. For example, export OMP_NUM_THREADS=${SLURM_CPUS_PER_TASK} ensures your thread count always matches the allocation regardless of what you requested.
Job states¶
| State | Meaning |
|---|---|
| PENDING | Waiting in queue for resources |
| RUNNING | Executing on compute nodes |
| COMPLETED | Finished successfully (exit code 0) |
| FAILED | Terminated with non-zero exit code |
| TIMEOUT | Exceeded the walltime limit |
| CANCELLED | Cancelled by user or administrator |
| NODE_FAIL | Terminated due to a node failure |
| PREEMPTED | Terminated because a higher-priority job needed the resources |
Troubleshooting¶
My job has been PENDING for a long time
Check why SLURM is holding your job:
squeue -j <jobid> -o "%.18i %.30j %.10R"
The NODELIST(REASON) column shows the cause. Common reasons:
| Reason | What it means | What to do |
|---|---|---|
Priority |
Other jobs have higher priority (fair-share). See Job priority and scheduling for how this is computed | Wait; your priority increases over time |
Resources |
Not enough free nodes/cores/memory right now | Wait, or reduce your request |
ReqNodeNotAvail |
A node you requested (or that matches your constraints) is unavailable, e.g. in DRAIN for maintenance |
Wait; SLURM picks the job up once the node returns. If the cluster looks free but the reason persists, see the reason looks stuck below |
QOSMaxJobsPerUserLimit |
You hit the max running jobs for this QoS | Wait for running jobs to finish |
QOSMaxNodePerUserLimit |
You are using the max nodes allowed | Wait or reduce --nodes |
The reason reflects the last scheduling cycle in which SLURM evaluated your job, not a live state. If it appears to disagree with the current state of the cluster, see the next entry.
If the reason is Resources and the cluster is not particularly busy, your request may be too large for any single node. For example, requesting 256 GB of memory on nodes that have 192 GB will never schedule.
The reason in squeue looks stuck or outdated
The reason field shown by squeue is not real-time state. SLURM records it the last time it evaluated your job during a scheduling cycle, and refreshes it only the next time the scheduler looks at that specific job. Until then the field keeps the old reason, even if the underlying condition (e.g. a node in DRAIN for maintenance, a busy partition) is no longer in effect. The Slurm documentation makes this explicit: the field reports "the reason that was encountered by the attempted scheduling method" (squeue man page, JOB REASON CODES section).
All pending jobs remain in the queue and are continuously considered every scheduling cycle, regardless of what the reason reads. The field is descriptive, not prescriptive: it does not hold your job back.
To check the actual state of the nodes you requested:
scontrol show node <nodename> | grep State
sinfo -N -o "%N %T"
<nodename> accepts ranges, e.g. hyperion-[252-254,257].
Common base states:
| State | Allows new jobs? | Notes |
|---|---|---|
IDLE |
Yes | No jobs running |
MIXED |
Yes | Some CPUs in use, others free |
ALLOCATED |
Yes (when CPUs free up) | All listed CPUs already in use |
COMPLETING |
No (transient) | Jobs finishing; will become IDLE or MIXED shortly |
DRAIN, DRAINING, DRAINED |
No | Reserved for maintenance or admin action |
DOWN, FAIL, NOT_RESPONDING |
No | Node is unhealthy or offline |
RESERVED |
Only matching reservations | Held for an advance reservation |
A node in MIXED or ALLOCATED is not blocked: it simply has work on it. SLURM will start your job there as soon as enough resources free up, in the order set by priority and backfill. You may also see flags appended such as +PLANNED (the node is being held for a higher-priority job; backfill can still place yours there if it fits in the gap) or +RESERVED.
If the reason still looks stale and you would like it refreshed sooner, contact us at support-hpc@dipc.org with the job ID; we can nudge the scheduler to re-evaluate it.
My job failed immediately with exit code 1
Check the error file (<jobname>.<jobid>.err) for the actual error. Common causes:
- Module not found: the software is not available on this cluster or the version string is wrong. Run
module spider <name>to check. - File not found: input files are not where the script expects them. Remember that the job runs from
$SLURM_SUBMIT_DIR(the directory where you ransbatch). - Permission denied: you may be trying to write to a read-only filesystem. On Atlas,
/dipcis not accessible from compute nodes.
My job was killed with signal 9 (exit code 137)
The job exceeded its memory allocation and was killed by the kernel (OOM killer). Increase --mem or --mem-per-cpu and resubmit. Use sacct -j <jobid> --format=JobID,MaxRSS,State to see how much memory was actually used before the kill.
SLURM rejects my job with 'Invalid account'
Your user account is not associated with a SLURM account on this cluster. Contact support-hpc@dipc.org with your username and the cluster name.
See also¶
-
GPU accelerators
GPU hardware inventory and SLURM mechanics per cluster.
-
PyTorch distributed training
Distributed deep learning with PyTorch.
-
MPI
Compiling and running MPI applications.
-
OpenMP
Threading and affinity.
-
Compilers
Available compilers and optimization flags.