Repository navigation
Migrate DeepGEMM off of pybind11 and on to TORCH_LIBRARY - #15
Merged
Harry-Chen merged 13 commits intoOct 6, 2026
Merged
Harry-Chen merged 13 commits into
Harry-Chen merged 13 commits into
Conversation
cleonard530
force-pushed
the
migrate_pybind_to_torch_library_dev
branch
2 times, most recently
from
September 24, 2026 12:59
dec2595 to
66d8928
Compare
… branch. Will need to figure out how to handle DeepJIT. Signed-off-by: Chris Leonard <chleonar@redhat.com> Co-authored-by: codex
…nd for GIL release. We will need to come back and address this later Signed-off-by: Chris Leonard <chleonar@redhat.com> Co-authored-by: codex
…eplacing _C with _C_extension Signed-off-by: Chris Leonard <chleonar@redhat.com> Co-authored-by: codex
…hon_api.cpp like it was before, added some checks to mega_moe.hpp to keep the new registration inline with the pybind registration. Signed-off-by: Chris Leonard <chleonar@redhat.com> Co-authored-by: codex
Signed-off-by: Chris Leonard <chleonar@redhat.com> Co-authored-by: codex
Signed-off-by: Chris Leonard <chleonar@redhat.com> Co-authored-by: codex
…hpp to disable to gil.hpp in DeepJIT, this is just temporary and will need to be changed upstream Signed-off-by: Chris Leonard <chleonar@redhat.com> Co-authored-by: codex
…of doing it itslef (requires changes to DeepJIT) Signed-off-by: Chris Leonard <chleonar@redhat.com> Co-authored-by: codex
Co-authored-by: codex Signed-off-by: Chris Leonard <chleonar@redhat.com>
…mpatibility facade. Co-authored-by: codex Signed-off-by: Chris Leonard <chleonar@redhat.com>
cleonard530
force-pushed
the
migrate_pybind_to_torch_library_dev
branch
from
September 28, 2026 23:15
27cc188 to
496fd0b
Compare
Signed-off-by: Chris Leonard <chleonar@redhat.com> Co-authored-by: codex
cleonard530
commented
Sep 29, 2026
Comment on lines
+23
to
+27
| // Preserve the opaque runtime handle exposed by DeepJIT's former Python binding. | ||
| struct JitRuntimeHandle : torch::CustomClassHolder { | ||
| std::shared_ptr<deep_jit::Runtime<deep_jit::CUDA>> value; | ||
| JitRuntimeHandle() : value(jit.get()) {} | ||
| }; |
Author
There was a problem hiding this comment.
DeepJIT's Python binding exposed no Runtime methods, so this opaque handle preserves the old get_jit() API's observable behavior, but does not preserve custom-class identity.
Co-authored-by: codex Signed-off-by: Chris Leonard <chleonar@redhat.com>
…setup.py Co-authored-by: codex Signed-off-by: Chris Leonard <chleonar@redhat.com>
cleonard530
force-pushed
the
migrate_pybind_to_torch_library_dev
branch
from
September 30, 2026 12:27
9560d13 to
45d9a65
Compare
cleonard530
marked this pull request as ready for review
September 30, 2026 12:30
Harry-Chen
approved these changes
Oct 6, 2026
zyongye
pushed a commit
that referenced
this pull request
Oct 10, 2026
Register every op through TORCH_LIBRARY instead of pybind11, and keep the existing Python API through a deep_gemm._C facade that loads the _C_extension library and forwards to torch.ops.deep_gemm. Parameter names match the former pybind registrations, and the NVFP4 MegaMoE API moves over too. Build the extension against the CPython limited API (cp310-abi3, Python >= 3.10), drop the pybind11 and torch_python dependencies and the private cxx11 ABI query from CMake and setup.py, and disable DeepJIT's own GIL release with DJ_DISABLE_GIL. DeepJIT is bumped to its stable ABI integration. Squashed from: - 29597d6 migrating DeepGEMM off of pybind and onto TORCH_LIBRARY - 2884a57 removed the stable CPython dependency because DeepJIT still uses pybind for GIL release - b5dbde8 moved CMakeLists.txt to be back inline with the original file - 3d47b20 cleaned up some of the migration - 6aa3313 Added explicit methods to _C.py __all__ list - ca99616 changed registered parameter name to match before when it was on pybind - 2c8001e changed build to use CPython stable abi - 3d4041f updated DeepGEMM to use flag to disable DeepJIT's gil release - c7c9780 updated the newly added nvfp4 API to use torch_library instead of pybind - fa21ec9 Avoid MegaMoE layout serialization round trips and document the _C compatibility facade - 056a881 added min python version 3.10 to setup.py - 364da78 Update DeepJIT stable ABI integration - 45d9a65 removed pybind and unstable cxx_abi references in CMakeLists.txt and setup.py Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Migrates DeepGEMM's C++ extension from pybind11 (
PYBIND11_MODULE+ per-headerregister_apis) toTORCH_LIBRARY/TORCH_LIBRARY_IMPLregistration. Ops are now registered astorch.ops.deep_gemm.*.To preserve the existing Python API (
import deep_gemm; deep_gemm._C.fp8_gemm_nt(...)), a newdeep_gemm/_C.pyshim loads the extension and re-exports the legacy surface. The compiled module is renamed todeep_gemm._C_extension.Updates
.pyistub generation to readTORCH_LIBRARYschemas fromcsrc/and overlay defaults/types from_C.py.JitRuntimeHandleincsrc/python_api.cpppreserves the existing_C.get_jit()API throughTORCH_LIBRARY. It wraps the existing DeepJIT runtime’s shared pointer in atorch::CustomClassHolder, allowing the dispatcher to return it as a registered custom class. It does not create a new runtime or change kernel execution.ABI3 note: This migration does not yet enable the stable CPython ABI (abi3) because DeepJIT still uses pybind11 to release the GIL. Since calls through torch.ops already release the GIL, DeepJIT’s GIL handling can be disabled for this integration, removing the remaining pybind11 dependency and allowing abi3 packaging to be restored.working around the non ABI3 stable CPython was becomming difficult upstream on vllm, so I updated the build to use CPython stable abi. This added a preprocessor macro defined
DJ_DISABLE_GILwhich is used on my DeepJIT branch deepseek-ai/DeepJIT#11 to not pull in pybind11 and disables the gil release.WARNING:
Before,
get_symm_buffer_size_for_mega_moereturned anintand afunction(std::tuple<int64_t, std::function...>) butTORCH_LIBRARYdoesn't allow returning function objects/closures. Now, it returns anintand the computed buffer layout as anint[](std::tuple<int64_t, c10::List<int64_t>>), and a separate function,_slice_symm_buffer_for_mega_moe, consumes thatint[]instead of the closure. The_C.pywrapper reconstructs the callback, preserving the existingget_symm_buffer_size_for_mega_moeAPI and backwards compatibility.New files
deep_gemm/_C.py
Python compatibility shim for the old
deep_gemm._Cmodule. Responsibilities:torch.ops.load_library(...)on_C_extension*.soat import timeRe-export
torch.ops.deep_gemm.*under the legacy_CnamesRestore pybind-era conveniences that are not expressible in
TORCH_LIBRARYschemas alone: tuple unpacking (q/kv/(weight, scale)pairs), default arguments.Previously
_Cwas the compiled.soitself; now_Cis pure Python and the.sois_C_extension.csrc/torch_library_utils.hpp
(namespace
deep_gemm::torch_utils) Conversion helpers for bridging PyTorch schema types to the C++ types the existing kernel implementations expect — e.g.c10::List<int64_t>→std::tuple<int,int,int>forrecipe/head_splits, and optional list →std::vector<int>. Without this, everyTORCH_LIBRARYwrapper would duplicate the same list/tuple parsing logic.csrc/utils/registration.h
Defines the REGISTER_EXTENSION(NAME) macro used by csrc/python_api.cpp. Under TORCH_LIBRARY, ops self-register via static initializers when the .so loads, so there's no real pybind11 module to build — this macro just emits an empty PyInit_ function so the compiled .so still satisfies Python's import machinery (which requires that symbol to exist).
Significantly changed files
csrc/apis/mega_moe.hpp
build_symm_buffer_layout, which centralizes the layout calculation and returns the offsets and dimensions needed to construct every symmetric-buffer view.get_symm_buffer_size_for_mega_moeserializes this layout throughto_int_list, while the Mega MoE kernel entry points deserialize it and slice the buffer through the shared C++ helper without dispatching through another registered operator. This preserves the original centralized layout calculation, including thenum_sms-dependent ring sizing.get_symm_buffer_size_for_mega_moereturned anint64_tand a C++ closure. BecauseTORCH_LIBRARYschemas cannot return closures, the registered operator now returns the byte count and serialized layout as anint[]._slice_symm_buffer_for_mega_moe(Tensor buffer, int[] layout_info)reconstructs the views. The compatibility wrapper in_C.pycaptures that layout in a Python closure, preserving the original public API. The slicing operator remains an internal implementation detail and is excluded from_C.__all__.csrc/python_api.cpp
Replaces the old
PYBIND11_MODULE(...)entry point. Each API header declares its schemas withTORCH_LIBRARY_FRAGMENTand registers implementations withTORCH_LIBRARY_IMPL; including those headers in this file instantiates their static registrations when the shared library loads. This file also owns the primaryTORCH_LIBRARY(deep_gemm, m)block, which registers theRuntimecustom class andget_jit(see comment below about python binding difference). Finally,REGISTER_EXTENSION(_C_extension)defines the minimalPyInit__C_extensionfunction needed to import the shared library as a Python extension. The Python C API is used only to create that empty module; operators and classes are registered through PyTorch’s library API.scripts/generate_pyi.py
Previously generated
.pyitype hints by regex-parsing the C++ function declarations incsrc/— but under pybind, the real Python-callable keyword names come frompy::arg("...")strings inPYBIND11_MODULE, which pybind doesn't require to match the C++ parameter names. That divergence caused real bugs: e.g.fp8_fp4_paged_mqa_logits's C++ parameter is namedfused_kv_cache, but it's bound aspy::arg("kv_cache"), so the old generated stub advertised a keyword (fused_kv_cache) that would actually raiseTypeErrorif used — the true kwarg iskv_cache. The script now parses TORCH_LIBRARY schema strings fromcsrc/and overlays defaults from an AST parse ofdeep_gemm/_C.py, so the stub is generated from the real registration contract and entry point instead of an incidental C++ signature.Test plan/Results
All test pass
Test that require Blackwell GPUs have not been tested yet. These include
and a few test in the other files.
Migration progress using the Audit Python extension torch-abi-audit:
This shows that the library is now on the CPython Stable ABI (ABI3)
Performance Benchmarks
Link to performance benchmarks: cleonard530/Benchmarks#1
The tldr; most gemm kernels stayed the same
except thethe runtime increase infp8_fp4_gemm_{nn,nt,tn,tt}kernels which had a 10-20% runtime increase (2-6 µs/call). I ran another workload with them in a vLLM-like workload. In eager mode the regression was about the same, but it disappeared with the CUDA-graph run.fp8_fp4_gemm_{nn,nt,tt}went away when the data element_size was cached.fp8_fp4_gemm_tnstill has a slight runtime regression.Updated DeepJIT to use their current commit on main (see deepseek-ai/DeepJIT@3732a3b) so that we can get on CPython stable ABI.