Skip to content

build: 📦 use nanobind 3 in split mode - #243

Merged
robertodr merged 12 commits into
mainfrom
chore-deps-update-nanobind
Aug 24, 2026
Merged

build: 📦 use nanobind 3 in split mode#243
robertodr merged 12 commits into
mainfrom
chore-deps-update-nanobind

Conversation

@robertodr

@robertodr robertodr commented Aug 19, 2026

Copy link
Copy Markdown
Member

Summary

New split mode in the upcoming nanobind 3 release series promises to reduce compile times by a lot and produce more efficient wheels. This PR is to keep track of its development and flag any issues early.

Note

We might want to drop the microbenchmark on binding overhead entirely from the repo.

Changes

  • Use latest nanobind and build the Python package in split mode.

Checklist

  • Tests added or updated to cover the changes
  • Documentation updated (docstrings, docs/, CONTRIBUTING.md) if needed
  • CHANGELOG / release notes updated if applicable

AI/LLM disclosure

  • I did not use LLM tooling, or used it only privately for ideation
  • I used the following tool to help write this PR description:
  • I used the following tool to generate or modify code:

Important

By opening this PR I confirm that I have read CONTRIBUTING.md and I agree to the terms of the Contributor License Agreement.

Warning

If you're contributing on behalf of your employer, contact cla@algorithmiq.fi to arrange a Corporate CLA.

@robertodr robertodr added the test-in-draft Run CI even in Draft mode label Aug 19, 2026
@github-actions github-actions Bot added dependencies Pull requests that update a dependency file python labels Aug 19, 2026
@github-actions

Copy link
Copy Markdown

Docs preview: https://pr-243.monoprop-docs.pages.dev

@codecov

codecov Bot commented Aug 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.70%. Comparing base (ca69496) to head (121dd0e).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #243   +/-   ##
=======================================
  Coverage   97.70%   97.70%           
=======================================
  Files          14       14           
  Lines         742      742           
  Branches       98       98           
=======================================
  Hits          725      725           
  Misses         12       12           
  Partials        5        5           
Flag Coverage Δ
cpp 97.70% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

@robertodr

Copy link
Copy Markdown
Member Author

🤖 AI text below 🤖

nanobind 3 benchmark results

Benchmarked using Python 3.12.14 and Release builds on the same host. Results are the median of five interleaved runs; lower is better.

Benchmark nanobind 2 nanobind 3 With tuple_builder Total improvement
Positional dispatch 72.1 ns 47.0 ns 47.2 ns 34.6%
Keyword dispatch 113.9 ns 84.6 ns 86.2 ns 24.4%
Bound size() 41.3 ns 48.4 ns 44.6 ns -8.1%
Expectation-value functional 10.92 µs 10.45 µs 10.49 µs 4.0%
One-term conversion 9.05 µs 8.89 µs 8.82 µs 2.5%
1,024-term conversion 169.0 µs 126.4 µs 110.2 µs 34.8%

Conclusions

  • nanobind 3 reduces positional dispatch latency by 34.8% and keyword dispatch latency by 25.8% without source changes.
  • Replacing list-based tuple construction with nb::tuple_builder reduces 1,024-term conversion latency by a further 12.8%.
  • The combined improvement for 1,024-term conversion is 34.8%.
  • Functional and one-term conversion performance improve slightly.
  • The size() difference is only a few nanoseconds and is considered inconclusive due to measurement noise.

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Aug 19, 2026
@robertodr

Copy link
Copy Markdown
Member Author

Ready to go when nanobind 3 is officially stable.

@robertodr

Copy link
Copy Markdown
Member Author

PS: I don't think commit 43d61b9 adds much to our benchmarks, I'm ok with tossing it

@matteoacrossi matteoacrossi changed the title build: use latest nanobind in split mode build: use nanobind 3 in split mode Aug 20, 2026
Signed-off-by: Roberto Di Remigio Eikås <robertodr@users.noreply.github.com>
@robertodr robertodr changed the title build: use nanobind 3 in split mode build: 📦 use nanobind 3 in split mode Aug 20, 2026
robertodr and others added 3 commits August 20, 2026 14:39
Signed-off-by: Roberto Di Remigio Eikås <robertodr@users.noreply.github.com>
Signed-off-by: Roberto Di Remigio Eikås <robertodr@users.noreply.github.com>
@robertodr
robertodr marked this pull request as ready for review August 22, 2026 07:45
matteoacrossi
matteoacrossi previously approved these changes Aug 23, 2026
@matteoacrossi

Copy link
Copy Markdown
Member

PS: I don't think commit 43d61b9 adds much to our benchmarks, I'm ok with tossing it

I would toss it but I can leave with it.

@robertodr
robertodr merged commit 8ba1554 into main Aug 24, 2026
30 checks passed
@robertodr
robertodr deleted the chore-deps-update-nanobind branch August 24, 2026 07:45
@sonarqubecloud

Copy link
Copy Markdown

robertodr added a commit that referenced this pull request Sep 1, 2026
🤖 _AI text below_ 🤖

Adds a Nix flake so Nix/NixOS users can build and hack on monoprop
without installing the C++ toolchain, hwloc, Boost or MPI by hand.

Stacked on #314 — this branch is rebased onto
`chore-mpi4py-build-req-dynamically` and should merge after it.

## Outputs

| Command | What it gives you |
| --- | --- |
| `nix develop` | dev shell: GCC 15, CMake, Ninja, Boost, hwloc, Open
MPI, `uv`, `just`, Node.js, clang-tools, gdb, lcov, doxygen |
| `nix build .#monoprop` | the Python package, without MPI |
| `nix build .#monoprop-mpi` | the same package with
`monoprop_ENABLE_MPI=ON` |
| `nix run` | a Python interpreter with `monoprop` importable |

Inside `nix develop`, the existing `uv sync` and `just` workflows apply
unchanged. The shell sets `UV_PYTHON_PREFERENCE=only-system` (uv's
managed interpreters expect a loader NixOS does not provide, and
`[tool.uv]` pins `only-managed`) and `LD_LIBRARY_PATH` so manylinux
wheels resolve `libstdc++`.

## Blocker: the packages do not currently build

`nix build .#monoprop` and `.#monoprop-mpi` both fail in
`pypaBuildPhase` with `Unmet dependencies`: #243 pinned
`nanobind==3.0.0` and added `nanobind-backend>=1.0.0` to `[build-system]
requires`, but nixpkgs ships nanobind 2.13.0 and has no
`nanobind-backend` at all. This predates the rebase — it arrived in this
branch through its last `Merge branch 'main'` and the validation below
was never re-run against it. The flake needs the same kind of override
it already applies to scikit-build-core before this can merge. The dev
shell is unaffected.

## Deviations from the `uv` build

All in `nix/monoprop.nix` and documented in the building guide:

- C++ unit tests are off — they resolve msgpack-cxx through a CPM git
fetch that the build sandbox denies. Build them from the dev shell
instead.
- `monoprop_ENABLE_ARCH_FLAGS` is off, since a store path may be
substituted onto a machine other than the one that built it. `.override
{ enableArchFlags = true; }` restores `-march=native`.
- The version is pinned, because setuptools-scm cannot read git metadata
inside the sandbox. **It needs bumping alongside the release tag.**
- MPI is enabled by setting the CMake option directly rather than
through #314's `monoprop_ENABLE_MPI` environment switch, because that
switch also appends mpi4py to `build.requires` — a PyPI resolution the
sandbox denies. The store copy of mpi4py is supplied as a build input of
`monoprop-mpi` only.

## Notes for reviewers

- nixpkgs ships scikit-build-core 1.0.2 while `[build-system] requires`
asks for `>=1.0.3`, so the flake overrides it with the 1.0.3 PyPI sdist.
That override should be dropped once nixpkgs catches up.
- `tools/generate-dispatch.py` reads `.github/license-header.txt` during
`cmake --install`, but `.github` is in `sdist.exclude`. The flake works
around it by including that one file in the source set; an sdist-based
install would presumably hit the same failure.

## Validation

On `x86_64-linux`, **before #243 landed**: `nix build .#monoprop` and
`.#monoprop-mpi` both compiled and passed the import check, `nix flake
check` passed, `nix run` evaluated a `MajoranaOperator`, and `uv sync`
inside `nix develop` built the bindings against the Nix toolchain. All
of that needs re-running once the nanobind override is in. Darwin and
`aarch64-linux` are exposed via `flake-utils.lib.eachDefaultSystem` but
untested.

---------

Signed-off-by: Roberto Di Remigio Eikås <robertodr@users.noreply.github.com>
Co-authored-by: Roberto Di Remigio Eikås <robertodr@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation python test-in-draft Run CI even in Draft mode

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants