Skip to content

Your first real job

This guide picks up where the Quick Start left off. You already have an account, can connect via SSH, and have submitted a simple "hello world" job. Now we will walk through a more realistic workflow: understanding what each directive does, submitting a real computation, and learning how to check and improve your resource requests.

1. Prepare your workspace

All job I/O should happen on /scratch. Move there and create a directory for this tutorial:

cd /scratch/$USER
mkdir first-job && cd first-job

2. Write a batch script

Create a file called matrix.slurm with the following content:

matrix.slurm
#!/bin/bash
#SBATCH --job-name=matrix
#SBATCH --partition=general
#SBATCH --qos=test
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=4
#SBATCH --mem=4gb
#SBATCH --time=00:05:00
#SBATCH --output=%x.%j.out
#SBATCH --error=%x.%j.err

echo "Job started on $(hostname) at $(date)"

# Load Python (the system python does not include numpy)
module load Miniforge3

# Generate a random matrix and compute its eigenvalues
python3 -c "
import numpy as np
n = 2000
A = np.random.rand(n, n)
vals = np.linalg.eigvals(A)
print(f'Computed {len(vals)} eigenvalues of a {n}x{n} matrix')
print(f'Largest eigenvalue (magnitude): {np.max(np.abs(vals)):.4f}')
"

echo "Job finished at $(date)"

What each directive means

Directive What it does
--job-name=matrix A human-readable name; appears in squeue and in output filenames
--partition=general The pool of nodes to use (default on all clusters)
--qos=test Quality of Service: test allows short jobs (max 10 min) with high priority, ideal for testing
--nodes=1 Number of physical nodes
--ntasks=1 Number of independent processes (MPI ranks). 1 for serial or pure OpenMP jobs
--cpus-per-task=4 CPU cores assigned to each task. Useful for multithreaded programs
--mem=4gb Total memory for the job. Overestimate at first, then refine
--time=00:05:00 Maximum walltime. The job is killed if it exceeds this
--output=%x.%j.out Stdout file. %x = job name, %j = job ID
--error=%x.%j.err Stderr file

Choosing a QoS

Use test while developing and debugging your scripts. Once your job works correctly, switch to regular, long, or xlong depending on how much time you need. See Partitions and QoS for limits.

3. Submit and monitor

Submit the job:

sbatch matrix.slurm
Submitted batch job 123456

Check its status:

squeue -u $USER
JOBID   PARTITION   NAME     USER     ST  TIME  NODES  NODELIST
123456  general     matrix   username  R  0:02  1      hyperion-101

The ST column shows the state: PD (pending, waiting for resources) or R (running).

4. Check the results

Once the job finishes, it disappears from squeue. View the output:

cat matrix.*.out
Job started on hyperion-101 at Thu Mar  7 10:00:00 CET 2026
Computed 2000 eigenvalues of a 2000x2000 matrix
Largest eigenvalue (magnitude): 1000.1234
Job finished at Thu Mar  7 10:00:12 CET 2026

If something went wrong, check the error file:

cat matrix.*.err

5. Evaluate efficiency

After a job completes, use seff to see how well your resource requests matched actual usage:

seff 123456
Job ID: 123456
State: COMPLETED
Cores: 4
CPU Utilized: 00:00:10
CPU Efficiency: 41.7% of 00:00:24 core-walltime
Memory Utilized: 312.00 MB
Memory Efficiency: 7.6% of 4.00 GB

Understanding the numbers

CPU Efficiency is the ratio of actual CPU time used to the total CPU time allocated. In this example, the job requested 4 cores for ~6 seconds of walltime, so the total allocation was 4 x 6 = 24 core-seconds. The program only used 10 core-seconds of that, hence 41.7%. This is normal for a short numpy script that does not fully parallelize across all cores.

Memory Efficiency is the ratio of peak memory used to the memory requested. Here, the job used 312 MB out of 4 GB (7.6%), meaning the request was far too generous.

What is a good efficiency?

There is no universal threshold, but as a rule of thumb:

Metric Good Worth investigating
CPU Efficiency > 70% < 50% consistently
Memory Efficiency > 30% < 10% consistently

Low efficiency on a single short test run is not a problem. But if your production jobs consistently show low efficiency, you are wasting resources and waiting longer in the queue than necessary.

What to do

If you see... Try...
Low CPU efficiency with multiple cores Reduce --cpus-per-task. Your program may not use all the cores you requested
Low memory efficiency Reduce --mem. In this example, --mem=1gb would be more than enough
High memory efficiency (> 90%) Increase --mem slightly to avoid being killed by the OOM killer
CPU efficiency > 100% This can happen with hyperthreading; it is not a problem

Why this matters

Requesting more resources than you need does not make your job faster. It makes it wait longer in the queue (fewer nodes can satisfy the request) and blocks resources for other users. Always check seff on your first runs and adjust.

6. Iterate and scale up

Now that you have a working, tested script:

  1. Switch to a production QoS: replace --qos=test with --qos=regular (or long/xlong for longer jobs).
  2. Adjust resources based on seff output.
  3. Load your real software with module load (see Environment modules).
  4. Replace the python example with your actual computation.

For common job patterns (MPI, OpenMP, hybrid, GPU), see the ready-made job templates.

What's next

  • SLURM reference


    Full reference: all directives, templates, job arrays, dependencies, and more.

    SLURM

  • Batch script generator


    Build a batch script interactively by selecting your resources.

    Generator

  • GPU jobs


    How to request and use GPUs on Hyperion and Atlas EDR.

    GPU accelerators

  • Environment modules


    Load pre-installed software (compilers, libraries, applications).

    Modules

  • Scientific software


    Application-specific guides (VASP, GROMACS, Gaussian, PyTorch, etc.).

    Catalog