All in One View

Content from What a supercomputer is


Last updated on 2026-10-26 | Edit this page

Overview

Questions

  • What is different about a supercomputer and the computer on your desk?
  • How do you log in to Snellius, and how is the course cluster different?

Objectives

  • Describe a supercomputer as a login node, a scheduler, and compute nodes.
  • Identify a login hostname and a compute hostname from a written example.
  • Connect to Snellius with SSH after the SURF user portal step.
  • Connect to the course cluster with the address in your welcome note.
  • Predict what a long computation does to a shared login node.

A room of computers, with a door


A supercomputer is not a bigger laptop. It is many computers in one room. They share a door, a queue, and file systems. You talk to the door. A scheduler decides when your work may run on a computer in the room.

You will meet three roles.

  • The login node is the door. You reach it with SSH, or with a web shell. It is shared with everyone else who is logged in. It is the right place to edit a script, look at a small file, and submit a job. It is the wrong place to run the job.
  • The scheduler is the queue. On Snellius and on the course cluster the scheduler is Slurm. You describe the resources you need. Slurm starts the work when those resources are free.
  • A compute node is where the work runs. You do not SSH there for a normal batch job. Slurm starts your script on that node and writes the text output to a file.
How a job moves. The nodes drawn are laptop, login node, scheduler, and compute node.
How a job moves. The nodes drawn are laptop, login node, scheduler, and compute node.

Snellius


Snellius is the Dutch national supercomputer, operated by SURF. The public description is at https://www.surf.nl/en/services/compute/snellius-the-national-supercomputer. Before the first SSH login you sign in to the SURF user portal, CUA. The account email comes from SURF and names your login.

From your own computer:

BASH

ssh YOUR_LOGIN@snellius.surf.nl

Your prompt is on a login node. It looks like YOUR_LOGIN@int4:~$. The int names are login nodes. A compute node has a different name. If the network you are on is not trusted, SURF documents a separate door node in the service desk. Use that host when the welcome mail tells you to.

You can also work in a browser through Open OnDemand. That page gives you a shell, a file manager, and a few applications. The shell is still a login node.

Callout

A password prompt on the login node is normal. A job does not start because you logged in. Logging in only gives you the door.

The course cluster


This course also uses a small cluster built from SURF Research Cloud workspaces. The template is Magic Castle: https://github.com/ComputeCanada/magic_castle. Your trainer sends a setup link. That link creates your password. There is one login node, and there is no CUA account.

BASH

ssh YOUR_LOGIN@MANAGER

MANAGER is the address in the welcome note. It is not snellius.surf.nl. The nodes have two cores each, with more cores on the GPU node. Ethernet stands in for the fast network Snellius uses. The partition names rome and thin_course point at the same CPU nodes. The gpu partition holds the GPU cards.

There is no project budget on the course cluster. accinfo is not installed. sacct still reports core-seconds in CPUTimeRAW. On Snellius your project does have a budget, counted in system billing units. You do not need the budget command for the exercises in this lesson.

A faded login


Fill the blank for the machine you are actually using.

BASH

ssh ________@________

On Snellius the host is snellius.surf.nl and the name is your CUA login. On the course cluster both values come from the welcome note.

The sample SSH config in episodes/files/ssh-config-sample is the Snellius shape:

BASH

Host snellius
  HostName snellius.surf.nl
  User YOUR_LOGIN
Challenge

Predict the hostname

You are about to run hostname after logging in. Write down what you think the name will start with, before you run it.

On Snellius, which of these is a login node: int4, or tcn123?

int4 is a login node. Names that start with int are the shared door. A name like tcn123 is a compute node. You should see an int name when you run hostname on Snellius just after SSH. On the course cluster there is one login node, and its name is the one in your welcome note, not an int name.

Challenge

Check a Snellius SSH config

From the lesson directory, run the offline check:

BASH

bash episodes/files/exercises/login-checklist.sh

SH

hostname=snellius.surf.nl

What does the script refuse to accept?

It reads HostName from episodes/files/ssh-config-sample and exits with an error if that value is not snellius.surf.nl. A course-cluster address belongs in a different Host block, not in this one.

Challenge

Log in for real

On Snellius or the course cluster, run:

BASH

hostname
sinfo -s
who

In the EESSI client container there is no Slurm, so sinfo will not exist. Run hostname there anyway, and compare it with the cluster. Setup for the container is on the setup page.

On Snellius, hostname starts with int and sinfo -s lists partitions such as rome and genoa. On the course cluster, sinfo -s shows the small partitions, including thin_course or rome. who shows other people on the login node. That is the reminder: the door is shared.

The container prints its own hostname. That name is the container, not a SURF node. You use it for the software exercises, not as a substitute for sinfo.

What you do next


You have a shell on a shared door. The next episode loads the software you will run. The episode after that sends the work through Slurm so it does not stay on this door.

Key Points
  • A supercomputer is a login node, a scheduler, and compute nodes.
  • ssh YOUR_LOGIN@snellius.surf.nl reaches Snellius after you have a CUA account.
  • The course cluster is a Magic Castle workspace. Its address is in your welcome note.
  • hostname on a Snellius login node starts with int.
  • A long computation does not belong on the login node.

Content from Software from a shared stack


Last updated on 2026-10-26 | Edit this page

Overview

Questions

  • Why do you load software instead of installing it into your home directory?
  • How do you get the same Python on the cluster and in a container?

Objectives

  • Explain why a shared software stack is easier to support than a private install.
  • Source the EESSI 2025.06 init script and read the CPU target it prints.
  • Use module avail, module spider, and module load to select a program.
  • Name the site command module load 2025 and the portable init script it stands in for on the course cluster.
  • Point to the EasyBuild book when the question is how a module was built, and stop there.

One copy, many people


If every person compiles their own Python, the cluster fills up with almost the same files, and nobody can say which one a paper used. A shared stack is one curated set of builds. You select a build by loading a module. The files stay on a shared file system. Your home directory stays for your own scripts and small inputs.

EESSI is that kind of stack, distributed with CVMFS. CVMFS shows a directory tree that is the same on every machine that mounts it, and it fetches a file when you first use it. The tree for this lesson is /cvmfs/software.eessi.io.

Where a program comes from. The nodes drawn are your script, CVMFS, EESSI, module, and the program.
Where a program comes from. The nodes drawn are your script, CVMFS, EESSI, module, and the program.

How those builds are produced is a different course. EasyBuild is the tool that turns a recipe into the module you load. Read that story in the book at https://hpceb.rgoswami.me/ and in the sources at https://github.com/HaoZeke/what-easybuild-is-doing. This episode only uses the result.

Start the stack


On any machine where the repository is mounted, including the EESSI client container:

BASH

source /cvmfs/software.eessi.io/versions/2025.06/init/lmod/bash

The script loads the EESSI/2025.06 module and prints three kinds of lines: that the module loaded, which CPU target it selected, and whether it saw a GPU. The CPU line depends on the machine. On one Intel Sapphire Rapids host it was:

Module for EESSI/2025.06 loaded successfully
EESSI has selected x86_64/intel/sapphirerapids as the compatible CPU target for EESSI/2025.06
EESSI did not identify an accelerator on the system

Your line may name a different CPU. Read the line. Do not copy a path from someone else's CPU into your script. The init script picks the path for you.

Two variables are stable:

BASH

printf '%s\n' "$EESSI_VERSION"
printf '%s\n' "$EESSI_CVMFS_REPO"

They print 2025.06 and /cvmfs/software.eessi.io.

The previous stack is still there. After module purge, module load EESSI/2023.06 switches to it. You can also source /cvmfs/software.eessi.io/versions/2023.06/init/lmod/bash in a new shell. Do not load both stacks in one shell. Purge first.

On the course cluster you do not have to source that file by hand. module load 2025 loads EESSI 2025.06. The names 2024 and foss/2023a load that same stack on the course cluster, so older scripts keep working. On Snellius, module load 2025 is how you select the 2025 site stack. Prefer the explicit init script when you are in the container, because the container does not define the site name 2025.

Callout

QCG-PilotJob is not part of EESSI 2025.06. module spider QCG-PilotJob reports that it cannot find it. The cluster installs it as a site module, loaded after module load 2024. That is the next episode but one. Do not spend this episode searching the EESSI tree for it.

Find a Python and load it


module avail prints a long list. module spider Python searches it. In EESSI 2025.06 the Python modules include:

  • Python/3.12.3-GCCcore-13.3.0
  • Python/3.13.1-GCCcore-14.2.0
  • Python/3.13.5-GCCcore-14.3.0 (the default)

In EESSI 2023.06 one of the modules is Python/3.11.5-GCCcore-13.2.0.

Load the 2025.06 default, then ask Python where it lives:

BASH

module load Python/3.13.5-GCCcore-14.3.0
python3 --version

python3 --version prints Python 3.13.5. The prefix is under /cvmfs/software.eessi.io/versions/2025.06/. The CPU directory in the middle of that path is the one the init script chose.

module list shows what is loaded. module purge unloads it. ml is the short form of module once the init script has run.

A faded load


BASH

source /cvmfs/software.eessi.io/versions/________/init/lmod/bash
module load Python/________
python3 --version

For this course the version is 2025.06 and the module is Python/3.13.5-GCCcore-14.3.0.

Challenge

Predict the version string

Write down what you expect the next block to print. Then run it. On a cluster, run it in a shell where you have sourced the init script, or where module load 2025 has already set the stack up. In the container, the check below runs the same questions for you.

What is EESSI_VERSION after the 2025.06 init? What Python version do you get from Python/3.13.5-GCCcore-14.3.0? After a purge and module load EESSI/2023.06, what version does Python/3.11.5-GCCcore-13.2.0 report?

BASH

# runner: eessi
set +u
source /cvmfs/software.eessi.io/versions/2025.06/init/lmod/bash >/dev/null
set -u
printf '%s\n' "$EESSI_VERSION"
printf '%s\n' "$EESSI_CVMFS_REPO"
module load Python/3.13.5-GCCcore-14.3.0
python3 -c 'import sys; print(sys.version.split()[0]); prefix=sys.prefix; print("eessi-prefix" if prefix.startswith("/cvmfs/software.eessi.io/versions/2025.06/") else "unexpected")'
module purge >/dev/null
module load EESSI/2023.06 >/dev/null
module load Python/3.11.5-GCCcore-13.2.0
python3 -c 'import sys; print(sys.version.split()[0])'

SH

2025.06
/cvmfs/software.eessi.io
3.13.5
eessi-prefix
3.11.5

eessi-prefix means the prefix started with the 2025.06 tree. The CPU directory is allowed to differ. set +u lets the init script read a variable that may be unset, and set -u turns that check back on.

Challenge

Load Python on the cluster

On the course cluster:

BASH

module purge
module load 2025
module spider Python
module load Python/3.13.5-GCCcore-14.3.0
python3 --version
which python3

On Snellius, module load 2025 selects the site 2025 stack. If Python/3.13.5-GCCcore-14.3.0 is not the name there, trust module spider Python and load the newest 3.13 it offers. Write the full module name in your notes.

If /cvmfs/software.eessi.io is missing, use the container path from the setup page and run the block in the solution above.

python3 --version prints Python 3.13.5 when that module exists. which python3 prints a path under the stack, not under /usr/bin. If the site stack uses a different build, the version string changes and that is the number you record. Mixing a site module load with a second source of the init script in the same shell is how two Pythons end up on PATH. Purge first.

Key Points
  • A shared stack means one supported copy of a program, selected with a module.
  • source /cvmfs/software.eessi.io/versions/2025.06/init/lmod/bash prepares EESSI 2025.06.
  • module spider searches. module load selects. module purge clears the selection.
  • On the course cluster, module load 2025 is the site name for EESSI 2025.06.
  • EasyBuild, and how a module file is produced, is the book at https://hpceb.rgoswami.me/.

Content from Submitting a job


Last updated on 2026-10-26 | Edit this page

Overview

Questions

  • How do you ask Slurm for time and cores without starting the work on the login node?
  • What does a job array change, compared with four separate scripts?

Objectives

  • Write a batch script with a job name, a partition, a core count, a time limit, and an output file.
  • Explain why Snellius rounds a small request up to 16 cores on the rome partition.
  • Submit a script with sbatch and read its state with squeue.
  • Use SLURM_ARRAY_TASK_ID to give each array task a different input.
  • Cancel a job you submitted by mistake with scancel.

The script is the request


A batch script is a shell script with a header of #SBATCH lines. Slurm reads the header. The shell runs the rest, on a compute node, after the wait.

This is the Snellius shape. The file in the lesson is episodes/files/pi-snellius.sh.

BASH

#!/bin/bash
#SBATCH --job-name=pi-one
#SBATCH --partition=rome
#SBATCH --cpus-per-task=16
#SBATCH --time=00:15:00
#SBATCH --output=pi-%j.out

module purge
module load 2025
export SAMPLE_COUNT=1000
python3 pi_one.py

%j in the output name becomes the job id. pi_one.py prints one line, samples=1000 hits… estimate=…=. It uses a fixed random sequence, so the same SAMPLE_COUNT always prints the same line. The program is in episodes/files/pi_one.py.

On Snellius the rome partition gives memory with the cores, and the smallest slice is 16 cores. A request for 1 core is rounded up to 16, and the project is charged for 16. Asking for 16 in the script matches what you will be charged.

On the course cluster the same nodes answer to rome and to thin_course, and a node has two cores. Ask for one core there. episodes/files/pi-course.sh is that script: --partition=thin_course and --cpus-per-task=1.

Submit from the directory that contains pi_one.py:

BASH

sbatch pi-course.sh
squeue -u "$USER"

sbatch prints Submitted batch job and a number. squeue shows PD while the job waits and R while it runs. When it leaves the queue, read pi-<jobid>.out.

Callout

srun can start a step inside a job, or a short interactive allocation. sbatch is the command for a script you can resubmit. This lesson uses sbatch.

The directives you will see most often are in episodes/files/slurm-directives.tsv. The same rows are below.

directive meaning example where
–job-name a short name in the queue pi-one any Slurm cluster
–partition which group of nodes rome Snellius and the course cluster
–cpus-per-task cores for the one task 16 Snellius rome slice
–time wall clock limit 00:15:00 any Slurm cluster
–output file for the job text pi-%j.out any Slurm cluster
–array one index per task 0-3 any Slurm cluster

While you wait


A job in PD is waiting for resources. squeue -u "$USER" is enough during class. scancel JOBID removes a job you do not want. On Snellius, scontrol show job JOBID tells you why a job is still waiting. On the course cluster the reason is usually that someone else holds the two cores.

Do not resubmit because the first job is still PD. You will get two jobs, and then four.

Four lengths, one script


A job array runs the same script many times. SLURM_ARRAY_TASK_ID is 0, 1, 2, or 3 when you ask for --array=0-3. %A is the array id and %a is the task id, so each task gets its own output file.

episodes/files/pi-array.sh:

BASH

#!/bin/bash
#SBATCH --job-name=pi-array
#SBATCH --partition=thin_course
#SBATCH --cpus-per-task=1
#SBATCH --time=00:10:00
#SBATCH --array=0-3
#SBATCH --output=pi-%A_%a.out

module purge
module load 2025
sizes=(1000 2000 4000 8000)
export SAMPLE_COUNT="${sizes[$SLURM_ARRAY_TASK_ID]}"
python3 pi_one.py

A faded header


BASH

#SBATCH --job-name=________
#SBATCH --partition=________
#SBATCH --cpus-per-task=________
#SBATCH --time=________

On the course cluster the partition is thin_course or rome, and the core count is 1 for this program. On Snellius rome the core count for this lesson is 16.

Challenge

Predict the array index

sizes has four numbers: 1000, 2000, 4000, 8000. The header says --array=0-3. Which SAMPLE_COUNT does task 2 export? Write the number before you look at the solution.

Task 2 exports 4000. The index starts at 0, so task 0 is 1000, task 1 is 2000, task 2 is 4000, and task 3 is 8000. The output file for task 2 is pi-<arrayid>_2.out.

Challenge

Check the batch script

From the lesson directory:

BASH

bash episodes/files/exercises/check-batch-script.sh

SH

batch-script=ok

Then, if you are on the course cluster, submit the one-core script and the array. Copy pi_one.py into the directory you submit from, or submit from episodes/files.

BASH

cd episodes/files
sbatch pi-course.sh
sbatch pi-array.sh
squeue -u "$USER"

The check runs bash -n on pi-snellius.sh and requires the five directives plus module load 2025. A missing --time line makes it exit with an error.

After sbatch, squeue shows one job and an array. When they finish, pi-<jobid>.out contains one samples=1000 line. The array writes four files. Task 0 prints samples=1000. You can also run SAMPLE_COUNT=1000 python3 pi_one.py on the login node for this tiny count if the queue is busy. 1000 samples is a login-node-sized test. The array sizes above 1000 belong in the job.

Key Points
  • A batch script is a shell script plus #SBATCH resource lines.
  • sbatch submits. squeue shows the wait. scancel removes a job.
  • On Snellius rome, ask for 16 cores because smaller requests are rounded up.
  • On the course cluster, ask for 1 core on thin_course or rome.
  • SLURM_ARRAY_TASK_ID selects the input for one task in an array.

Content from Files and moving data


Last updated on 2026-10-26 | Edit this page

Overview

Questions

  • Which directory is for a running job, and which one is for a file you still need next month?
  • Why does a directory of tiny files travel badly?

Objectives

  • Choose home, scratch-shared, scratch-local, scratch-node, projects, or archive for a file on Snellius.
  • Name the three course-cluster mounts and the one that is not shared.
  • Pack a directory of small files with tar before you copy it.
  • Copy with rsync -avP and check the archive with sha256sum -c.
  • State what dcp and dsync are for, after the small-file case is already packed.

Six places on Snellius


A file's path decides how fast it is, who can read it, and when it disappears.

Home holds 200 GiB. An unused file on scratch-shared is removed after 14 days. Scratch-local keeps a file for 6 days. The class table is episodes/files/filesystems.tsv.

place mount backup lifetime quota
home /home/LOGIN nightly 15 weeks after the project ends 200 GiB
scratch-shared /scratch-shared/ none 14 days 8 TiB across scratch areas
scratch-local /scratch-local/ none 6 days counted in the scratch quota
scratch-node /scratch-node/ none deleted when the job ends the node disk
project /projects/NAME none the project by request
archive /archive/ nightly the project by request
Where files live on Snellius. The nodes drawn are home, scratch-shared, scratch-node, and project.
Where files live on Snellius. The nodes drawn are home, scratch-shared, scratch-node, and project.

On the course cluster you have three mounts, not six. /home is the shared home file system. /project is large shared scratch, and it is not the same path as Snellius /projects. /scratch is the local disk on that machine. It is not shared with the other nodes. There is no tape archive.

Callout

A file written to /scratch on the course login node is not visible on a compute node. A file written to $TMPDIR on Snellius disappears when the job ends. Copy results to /home or /project before the job exits.

Pack, then copy


Fifty single-line files are a bad transfer. Each file is a separate metadata operation. tar turns them into one file. rsync -avP copies that file and can continue if the connection drops. -a keeps timestamps and permissions, -v lists files, and -P shows progress and keeps a partial file.

From the machine that has the files, towards the cluster:

BASH

tar -cf many.tar many
rsync -avP many.tar YOUR_LOGIN@snellius.surf.nl:/scratch-shared/$USER/

On the course cluster the destination is YOUR_LOGIN@MANAGER:/project/$USER/. Create the directory on the remote side first if it does not exist.

Then check the bytes. On the source:

BASH

sha256sum many.tar > many.tar.sha256

Copy the .sha256 file the same way, and on the destination:

BASH

sha256sum -c many.tar.sha256

A good check prints the file name and OK.

sha256sum and rsync in this lesson are the ones on the machine, not an EESSI module. command -v sha256sum and command -v rsync should print a path. tar is the system tar.

When the copy itself is the large job


mpiFileUtils provides dcp, dsync, and dwalk for copies that need many nodes. You do not need them for many.tar. You need them when the tree is huge and a single rsync would take the whole day. dcp copies. dsync updates a destination to match a source. dwalk lists a tree in parallel so you can see what you have.

The module name is site-specific. On the course cluster, module load 2025 and then module spider mpiFileUtils. Load the name spider prints. Do not invent a version. If the spider search is empty, the tool is not on that stack, and rsync remains the tool for this lesson's files.

A faded destination


BASH

rsync -avP many.tar ________:________/

Snellius shared scratch for your user is YOUR_LOGIN@snellius.surf.nl:/scratch-shared/$USER/. The course cluster uses /project/$USER/ on MANAGER.

Challenge

Predict the surviving file

A job on Snellius writes result.txt into $TMPDIR and also copies it to /scratch-shared/$USER/result.txt. The job ends. Which copy can you still open from the login node the same afternoon, and which copy is already gone?

/scratch-shared/$USER/result.txt is still there that afternoon. The $TMPDIR copy lived on the node-local NVMe and was removed at the end of the job. Two weeks later the scratch copy can also be gone if nobody has used it. A file you still need next month belongs on /projects or /archive, not on scratch.

Challenge

Pack fifty files and check the sum

From the lesson directory:

BASH

bash episodes/files/exercises/pack-small-files.sh

SH

packed=50
checksum=ok

If you are copying to a real cluster, use your own login in the rsync line and a destination under /scratch-shared/$USER or /project/$USER. Do not copy the fifty loose files.

The script creates fifty small files, packs them with tar, and runs sha256sum -c. packed=50 means the archive contains fifty members. checksum=ok means the digest matched. If the digest does not match, copy the archive again. Do not unpack a file that failed the check and then try to debug the contents.

Key Points
  • On Snellius, home is small and persistent, scratch is large and temporary, and $TMPDIR dies with the job.
  • On the course cluster, /project is the shared large disk and /scratch is local to one machine.
  • Pack many small files with tar before you transfer them.
  • rsync -avP copies the archive. sha256sum -c checks it.
  • dcp and dsync are for a tree that is already too big for one rsync.

Content from Many small tasks


Last updated on 2026-10-26 | Edit this page

Overview

Questions

  • Why is one Slurm job per tiny task a poor plan?
  • What does a pilot job keep hold of, while it runs the tasks?

Objectives

  • Explain the cost of submitting thousands of separate Slurm jobs.
  • Run three tasks inside one QCG-PilotJob LocalManager on the course stack.
  • Describe a HyperQueue server as a process that fills one Slurm allocation with tasks.
  • Read a three-rule Snakemake file as a graph of files, not as a queue.
  • Say what FireWorks adds when tasks must be tracked in a database.

The queue is not free


A one-second task with its own sbatch still waits in the queue, still writes a job record, and still starts a shell. A few thousand of those tasks can spend more time starting than working. A job array, from the Slurm episode, is the first improvement: one submission, many tasks, and Slurm still tracks each task.

A pilot job goes further. You ask Slurm for a block of cores once. A small manager sits inside that allocation and starts the short tasks itself. The queue saw one job.

Many tasks inside one Slurm job. The nodes drawn are one allocation, pilot, and many tasks.
Many tasks inside one Slurm job. The nodes drawn are one allocation, pilot, and many tasks.

QCG-PilotJob on the course cluster


QCG-PilotJob is the pilot manager this course installs. It is a site module. It is not in the EESSI stack. module spider QCG-PilotJob inside EESSI 2025.06 says it cannot be found, and that is expected.

On the course cluster:

BASH

module purge
module load 2024
module load QCG-PilotJob
python3 episodes/files/exercises/qcg-three.py

module load 2024 is the course alias for EESSI 2025.06. Load it before QCG-PilotJob. The script submits three tasks that each run printf, waits until they finish, and prints:

qcg-finished
task-0

The Python is short. A LocalManager runs the tasks on the machine where you started it. Jobs collects the descriptions. Each task asks for exactly one core.

PYTHON

manager = LocalManager()
jobs = Jobs()
jobs.add(name="job_0", exec="/usr/bin/printf", args=["task-0\\n"],
         stdout="out_0.txt", numCores={"exact": 1})
manager.submit(jobs)
manager.wait4all()
manager.finish()

On a cluster you normally put that manager inside one sbatch script, so the cores come from the allocation instead of from the login node. For three printf tasks the login node is an acceptable place to see the tool work. A real parameter sweep belongs in the job.

qcg-pilotjob --help-h prints the command-line help if you want the non-Python entry point. The exercises use the Python API because that is what the course stack is there to support.

Callout

If module load QCG-PilotJob fails, you are probably on the EESSI container or on a machine without the site module. Skip the run. The HyperQueue and Snakemake sections are still readable, and the QCG script is still in the lesson files for later.

HyperQueue


HyperQueue is the tool to reach for when the pilot should be a small server plus workers, and the workers are Slurm jobs. You start hq server start, you submit tasks to that server, and hq alloc add slurm asks Slurm for workers. The server fills the workers. You do not write one batch script per task.

The idea you should keep: the Slurm job is the bucket of resources. HyperQueue is who pours tasks into the bucket. You do not need to memorise every flag today.

Snakemake


Snakemake starts from files. A rule names an output, the inputs it needs, and the command that builds the output. Snakemake runs a rule when the output is missing or older than the input. Three rules that feed each other are a pipeline:

PYTHON

rule all:
    input: "summary.txt"

rule step_one:
    output: "part.txt"
    shell: "printf 'part\\n' > part.txt"

rule summary:
    input: "part.txt"
    output: "summary.txt"
    shell: "cp part.txt summary.txt"

That is a different question from QCG. QCG asks how to run many copies of a command. Snakemake asks which files are out of date. People combine them: Snakemake decides the graph, and a cluster profile or a pilot runs the commands.

FireWorks


FireWorks stores tasks in a database, with dependencies, and workers pull the tasks. You use it when many people submit tasks, when a task must be retried, or when you need a record of what ran. It is more machinery than a three-task LocalManager. If your whole problem is "run this command on these fifty inputs today", stay with the array or with QCG.

Which tool answers which question


Tool When you reach for it
QCG-PilotJob a Python script should launch tasks inside one allocation
HyperQueue a small server should fill Slurm workers
Snakemake the work is a graph of files
Slurm array every task is the same batch script with a different index
FireWorks tasks must be stored and shared through a database

A faded load


BASH

module purge
module load ________
module load ________

On the course cluster the two names are 2024 and QCG-PilotJob, in that order.

Challenge

Predict the printed line

qcg-three.py runs three tasks. The last two lines of the program print a fixed word and then the contents of out_0.txt. What are those two lines?

qcg-finished
task-0

Task 0 writes task-0 into out_0.txt. The other two tasks write out_1.txt and out_2.txt. The script only prints the first file, so you do not see task-1 in the program output.

Challenge

Run the three tasks

On the course cluster, from the lesson directory, after the two module load commands:

BASH

python3 episodes/files/exercises/qcg-three.py

If you cannot load the module, do not install a random copy into your home directory during class. Read the script instead and write down the three task names.

A successful run ends with qcg-finished and task-0. The working directory is a temporary directory the script creates, so you will not see out_0.txt in the lesson tree afterwards. The three task names inside the script are job_0, job_1, and job_2.

If Python says No module named qcg, the site module is not loaded. module purge and then module load 2024 before module load QCG-PilotJob is the sequence that works on the course cluster.

Key Points
  • Thousands of one-task Slurm jobs spend their time starting, not working.
  • A pilot job holds one allocation and starts the short tasks inside it.
  • On the course cluster, module load 2024 and then module load QCG-PilotJob.
  • QCG-PilotJob is not an EESSI module. module spider inside EESSI will not find it.
  • HyperQueue fills a Slurm allocation, Snakemake tracks files, and FireWorks tracks tasks in a database.

Content from Timing and scaling


Last updated on 2026-10-26 | Edit this page

Overview

Questions

  • What does a single timing tell you, and what does it fail to tell you?
  • When does adding cores stop helping?

Objectives

  • Time a command with time -p and read the real line as wall-clock seconds.
  • Compute speedup and parallel efficiency from a table of timings.
  • Separate a strong-scaling study from a weak-scaling study.
  • Give one reason an efficiency of 1.0 is rare.
  • Place a kernel on a roofline as limited by arithmetic or limited by memory movement.

Wall-clock time


time -p is the POSIX form. It prints three lines to standard error: real, user, and sys. real is the elapsed time you waited. user and sys add up CPU time, which can be larger than real when several cores run at once.

BASH

time -p python3 episodes/files/pi_one.py

Set SAMPLE_COUNT if you want a longer run. The real line is the one to write in a table. A single measurement is noisy. For a number you will compare, run the same command three times and keep the middle real value. This lesson's table is already collected that way, so the exercises use the table instead of asking you to produce a stable benchmark during class.

On the EESSI client the same time -p works, because it is a shell keyword or a system command, not a module.

Strong and weak scaling


Strong scaling keeps the problem the same size and adds cores. The hope is that the same work finishes sooner. Speedup is T(1) / T(N). Parallel efficiency is T(1) / (N * T(N)). An efficiency of 1.0 would mean every new core pulled its full weight. Communication, startup, and parts of the program that do not parallelise pull the number down.

Weak scaling grows the problem with the cores, so each core keeps the same amount of work. The hope is that the time stays about the same. A weather model on a larger region is often a weak-scaling question. A fixed video frame is often a strong-scaling question.

These timings are the worked strong-scaling series in episodes/files/timings.csv. The problem size stays fixed. The efficiencies are 1.000, 0.909, 0.800, and 0.625.

Cores Seconds Speedup Efficiency
1 8.0 1.000 1.000
2 4.4 1.818 0.909
4 2.5 3.200 0.800
8 1.6 5.000 0.625

Eight cores finish in 1.6 seconds instead of 8.0. The speedup is 5, not 8. The efficiency is 0.625. Those last cores still helped, and they helped less than the first ones.

Callout

A faster real time with poor efficiency can still be the right choice when the queue gives you the cores and the person is waiting for the result. Efficiency tells you how much of the machine you used. It does not, by itself, tell you to use fewer cores.

A roofline, in one picture


Two ceilings show up once the program is already parallel. The figure names them the bandwidth roof and the peak roof. Your code sits under one of them.

The peak roof is how fast the cores can do arithmetic. If the kernel does a lot of arithmetic on each byte it reads, it can reach that roof.

The bandwidth roof is how fast bytes move. If the kernel does little arithmetic per byte, it hits that slope first. Adding cores does not help a kernel that is already waiting on memory, until you also give it more memory bandwidth.

Arithmetic intensity is arithmetic per byte moved. A low intensity sits under the bandwidth roof. A high intensity sits under the peak roof. You do not need a profiler to use the picture. You need it so that "use more cores" is not your only idea.

Two bounds for a program. The nodes drawn are bandwidth roof, peak roof, and your code.
Two bounds for a program. The nodes drawn are bandwidth roof, peak roof, and your code.

A faded efficiency


efficiency = ________ / (cores * ________)

The first blank is the one-core time. The second is the time at that core count.

Challenge

Predict the eight-core efficiency

The table says 8.0 seconds on one core and 1.6 seconds on eight. What is 8.0 / (8 * 1.6)? Write the decimal before you run the checker.

0.625. The checker prints one efficiency per row and checks that the last row matches.

BASH

python3 episodes/files/exercises/scaling-table.py

SH

1 1.000
2 0.909
4 0.800
8 0.625
Challenge

Time one short run

From the lesson directory, with python3 available:

BASH

SAMPLE_COUNT=1000 time -p python3 episodes/files/pi_one.py

Which of the three time lines is the wall-clock time? Run it twice. Do the two real lines match to the hundredth of a second?

real is the wall-clock time. user and sys are CPU time. Two runs of a 1000-sample estimate often differ in the hundredths, because the machine is doing other work. That is why a comparison uses a repeated measurement, or a table collected under the same conditions, rather than one lucky run. The pi_one.py estimate line itself does not change between runs. Only the timing does.

Key Points
  • time -p prints real, user, and sys. real is the time you waited.
  • Strong scaling fixes the problem size. Weak scaling grows it with the cores.
  • Efficiency is T(1) / (N * T(N)). The sample eight-core efficiency is 0.625.
  • A roofline separates a kernel limited by arithmetic from one limited by memory movement.
  • Compare timings of the same work. One noisy run is a weak basis for a claim.