Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/cscs.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,10 @@ CSCS_EDF="${CSCS_EDF}" \
The driver runs:

- package smoke tests through the normal tutorial entrypoint
- the full notebook ladder, including `03__mpi4py`
- the full notebook ladder, including `06__mpi4py`
- direct `nsys` and `ncu` command-line smoke checks

The PyHPC image builds `mpi4py` against MPICH. Notebook 03 runs local ranks with
The PyHPC image builds `mpi4py` against MPICH. Notebook 06 runs local ranks with
`mpirun.mpich -launcher fork`, avoiding nested use of the host `srun` launcher.

For debugging, the individual commands are below.
Expand Down Expand Up @@ -214,7 +214,7 @@ Run the profiling notebooks:
```bash
srun -A "${CSCS_ACCOUNT}" -p normal -t 01:00:00 -N1 -n1 \
--environment="${CSCS_EDF}" \
env ACH_RUN_TESTS=1 ACH_TEST_ARGS="10 or 11 or 12" \
env ACH_RUN_TESTS=1 ACH_TEST_ARGS="03 or 04 or 05" \
/accelerated-computing-hub/brev/entrypoint.bash base
```

Expand Down
4 changes: 2 additions & 2 deletions tutorials/pyhpc/.gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Artifacts generated when the tutorial is run.
#
# SWE ladder (notebooks 04-09):
# SWE ladder (notebooks 07-12):
notebooks/build/
notebooks/CMakeLists.txt
notebooks/swe_step.cpython-*.so
notebooks/timings.json

# Kernel / asynchrony notebooks (10-12): %%writefile scripts, Nsight
# Kernel / asynchrony notebooks (03-05): %%writefile scripts, Nsight
# profiler reports, the downloaded text corpus, and rendered plots.
# Patterns are applied at the notebooks/ root and under solutions/, since
# executing the solution notebooks (e.g. in CI) writes the same artifacts there.
Expand Down
38 changes: 19 additions & 19 deletions tutorials/pyhpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Brev Launchables of this tutorial should use:

## Notebooks

Each exercise notebook that has a paired solution carries `# TODO:` cells with `...` placeholders; the solution fills them in. The intro/reference notebook (04), the synthesis notebook (09), and the mpi4py walkthrough (03) are complete as written and have no separate solution.
Each exercise notebook that has a paired solution carries `# TODO:` cells with `...` placeholders; the solution fills them in. The intro/reference notebook (07), the synthesis notebook (12), and the mpi4py walkthrough (06) are complete as written and have no separate solution.

### Fundamentals

Expand All @@ -27,32 +27,32 @@ Each exercise notebook that has a paired solution carries `# TODO:` cells with `
| 01 | CuPy | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/01__cupy.ipynb) | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/solutions/01__cupy__SOLUTION.ipynb) |
| 02 | Power Iteration - CuPy - Memory Spaces | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/02__power_iteration__cupy__memory_spaces.ipynb) | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/solutions/02__power_iteration__cupy__memory_spaces__SOLUTION.ipynb) |

### Distributed
### Kernels

| # | Notebook | Link | Solution |
|---|----------|------|----------|
| 03 | mpi4py | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/03__mpi4py.ipynb) | |

### Programming models and interoperability
| 03 | Power Iteration - CuPy - Asynchrony | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/03__power_iteration__cupy__asynchrony.ipynb) | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/solutions/03__power_iteration__cupy__asynchrony__SOLUTION.ipynb) |
| 04 | Copy - Kernel Authoring | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/04__copy__kernel_authoring.ipynb) | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/solutions/04__copy__kernel_authoring__SOLUTION.ipynb) |
| 05 | Book Histogram - Kernel Authoring | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/05__book_histogram__kernel_authoring.ipynb) | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/solutions/05__book_histogram__kernel_authoring__SOLUTION.ipynb) |

Notebooks 04-09 are the Shallow Water Equations "ladder": an intro plus NumPy baseline, four solvers that each re-implement the same timestep with a different tool, and a synthesis that reads the measured timings and compares them. The synthesis notebook collects the per-tool rows from `timings.json` (written by notebooks 04 to 08) and closes with a matched-precision GPU comparison of the JAX and CppJIT device paths.
### Distributed

| # | Notebook | Link | Solution |
|---|----------|------|----------|
| 04 | SWE - Intro | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/04__swe__intro.ipynb) | |
| 05 | SWE - JAX | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/05__swe__jax.ipynb) | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/solutions/05__swe__jax__SOLUTION.ipynb) |
| 06 | SWE - PyOMP | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/06__swe__pyomp.ipynb) | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/solutions/06__swe__pyomp__SOLUTION.ipynb) |
| 07 | SWE - nanobind | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/07__swe__nanobind.ipynb) | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/solutions/07__swe__nanobind__SOLUTION.ipynb) |
| 08 | SWE - CppJIT - Thrust | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/08__swe__cppjit__thrust.ipynb) | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/solutions/08__swe__cppjit__thrust__SOLUTION.ipynb) |
| 09 | SWE - Synthesis | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/09__swe__synthesis.ipynb) | |
| 06 | mpi4py | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/06__mpi4py.ipynb) | |

### Kernels
### Programming models and interoperability

Notebooks 07-12 are the Shallow Water Equations "ladder": an intro plus NumPy baseline, four solvers that each re-implement the same timestep with a different tool, and a synthesis that reads the measured timings and compares them. The synthesis notebook collects the per-tool rows from `timings.json` (written by notebooks 07 to 11) and closes with a matched-precision GPU comparison of the JAX and CppJIT device paths.

| # | Notebook | Link | Solution |
|---|----------|------|----------|
| 10 | Power Iteration - CuPy - Asynchrony | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/10__power_iteration__cupy__asynchrony.ipynb) | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/solutions/10__power_iteration__cupy__asynchrony__SOLUTION.ipynb) |
| 11 | Copy - Kernel Authoring | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/11__copy__kernel_authoring.ipynb) | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/solutions/11__copy__kernel_authoring__SOLUTION.ipynb) |
| 12 | Book Histogram - Kernel Authoring | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/12__book_histogram__kernel_authoring.ipynb) | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/solutions/12__book_histogram__kernel_authoring__SOLUTION.ipynb) |
| 07 | SWE - Intro | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/07__swe__intro.ipynb) | |
| 08 | SWE - JAX | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/08__swe__jax.ipynb) | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/solutions/08__swe__jax__SOLUTION.ipynb) |
| 09 | SWE - PyOMP | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/09__swe__pyomp.ipynb) | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/solutions/09__swe__pyomp__SOLUTION.ipynb) |
| 10 | SWE - nanobind | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/10__swe__nanobind.ipynb) | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/solutions/10__swe__nanobind__SOLUTION.ipynb) |
| 11 | SWE - CppJIT - Thrust | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/11__swe__cppjit__thrust.ipynb) | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/solutions/11__swe__cppjit__thrust__SOLUTION.ipynb) |
| 12 | SWE - Synthesis | [![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/NVIDIA/accelerated-computing-hub/blob/main/tutorials/pyhpc/notebooks/12__swe__synthesis.ipynb) | |

### Python/C++ interoperability

Expand All @@ -64,7 +64,7 @@ A standalone comparison of several ways to call C and C++ from Python (ctypes, c

## The Shallow Water Equations problem

A 1D shallow-water bump pulse: a small mound of water at rest splits into two outgoing wave packets. Two conserved fields (`h`, `hu`) advance under a forward-Euler step. This PDE is small enough to read in full while exhibiting nonlinearity, and a fixed number of steps from the initial condition gives a result we can compare across tools. The full specification is in [`04__swe__intro.ipynb`](./notebooks/04__swe__intro.ipynb).
A 1D shallow-water bump pulse: a small mound of water at rest splits into two outgoing wave packets. Two conserved fields (`h`, `hu`) advance under a forward-Euler step. This PDE is small enough to read in full while exhibiting nonlinearity, and a fixed number of steps from the initial condition gives a result we can compare across tools. The full specification is in [`07__swe__intro.ipynb`](./notebooks/07__swe__intro.ipynb).

## Running

Expand All @@ -76,8 +76,8 @@ Locally, with an NVIDIA GPU and a CUDA-13-capable driver:
docker compose -f tutorials/pyhpc/brev/docker-compose.yml up
```

Then open JupyterLab on port 8888. The notebooks are self-contained and can be run in any order, with one exception: the Shallow Water Equations ladder writes `timings.json` as you run notebooks 04 to 08, so run those before the synthesis notebook (09).
Then open JupyterLab on port 8888. The notebooks are self-contained and can be run in any order, with one exception: the Shallow Water Equations ladder writes `timings.json` as you run notebooks 07 to 11, so run those before the synthesis notebook (12).

## CppJIT toolchain

Notebook 08 uses CppJIT to automatically bind our Python runtime with CUDA C++, using the clang-repl C++ interpreter and [CppInterOp](https://github.com/compiler-research/CppInterOp). This is currently source built in the [Docker image](./brev/dockerfile) and not a standard `pip install`, so this will only run in the tutorial image. [CppJIT](https://github.com/compiler-research/CppJIT) is the successor to the [cppyy](https://cppyy.readthedocs.io/) automatic bindings tool, and no official CppJIT release is published on PyPI yet (beta release planned for end of summer 2026).
Notebook 11 uses CppJIT to automatically bind our Python runtime with CUDA C++, using the clang-repl C++ interpreter and [CppInterOp](https://github.com/compiler-research/CppInterOp). This is currently source built in the [Docker image](./brev/dockerfile) and not a standard `pip install`, so this will only run in the tutorial image. [CppJIT](https://github.com/compiler-research/CppJIT) is the successor to the [cppyy](https://cppyy.readthedocs.io/) automatic bindings tool, and no official CppJIT release is published on PyPI yet (beta release planned for end of summer 2026).
8 changes: 4 additions & 4 deletions tutorials/pyhpc/brev/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,22 @@ jupyter-dark-detect == 0.1.0
nbformat == 5.10.4
nbconvert == 7.17.1

# Programming models and interop (notebooks 04-09: the SWE ladder)
# Programming models and interop (notebooks 07-12: the SWE ladder)
jax[cuda13] == 0.10.0
pyomp == 0.5.1
nanobind == 2.12.0
pybind11 == 3.0.4

# CuPy and CUDA kernels (notebooks 00-02, 10-12: ported accelerated-python exercises)
# CuPy and CUDA kernels (notebooks 00-05: ported accelerated-python exercises)
cupy-cuda13x == 13.6.0
numba-cuda[cu13] == 0.28.2
cuda-cccl[test-cu13] == 0.4.5

# NVIDIA developer tools (notebooks 10-12: Nsight Systems / Nsight Compute profiling)
# NVIDIA developer tools (notebooks 03-05: Nsight Systems / Nsight Compute profiling)
nvtx == 0.2.14
nsightful[notebook] @ git+https://github.com/brycelelbach/nsightful.git@454dfa5124ebea193f64302058b327f2034ccd8e

# Distributed computing (notebook 03: mpi4py)
# Distributed computing (notebook 06: mpi4py)
mpi4py == 4.1.1

# Python/C++ Interop (notebook 13)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,12 +440,12 @@
"\n",
"| NB | Tool | Programming-model hook |\n",
"|---|---|---|\n",
"| 05 | **JAX** | JIT compilation + whole-loop fusion offloaded to device |\n",
"| 06 | **PyOMP** | OpenMP parallelisation model in Python |\n",
"| 07 | **nanobind** | Handwritten Python bindings for compiled C++ kernels |\n",
"| 08 | **CppJIT** | JIT compiled C++ with automatic bindings |\n",
"| 08 | **JAX** | JIT compilation + whole-loop fusion offloaded to device |\n",
"| 09 | **PyOMP** | OpenMP parallelisation model in Python |\n",
"| 10 | **nanobind** | Handwritten Python bindings for compiled C++ kernels |\n",
"| 11 | **CppJIT** | JIT compiled C++ with automatic bindings |\n",
"\n",
"We end with `09__swe__synthesis.ipynb`: a decision matrix and the achieved-throughput plot across the different notebooks in `timings.json`."
"We end with `12__swe__synthesis.ipynb`: a decision matrix and the achieved-throughput plot across the different notebooks in `timings.json`."
]
},
{
Expand All @@ -455,7 +455,7 @@
"source": [
"### <a id=\"sec10\"></a>10. How to read these notebooks\n",
"\n",
"Each numbered exercise (05-08) comes as two files:\n",
"Each numbered exercise (08-11) comes as two files:\n",
"\n",
"- `NN__topic__subtopic.ipynb`: the primary notebook we run live during the tutorial, with `# TODO:` cells whose body is a `...` placeholder.\n",
"- `solutions/NN__topic__subtopic__SOLUTION.ipynb`: notebooks complete with solution, for self-paced review.\n",
Expand All @@ -465,7 +465,7 @@
"- A **Quick Docs** sub-block precedes each TODO cell, listing the key APIs you need.\n",
"- Optional **`# BONUS TASK:`** cells explore deeper solutions if you have time.\n",
"\n",
"With the NumPy baseline in hand, let's continue with JAX: `05__swe__jax.ipynb`"
"With the NumPy baseline in hand, let's continue with JAX: `08__swe__jax.ipynb`"
]
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
"source": [
"### <a id=\"sec2\"></a>2. The step as a pure function\n",
"\n",
"Let's look at the same operation shape as notebook 04, expressed in JAX:\n",
"Let's look at the same operation shape as notebook 07, expressed in JAX:\n",
"\n",
"- **Read** — `h[:-1]`, `h[1:]` for interface states, same as NumPy-style slicing.\n",
"- **Compute** — Rusanov formula unchanged: `F_h = 0.5*(huL+huR) - 0.5*a*(hR-hL)`.\n",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@
"- Thread scaling works (section 5), and the kernel handles any `N`\n",
" with no recompile (section 6).\n",
"\n",
"Next: `07__swe__nanobind.ipynb` drops into C++. We compile a\n",
"Next: `10__swe__nanobind.ipynb` drops into C++. We compile a\n",
"hand-written kernel and call it from Python through a binding library.\n"
]
}
Expand Down
Loading
Loading