kernel-lens 1.3.0__tar.gz → 2.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/PKG-INFO +43 -10
  2. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/README.md +38 -5
  3. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/__init__.py +1 -1
  4. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/backends/builder.py +15 -0
  5. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/backends/trt_gen.py +86 -41
  6. kernel_lens-2.0.1/kernel_lens/backends/trt_v3_gen.py +571 -0
  7. kernel_lens-2.0.1/kernel_lens/compiler/ast_analyzer.py +300 -0
  8. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/compiler/core.py +21 -3
  9. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/runtime/engine.py +7 -3
  10. kernel_lens-2.0.1/kernel_lens/utils/env_check.py +265 -0
  11. kernel_lens-2.0.1/kernel_lens/utils/trt_headers.py +199 -0
  12. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens.egg-info/PKG-INFO +43 -10
  13. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens.egg-info/SOURCES.txt +2 -0
  14. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens.egg-info/requires.txt +4 -4
  15. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/pyproject.toml +10 -3
  16. kernel_lens-1.3.0/kernel_lens/compiler/ast_analyzer.py +0 -179
  17. kernel_lens-1.3.0/kernel_lens/utils/env_check.py +0 -107
  18. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/LICENSE +0 -0
  19. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/backends/__init__.py +0 -0
  20. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/backends/ort_gen.py +0 -0
  21. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/compiler/__init__.py +0 -0
  22. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/compiler/interaction.py +0 -0
  23. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/compiler/manifest.py +0 -0
  24. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/compiler/onnx_exporter.py +0 -0
  25. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/compiler/tracer.py +0 -0
  26. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/config.py +0 -0
  27. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/include/tensorrt/NvInfer.h +0 -0
  28. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/include/tensorrt/NvInferImpl.h +0 -0
  29. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/include/tensorrt/NvInferLegacyDims.h +0 -0
  30. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/include/tensorrt/NvInferPlugin.h +0 -0
  31. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/include/tensorrt/NvInferPluginBase.h +0 -0
  32. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/include/tensorrt/NvInferPluginUtils.h +0 -0
  33. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/include/tensorrt/NvInferRuntime.h +0 -0
  34. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/include/tensorrt/NvInferRuntimeBase.h +0 -0
  35. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/include/tensorrt/NvInferRuntimeCommon.h +0 -0
  36. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/include/tensorrt/NvInferRuntimePlugin.h +0 -0
  37. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/include/tensorrt/NvInferVersion.h +0 -0
  38. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/runtime/__init__.py +0 -0
  39. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/utils/__init__.py +0 -0
  40. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens/utils/deployment.py +0 -0
  41. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens.egg-info/dependency_links.txt +0 -0
  42. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/kernel_lens.egg-info/top_level.txt +0 -0
  43. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/setup.cfg +0 -0
  44. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_alignment_guard.py +0 -0
  45. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_architectural_fixes.py +0 -0
  46. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_conformance.py +0 -0
  47. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_edge_cases.py +0 -0
  48. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_fp8_gemm.py +0 -0
  49. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_fused_cross_entropy.py +0 -0
  50. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_fused_residual_rms.py +0 -0
  51. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_inplace.py +0 -0
  52. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_inplace_dtypes.py +0 -0
  53. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_int4_dequant_gemm.py +0 -0
  54. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_mamba_selective_scan.py +0 -0
  55. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_research_kernels.py +0 -0
  56. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_standalone.py +0 -0
  57. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_standalone_launch.py +0 -0
  58. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_standalone_ptx.py +0 -0
  59. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_tricky_triton_kernels.py +0 -0
  60. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_triton_vs_torch_compile.py +0 -0
  61. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_trt.py +0 -0
  62. {kernel_lens-1.3.0 → kernel_lens-2.0.1}/tests/test_unit_cpu.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kernel-lens
3
- Version: 1.3.0
3
+ Version: 2.0.1
4
4
  Summary: Compile PyTorch models with custom @triton.jit kernels into ONNX Runtime and TensorRT C++ plugins
5
5
  Author-email: Justin Duc <justin.duc@galiad-research.com>
6
6
  License: MIT License
@@ -52,12 +52,12 @@ Requires-Dist: onnx>=1.15.0
52
52
  Provides-Extra: ort
53
53
  Requires-Dist: onnxruntime-gpu>=1.17.0; extra == "ort"
54
54
  Provides-Extra: trt
55
- Requires-Dist: tensorrt<11.0.0,>=8.6.0; extra == "trt"
56
- Requires-Dist: tensorrt-cu12-libs<11.0.0; extra == "trt"
55
+ Requires-Dist: tensorrt<12.0.0,>=8.6.0; extra == "trt"
56
+ Requires-Dist: tensorrt-cu12-libs; extra == "trt"
57
57
  Provides-Extra: all
58
58
  Requires-Dist: onnxruntime-gpu>=1.17.0; extra == "all"
59
- Requires-Dist: tensorrt<11.0.0,>=8.6.0; extra == "all"
60
- Requires-Dist: tensorrt-cu12-libs<11.0.0; extra == "all"
59
+ Requires-Dist: tensorrt<12.0.0,>=8.6.0; extra == "all"
60
+ Requires-Dist: tensorrt-cu12-libs; extra == "all"
61
61
  Provides-Extra: bench
62
62
  Requires-Dist: transformers>=4.40.0; extra == "bench"
63
63
  Dynamic: license-file
@@ -86,7 +86,8 @@ Dynamic: license-file
86
86
 
87
87
  **KernelLens** compiles a PyTorch model that contains custom `@triton.jit` kernels
88
88
  into native C++ artifacts for **ONNX Runtime** (`OrtCustomOp`) and **NVIDIA
89
- TensorRT 10.x** (`nvinfer1::IPluginV2DynamicExt`). You write Triton in Python; it
89
+ TensorRT 8.6 to 11** (`nvinfer1::IPluginV2DynamicExt`, and `nvinfer1::IPluginV3`
90
+ on TensorRT 10 and later). You write Triton in Python; it
90
91
  emits the C++ plugin, builds the `.so`, and runs it with **zero-copy VRAM
91
92
  binding** — no manual C++ and no Python in the serving path.
92
93
 
@@ -114,6 +115,12 @@ compiled_model.run(inputs, backend="onnx"|"tensorrt")
114
115
  - **Dynamic grids in C++** — launch-grid expressions are transpiled to C++
115
116
  integer math over runtime shapes, so one plugin serves dynamic batch and
116
117
  sequence lengths.
118
+ - **One package, several TensorRT versions** — the plugin interface is chosen
119
+ from the environment. TensorRT 10 deprecated the whole `IPluginV2*` hierarchy
120
+ and TensorRT 11 removed it, so `plugin_api="auto"` (the default) emits
121
+ `IPluginV3` plugins where the runtime supports them and `IPluginV2DynamicExt`
122
+ plugins otherwise. This spans TensorRT 8.6 through 10.x today; TensorRT 11+
123
+ works when you point `TENSORRT_INCLUDE_DIR` at matching headers.
117
124
  - **Shape-generic engines** — `kl.compile(..., dynamic_shapes=True)` exports the
118
125
  leading dimension as a symbolic axis, so a single engine serves any size in a
119
126
  declared range via a TensorRT optimization profile. Verified on Blackwell
@@ -139,9 +146,12 @@ compiled_model.run(inputs, backend="onnx"|"tensorrt")
139
146
  > conformance patterns and the quantized GEMMs, on both backends; two
140
147
  > multi-operator fusions land just above zero and are reported as such. Keeping
141
148
  > the kernel pays when the baseline leaves the graph unfused and breaks even when
142
- > it already fuses. The TensorRT-LLM backend is design-only (see
143
- > [`docs/assets/data/a100/trtllm_backend_design.md`](docs/assets/data/a100/trtllm_backend_design.md)),
144
- > and the quantized GEMMs are validated on ONNX Runtime only. Full methodology
149
+ > it already fuses. A TensorRT-LLM backend is out of scope; the
150
+ > [design note](docs/assets/data/a100/trtllm_backend_design.md) records what
151
+ > integrating one would take. The kernels themselves are usable there — they are
152
+ > ordinary `@triton.jit` functions, and an A100 measurement confirmed a KernelLens
153
+ > RMSNorm is bit-identical to the flashinfer kernel TensorRT-LLM already uses
154
+ > (`0.00e+00`). The quantized GEMMs are validated on ONNX Runtime only. Full methodology
145
155
  > and every raw JSON are under [`docs/assets/data/`](docs/assets/data/).
146
156
 
147
157
  ## Installation
@@ -157,11 +167,34 @@ pip install kernel-lens[all] # both
157
167
  Triton ≥ 2.1, and `nvcc` + `g++` on `PATH`. TensorRT must be `< 11` (the
158
168
  generator emits `IPluginV2DynamicExt`).
159
169
 
170
+ **TensorRT versions.** Handled automatically. The pip TensorRT wheels ship **no
171
+ headers**, so KernelLens fetches the set matching the installed runtime from the
172
+ TensorRT OSS repository and caches it under `~/.kernel_lens_headers/<major>.<minor>`;
173
+ when the headers it already has match the runtime major, nothing is fetched. If
174
+ the download is unavailable the fallback is the bundled set, and a
175
+ header/runtime major mismatch is then reported instead of crashing inside
176
+ TensorRT. `plugin_api="auto"` picks the interface from the runtime:
177
+
178
+ | TensorRT | `IPluginV2*` | `IPluginV3` | emitted |
179
+ | :--- | :--- | :--- | :--- |
180
+ | < 10 (8.6, 9.x) | present | absent | `v2` |
181
+ | 10.x | deprecated | present | `v3` |
182
+ | 11+ | **removed** | present | `v3` |
183
+
184
+ Verified on TensorRT 10.16 and 11.3, both 16/16 on the conformance suite. Force
185
+ a choice with `plugin_api="v2"` / `"v3"`, or the `KERNEL_LENS_PLUGIN_API`
186
+ environment variable. To supply headers yourself — offline installs, or a TensorRT
187
+ build the OSS repository does not track — set `TENSORRT_INCLUDE_DIR`, or
188
+ `KERNEL_LENS_FETCH_HEADERS=0` to disable fetching entirely.
189
+
160
190
  **Environment:** `KERNEL_LENS_CACHE_DIR` (put it on a persistent volume so the
161
191
  `.so` / `.engine` artifacts survive `kl.load`), `KERNEL_LENS_CCBIN` (host
162
192
  compiler for `nvcc` — CUDA toolkits before 12.9 reject GCC 13's exception
163
193
  specifiers, so set it to `g++-12` there), `KERNEL_LENS_DEBUG` (or `KL_VERBOSE`),
164
- `TENSORRT_INCLUDE_DIR`, and `KERNEL_LENS_STREAM_READER=1` to deserialize engines
194
+ `TENSORRT_INCLUDE_DIR` (override the TensorRT headers),
195
+ `KERNEL_LENS_HEADER_CACHE` (where fetched TensorRT headers are kept),
196
+ `KERNEL_LENS_FETCH_HEADERS=0` (disable fetching),
197
+ `KERNEL_LENS_PLUGIN_API` (`auto`, `v2` or `v3`), and `KERNEL_LENS_STREAM_READER=1` to deserialize engines
165
198
  above 2 GB from disk rather than from a memory buffer (opt-in; see the
166
199
  [changelog](CHANGELOG.md)).
167
200
 
@@ -22,7 +22,8 @@
22
22
 
23
23
  **KernelLens** compiles a PyTorch model that contains custom `@triton.jit` kernels
24
24
  into native C++ artifacts for **ONNX Runtime** (`OrtCustomOp`) and **NVIDIA
25
- TensorRT 10.x** (`nvinfer1::IPluginV2DynamicExt`). You write Triton in Python; it
25
+ TensorRT 8.6 to 11** (`nvinfer1::IPluginV2DynamicExt`, and `nvinfer1::IPluginV3`
26
+ on TensorRT 10 and later). You write Triton in Python; it
26
27
  emits the C++ plugin, builds the `.so`, and runs it with **zero-copy VRAM
27
28
  binding** — no manual C++ and no Python in the serving path.
28
29
 
@@ -50,6 +51,12 @@ compiled_model.run(inputs, backend="onnx"|"tensorrt")
50
51
  - **Dynamic grids in C++** — launch-grid expressions are transpiled to C++
51
52
  integer math over runtime shapes, so one plugin serves dynamic batch and
52
53
  sequence lengths.
54
+ - **One package, several TensorRT versions** — the plugin interface is chosen
55
+ from the environment. TensorRT 10 deprecated the whole `IPluginV2*` hierarchy
56
+ and TensorRT 11 removed it, so `plugin_api="auto"` (the default) emits
57
+ `IPluginV3` plugins where the runtime supports them and `IPluginV2DynamicExt`
58
+ plugins otherwise. This spans TensorRT 8.6 through 10.x today; TensorRT 11+
59
+ works when you point `TENSORRT_INCLUDE_DIR` at matching headers.
53
60
  - **Shape-generic engines** — `kl.compile(..., dynamic_shapes=True)` exports the
54
61
  leading dimension as a symbolic axis, so a single engine serves any size in a
55
62
  declared range via a TensorRT optimization profile. Verified on Blackwell
@@ -75,9 +82,12 @@ compiled_model.run(inputs, backend="onnx"|"tensorrt")
75
82
  > conformance patterns and the quantized GEMMs, on both backends; two
76
83
  > multi-operator fusions land just above zero and are reported as such. Keeping
77
84
  > the kernel pays when the baseline leaves the graph unfused and breaks even when
78
- > it already fuses. The TensorRT-LLM backend is design-only (see
79
- > [`docs/assets/data/a100/trtllm_backend_design.md`](docs/assets/data/a100/trtllm_backend_design.md)),
80
- > and the quantized GEMMs are validated on ONNX Runtime only. Full methodology
85
+ > it already fuses. A TensorRT-LLM backend is out of scope; the
86
+ > [design note](docs/assets/data/a100/trtllm_backend_design.md) records what
87
+ > integrating one would take. The kernels themselves are usable there — they are
88
+ > ordinary `@triton.jit` functions, and an A100 measurement confirmed a KernelLens
89
+ > RMSNorm is bit-identical to the flashinfer kernel TensorRT-LLM already uses
90
+ > (`0.00e+00`). The quantized GEMMs are validated on ONNX Runtime only. Full methodology
81
91
  > and every raw JSON are under [`docs/assets/data/`](docs/assets/data/).
82
92
 
83
93
  ## Installation
@@ -93,11 +103,34 @@ pip install kernel-lens[all] # both
93
103
  Triton ≥ 2.1, and `nvcc` + `g++` on `PATH`. TensorRT must be `< 11` (the
94
104
  generator emits `IPluginV2DynamicExt`).
95
105
 
106
+ **TensorRT versions.** Handled automatically. The pip TensorRT wheels ship **no
107
+ headers**, so KernelLens fetches the set matching the installed runtime from the
108
+ TensorRT OSS repository and caches it under `~/.kernel_lens_headers/<major>.<minor>`;
109
+ when the headers it already has match the runtime major, nothing is fetched. If
110
+ the download is unavailable the fallback is the bundled set, and a
111
+ header/runtime major mismatch is then reported instead of crashing inside
112
+ TensorRT. `plugin_api="auto"` picks the interface from the runtime:
113
+
114
+ | TensorRT | `IPluginV2*` | `IPluginV3` | emitted |
115
+ | :--- | :--- | :--- | :--- |
116
+ | < 10 (8.6, 9.x) | present | absent | `v2` |
117
+ | 10.x | deprecated | present | `v3` |
118
+ | 11+ | **removed** | present | `v3` |
119
+
120
+ Verified on TensorRT 10.16 and 11.3, both 16/16 on the conformance suite. Force
121
+ a choice with `plugin_api="v2"` / `"v3"`, or the `KERNEL_LENS_PLUGIN_API`
122
+ environment variable. To supply headers yourself — offline installs, or a TensorRT
123
+ build the OSS repository does not track — set `TENSORRT_INCLUDE_DIR`, or
124
+ `KERNEL_LENS_FETCH_HEADERS=0` to disable fetching entirely.
125
+
96
126
  **Environment:** `KERNEL_LENS_CACHE_DIR` (put it on a persistent volume so the
97
127
  `.so` / `.engine` artifacts survive `kl.load`), `KERNEL_LENS_CCBIN` (host
98
128
  compiler for `nvcc` — CUDA toolkits before 12.9 reject GCC 13's exception
99
129
  specifiers, so set it to `g++-12` there), `KERNEL_LENS_DEBUG` (or `KL_VERBOSE`),
100
- `TENSORRT_INCLUDE_DIR`, and `KERNEL_LENS_STREAM_READER=1` to deserialize engines
130
+ `TENSORRT_INCLUDE_DIR` (override the TensorRT headers),
131
+ `KERNEL_LENS_HEADER_CACHE` (where fetched TensorRT headers are kept),
132
+ `KERNEL_LENS_FETCH_HEADERS=0` (disable fetching),
133
+ `KERNEL_LENS_PLUGIN_API` (`auto`, `v2` or `v3`), and `KERNEL_LENS_STREAM_READER=1` to deserialize engines
101
134
  above 2 GB from disk rather than from a memory buffer (opt-in; see the
102
135
  [changelog](CHANGELOG.md)).
103
136
 
@@ -7,7 +7,7 @@ from .config import set_verbose, is_verbose
7
7
 
8
8
 
9
9
 
10
- __version__ = "1.3.0"
10
+ __version__ = "2.0.0"
11
11
 
12
12
  __all__ = [
13
13
  "compile",
@@ -249,6 +249,21 @@ def build_trt_plugin(trt_plugins_dir: str, cache_dir: str):
249
249
  arch_flag = "-gencode=arch=compute_75,code=sm_75"
250
250
 
251
251
  trt_inc_dirs = []
252
+
253
+ # Headers matching the installed TensorRT, fetched and cached on first
254
+ # use when the bundled set is a different major version. See
255
+ # utils/trt_headers.py for why this is necessary: the pip TensorRT
256
+ # wheels ship no headers at all.
257
+ try:
258
+ from ..utils.trt_headers import resolve as _resolve_headers
259
+ _hdr_dir, _hdr_reason = _resolve_headers()
260
+ from ..config import debug_print as _dp
261
+ _dp(f"[KernelLens] TensorRT headers: {_hdr_dir or 'bundled'} ({_hdr_reason})")
262
+ if _hdr_dir:
263
+ trt_inc_dirs.append(_hdr_dir)
264
+ except Exception:
265
+ pass
266
+
252
267
  if os.environ.get("TENSORRT_INCLUDE_DIR"):
253
268
  trt_inc_dirs.append(os.environ["TENSORRT_INCLUDE_DIR"])
254
269
  user_trt_inc = os.path.expanduser("~/tensorrt_headers")
@@ -28,37 +28,31 @@ class TensorRTPluginGenerator:
28
28
  self.plugin_namespace = plugin_namespace
29
29
  self.plugin_version = plugin_version
30
30
 
31
- def _generate_kernel_h(self, manifest: KernelManifest) -> str:
32
- plugin_name = f"{manifest.kernel_name}Plugin"
33
-
34
- constant_decls = []
35
- for arg in manifest.arguments:
36
- if arg.kind == 'scalar':
37
- ctype = "float" if isinstance(arg.value, float) else "int"
38
- constant_decls.append(f"{ctype} m_{arg.name};")
39
- dynamic_members_cpp = "\n ".join(constant_decls)
40
-
41
- def get_trt_datatype(dtype_obj):
42
- dtype_str = str(dtype_obj).lower()
43
- if 'float8' in dtype_str or 'fp8' in dtype_str or 'e4m3' in dtype_str or 'e5m2' in dtype_str:
44
- return "nvinfer1::DataType::kFP8"
45
- elif 'bool' in dtype_str:
46
- return "nvinfer1::DataType::kBOOL"
47
- elif 'uint8' in dtype_str or 'int8' in dtype_str or 'int4' in dtype_str or 'uint4' in dtype_str:
48
- return "nvinfer1::DataType::kINT8"
49
- elif 'bfloat16' in dtype_str or 'bf16' in dtype_str:
50
- return "nvinfer1::DataType::kBF16"
51
- elif 'float16' in dtype_str or 'half' in dtype_str:
52
- return "nvinfer1::DataType::kHALF"
53
- elif 'float' in dtype_str:
54
- return "nvinfer1::DataType::kFLOAT"
55
- elif 'int64' in dtype_str or 'long' in dtype_str:
56
- return "nvinfer1::DataType::kINT64"
57
- elif 'int' in dtype_str:
58
- return "nvinfer1::DataType::kINT32"
59
- else:
60
- return "nvinfer1::DataType::kFLOAT"
61
-
31
+ @staticmethod
32
+ def trt_datatype(dtype_obj: str) -> str:
33
+ """Map a torch dtype onto the TensorRT DataType."""
34
+ dtype_str = str(dtype_obj).lower()
35
+ if 'float8' in dtype_str or 'fp8' in dtype_str or 'e4m3' in dtype_str or 'e5m2' in dtype_str:
36
+ return "nvinfer1::DataType::kFP8"
37
+ elif 'bool' in dtype_str:
38
+ return "nvinfer1::DataType::kBOOL"
39
+ elif 'uint8' in dtype_str or 'int8' in dtype_str or 'int4' in dtype_str or 'uint4' in dtype_str:
40
+ return "nvinfer1::DataType::kINT8"
41
+ elif 'bfloat16' in dtype_str or 'bf16' in dtype_str:
42
+ return "nvinfer1::DataType::kBF16"
43
+ elif 'float16' in dtype_str or 'half' in dtype_str:
44
+ return "nvinfer1::DataType::kHALF"
45
+ elif 'float' in dtype_str:
46
+ return "nvinfer1::DataType::kFLOAT"
47
+ elif 'int64' in dtype_str or 'long' in dtype_str:
48
+ return "nvinfer1::DataType::kINT64"
49
+ elif 'int' in dtype_str:
50
+ return "nvinfer1::DataType::kINT32"
51
+ else:
52
+ return "nvinfer1::DataType::kFLOAT"
53
+ @staticmethod
54
+ def supports_format_body(manifest: KernelManifest, tensor_prefix: str = "") -> str:
55
+ """The supportsFormatCombination body, shared by both plugin emitters."""
62
56
  in_args = [a for a in manifest.arguments if a.kind in ('input', 'inplace')]
63
57
 
64
58
  # Enforce the dtype the kernel was compiled for, position by position.
@@ -67,7 +61,7 @@ class TensorRTPluginGenerator:
67
61
  _ordered_in = [a for a in manifest.arguments if a.kind in ('input', 'inplace')]
68
62
  _ordered_sc = [a for a in manifest.arguments if a.kind == 'scalar' and not getattr(a, 'is_constexpr', False)]
69
63
  _ordered_out = [a for a in manifest.arguments if a.kind in ('output', 'inplace')]
70
- _pos_types = [get_trt_datatype(a.dtype) for a in (_ordered_in + _ordered_sc + _ordered_out)]
64
+ _pos_types = [TensorRTPluginGenerator.trt_datatype(a.dtype) for a in (_ordered_in + _ordered_sc + _ordered_out)]
71
65
  _pos_is_tensor = ([True] * len(_ordered_in) + [False] * len(_ordered_sc) + [True] * len(_ordered_out))
72
66
  _types_cpp = ", ".join(_pos_types) if _pos_types else "nvinfer1::DataType::kFLOAT"
73
67
  _is_tensor_cpp = ", ".join("true" if t else "false" for t in _pos_is_tensor) if _pos_is_tensor else "true"
@@ -96,7 +90,24 @@ class TensorRTPluginGenerator:
96
90
  )
97
91
  else:
98
92
  supports_format_cxx = type_guard_cxx + "return inOut[pos].format == nvinfer1::TensorFormat::kLINEAR;"
99
-
93
+ # IPluginV3 hands supportsFormatCombination a DynamicPluginTensorDesc,
94
+ # whose fields live under .desc; V2 hands it a PluginTensorDesc directly.
95
+ if tensor_prefix:
96
+ supports_format_cxx = supports_format_cxx.replace("inOut[pos].", f"inOut[pos]{tensor_prefix}.")
97
+ return supports_format_cxx
98
+
99
+ def _generate_kernel_h(self, manifest: KernelManifest) -> str:
100
+ plugin_name = f"{manifest.kernel_name}Plugin"
101
+
102
+ constant_decls = []
103
+ for arg in manifest.arguments:
104
+ if arg.kind == 'scalar':
105
+ ctype = "float" if isinstance(arg.value, float) else "int"
106
+ constant_decls.append(f"{ctype} m_{arg.name};")
107
+ dynamic_members_cpp = "\n ".join(constant_decls)
108
+
109
+ get_trt_datatype = TensorRTPluginGenerator.trt_datatype
110
+ supports_format_cxx = TensorRTPluginGenerator.supports_format_body(manifest)
100
111
  output_dim_cases = []
101
112
  out_args = [a for a in manifest.arguments if a.kind in ('output', 'inplace')]
102
113
  _dyn_axes = tuple(getattr(manifest, "dynamic_axes", ()) or ())
@@ -217,12 +228,15 @@ private:
217
228
  '''
218
229
  return textwrap.dedent(tpl).strip()
219
230
 
220
- def _generate_kernel_cu(self, manifest: KernelManifest) -> str:
221
- plugin_name = f"{manifest.kernel_name}Plugin"
222
- ptx_str = manifest.ptx
223
- ptx_encoded = json.dumps(ptx_str)
224
- block_size = (manifest.num_warps if manifest.num_warps > 0 else 4) * 32
225
-
231
+ @staticmethod
232
+ def build_shared_body(manifest: KernelManifest, block_size: int):
233
+ """Build the pieces the enqueue implementation needs.
234
+
235
+ Shared verbatim between the IPluginV2DynamicExt and the
236
+ IPluginV3 emitters: the PTX entry name, the kernelParams
237
+ assembly and the output-type dispatch are the same; only the
238
+ class hierarchy and the method signatures around them differ.
239
+ """
226
240
  scalars = [arg for arg in manifest.arguments if arg.kind == 'scalar']
227
241
  nb_outputs = sum(1 for arg in manifest.arguments if arg.kind == 'output')
228
242
  nb_outputs = max(1, nb_outputs)
@@ -388,10 +402,41 @@ private:
388
402
 
389
403
  output_type_lines.append(f"if (index == {i}) return {trt_type};")
390
404
 
391
- dynamic_output_types = "\n ".join(output_type_lines)
405
+ return {
406
+ "ptx_entry_name": ptx_entry_name,
407
+ "dynamic_args_cpp": "\n ".join(arg_setup_lines),
408
+ "dynamic_output_types": "\n ".join(output_type_lines),
409
+ "grid_x_cxx": grid_x_cxx,
410
+ "grid_y_cxx": grid_y_cxx,
411
+ "grid_z_cxx": grid_z_cxx,
412
+ "num_ptx_slots": num_ptx_slots,
413
+ "init_str": init_str,
414
+ "size_additions": size_additions,
415
+ "deserialize_cpp": deserialize_cpp,
416
+ "serialize_cpp": serialize_cpp,
417
+ "clone_cpp": clone_cpp,
418
+ }
392
419
 
393
- dynamic_args_cpp = "\n ".join(arg_setup_lines)
420
+ def _generate_kernel_cu(self, manifest: KernelManifest) -> str:
421
+ plugin_name = f"{manifest.kernel_name}Plugin"
422
+ ptx_str = manifest.ptx
423
+ ptx_encoded = json.dumps(ptx_str)
424
+ block_size = (manifest.num_warps if manifest.num_warps > 0 else 4) * 32
394
425
 
426
+ shared = TensorRTPluginGenerator.build_shared_body(manifest, block_size)
427
+ ptx_entry_name = shared["ptx_entry_name"]
428
+ dynamic_args_cpp = shared["dynamic_args_cpp"]
429
+ dynamic_output_types = shared["dynamic_output_types"]
430
+ grid_x_cxx = shared["grid_x_cxx"]
431
+ grid_y_cxx = shared["grid_y_cxx"]
432
+ grid_z_cxx = shared["grid_z_cxx"]
433
+ num_ptx_slots = shared["num_ptx_slots"]
434
+ init_str = shared["init_str"]
435
+ size_additions = shared["size_additions"]
436
+ deserialize_cpp = shared["deserialize_cpp"]
437
+ serialize_cpp = shared["serialize_cpp"]
438
+ clone_cpp = shared["clone_cpp"]
439
+
395
440
  tpl = f'''
396
441
  #include "{manifest.kernel_name}Plugin.h"
397
442
  #include <cuda.h>