One task, many CPUs, or many tasks?
The most common resource mistake is requesting a shape that does not match the program’s execution model.
| What the command actually does | Start with |
|---|---|
| Uses one useful thread | One task and one CPU |
Creates N threads or local worker processes on one node | One task, N CPUs per task, and an explicit N-worker setting |
| Repeats independently over files, traits, seeds, chromosomes, or chunks | One manifest row per work unit and a job array |
| Needs multiple SLURM tasks, MPI, or more than one node | Application-specific ARC guidance; this is outside the playbook’s scope |
| Behavior is unclear | A representative profile plus the application’s documentation |
Serial worker
A serial R or Python script typically uses one process and one useful CPU:
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=1
Requesting eight CPUs does not cause a loop written in serial code to run eight times faster.
Threaded or local process-pool worker
A threaded application or a single-node process pool can use several CPUs inside one allocation:
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=8
The program must then be told to use eight threads or local workers. Match library limits to the allocation:
export OMP_NUM_THREADS="${SLURM_CPUS_PER_TASK:-1}"
export OPENBLAS_NUM_THREADS="$OMP_NUM_THREADS"
export MKL_NUM_THREADS="$OMP_NUM_THREADS"
export NUMEXPR_NUM_THREADS="$OMP_NUM_THREADS"
The application’s own flag—such as --threads, --cpus, or --workers—usually matters more than the environment variables. Use both only when appropriate for the software stack.
Hidden thread pools can oversubscribe a node when the job requests one CPU but BLAS, OpenMP, Java, or the application launches many threads. Explicit limits protect other users and make accounting interpretable.
Multiple SLURM tasks or nodes
MPI and other distributed applications can require several SLURM tasks or nodes. That is different from a local R/Python process pool inside one node. Use the application’s official launch guidance and understand whether srun, MPI, or a framework controls the workers.
Independent repetitions
Phenotypes, chromosomes, files, simulations, parameter combinations, and data chunks are usually not threads within one program. They are independent invocations of one worker and belong in a job array.
A good worker contract is:
one task ID + explicit inputs → one deterministic output + one exit code
How to verify behavior
- Check the program’s documentation and help output for thread or worker options.
- Run a representative job inside an interactive allocation.
- Inspect process/thread activity with tools such as
htopwhen permitted. - Compare
TotalCPUwith elapsed time and allocated CPUs after completion. - Confirm that changing the thread setting changes performance before requesting more CPUs.
Low CPU efficiency does not always mean “use fewer CPUs.” A process may be waiting on shared storage. Inspect I/O patterns and logs before changing the request.