Parallel computing lab: how a GPU thinks, without a GPU, in JupyterLab

This lab gives each student a JupyterLab of their own for the ideas a GPU is built on: one operation over a great many numbers, a job split between workers, the limit on how much that can speed it up, a launch of blocks of threads that each find their own element, and the cost of moving data. There is no GPU in the lab. It teaches the model with NumPy, Python’s own multiprocessing and six short scripts.

It is not an attack lab. Every copy has no route to the internet and none to any other student, so nothing can be downloaded into it and nothing in it can reach anybody else.

What students learn

That one NumPy operation does the work of a Python loop over a whole array: the sum of squares of 1 to 1000 is 333833500 both ways, in 2000 Python-level operations for the loop and 1 for NumPy. That a job can be cut into chunks and shared between two workers, and that the partial sums add up to the same total. That some of every job cannot be split, so with 10 percent serial, 8 workers give 4.71 times and no number of workers gives more than 10.0. How a GPU kernel is launched as blocks of threads, each working out its own element as block times block size plus thread, which they see simulated in plain Python. Whether a job is limited by moving bytes or by doing sums, worked out from a stated bandwidth and rate. And why threads that read neighbouring numbers fetch 1 line of memory where threads that stride fetch 8. It suits introductions to computer architecture, parallel and high-performance computing and graphics; check your own awarding body’s unit for the exact wording, none is quoted here.

Run it in your browser

The lab starts one service, jupyter, which writes the notebook and the six scripts into its work folder and is ready in a few seconds, inside the 512 MB a service may have. JupyterLab asks for no token, because the platform’s own door already knows who is opening it. The terminal beside the lab has no Python of its own, so it reaches the lab’s with docker exec jupyter, followed by the command to run inside. Nothing is timed, so every script prints the same each time.

  1. Open the Container page. Open Build on the bar and choose Run a container. Anybody may open it, and the Git lab and the SQL lab start with no account. Every other lab needs a free account: create one, sign in, then press Start.
  2. Find the lab. The Sample labs card lists every sample. Find JupyterLab: parallel computing without a GPU.
  3. Press Start. Start runs it as it is, in one press. Edit the file first opens the compose file so you can change it before you start.
  4. Open it. On the lab’s page, the lab bar has a link called JupyterLab: press it to open JupyterLab in your browser and double-click start.ipynb. Then press Open terminal and type docker exec jupyter python3 steps/vectors.py to see the two results equal at 333833500, with 2000 operations for the loop and 1 for NumPy.

What to ask students to hand in

A short change of their own to one script, downloaded from JupyterLab with File, Download, such as a different number of chunks in chunks.py, a different share that cannot be split in amdahl.py, or a different launch size in kernel.py. Then a sentence or two in their own words on what moved and why. Nothing is marked automatically: the sentence shows whether it was understood. For stronger work ask them to predict the new numbers before they run it, and to say which limit, the serial part or the memory, they would meet first on a real GPU.

A basic lesson on this lab

Parallel Computing Basics is a small lesson worked in this lab. In it a student lists the scripts, sums squares with a loop and with one NumPy operation, shares a sum between two workers, reads a table of speed-ups, runs a simulated launch of blocks of threads, sees which of two jobs is limited by memory, and then opens the same work in the starter notebook.

It is deliberately small: it shows a teacher what a lesson worked in a lab is, and the lab does the rest. Copy it into a module of your own to change it.

The code on GitHub

The compose file has no Dockerfile: it runs one stock public image, the Jupyter Docker Stacks’ own scipy-notebook, pinned to a dated tag, as its own unprivileged account with 512 MB of memory. The image is licensed BSD-3-Clause and is not distributed by us. The file writes the scripts from fixed numbers when it starts, so every copy prints the same and nothing is downloaded. The limits are honest ones: there is no GPU, so the kernel launch is simulated in Python and the transfer figures are arithmetic on a made-up device, never a measurement. Nothing can be installed from the internet. Nothing is kept when the lab stops, so a student downloads their work first.

Set it as work

Say in the task what to hand in.

  1. Make the lab. In your module add a task and choose the Container lab card, then In a GitHub repository. Give https://github.com/mitsurutech/lab-parallel-lab with the branch main. The compose file is the default, compose.yaml. Fork the repository first if you want to change it, for example to change the numbers a script uses.
  2. Publish and try it. Publish pins the commit you were shown, so a later change in the repository does not alter a lab you have already set. Start your own copy first.
  3. Hand it out. Assign it like any task, with a due date if you want one, and say in the task what to do and what to hand in.
  4. Mark what is handed in. Open a student’s copy and the work they handed in, mark it, and send it back with a reason if it needs more.

Try this lab, and what it costs

A free personal account can work through the basic lessons in this lab, with enough free credit each month to follow most lessons and no card. For a class, a school or college has its first 365 days free for up to 50 students, then pays per student a year, with every lab included and staff free.

Questions people ask

Is there a GPU in the lab?
No. The lab teaches the model a GPU is built on, with NumPy, Python’s multiprocessing and short scripts. The kernel launch is simulated in plain Python, and the figures about moving data are arithmetic on a made-up device, so a student learns how to think about a GPU without one.
Why does the terminal use docker exec jupyter?
The lab’s terminal carries curl, psql and a few other clients, and no Python. docker exec jupyter runs a command inside the lab’s own container, which has Python and NumPy. JupyterLab also has a terminal of its own, under File, New, Terminal.
Why does nothing print a time?
A time changes from run to run and from machine to machine, so a lesson could not say what a student should see. The scripts count operations and work out figures from a stated bandwidth and rate instead, so every run prints the same and every answer can be checked by hand.