kernel-lens 1.2.1__tar.gz → 2.0.0__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.
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/PKG-INFO +58 -6
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/README.md +53 -1
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/__init__.py +1 -1
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/backends/builder.py +15 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/backends/ort_gen.py +55 -20
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/backends/trt_gen.py +99 -54
- kernel_lens-2.0.0/kernel_lens/backends/trt_v3_gen.py +571 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/compiler/ast_analyzer.py +54 -7
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/compiler/core.py +99 -9
- kernel_lens-2.0.0/kernel_lens/compiler/manifest.py +171 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/compiler/tracer.py +47 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/runtime/engine.py +164 -11
- kernel_lens-2.0.0/kernel_lens/utils/env_check.py +265 -0
- kernel_lens-2.0.0/kernel_lens/utils/trt_headers.py +199 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens.egg-info/PKG-INFO +58 -6
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens.egg-info/SOURCES.txt +2 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens.egg-info/requires.txt +4 -4
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/pyproject.toml +10 -3
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_conformance.py +58 -0
- kernel_lens-1.2.1/kernel_lens/compiler/manifest.py +0 -80
- kernel_lens-1.2.1/kernel_lens/utils/env_check.py +0 -107
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/LICENSE +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/backends/__init__.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/compiler/__init__.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/compiler/interaction.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/compiler/onnx_exporter.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/config.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/include/tensorrt/NvInfer.h +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/include/tensorrt/NvInferImpl.h +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/include/tensorrt/NvInferLegacyDims.h +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/include/tensorrt/NvInferPlugin.h +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/include/tensorrt/NvInferPluginBase.h +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/include/tensorrt/NvInferPluginUtils.h +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/include/tensorrt/NvInferRuntime.h +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/include/tensorrt/NvInferRuntimeBase.h +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/include/tensorrt/NvInferRuntimeCommon.h +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/include/tensorrt/NvInferRuntimePlugin.h +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/include/tensorrt/NvInferVersion.h +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/runtime/__init__.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/utils/__init__.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens/utils/deployment.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens.egg-info/dependency_links.txt +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/kernel_lens.egg-info/top_level.txt +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/setup.cfg +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_alignment_guard.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_architectural_fixes.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_edge_cases.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_fp8_gemm.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_fused_cross_entropy.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_fused_residual_rms.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_inplace.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_inplace_dtypes.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_int4_dequant_gemm.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_mamba_selective_scan.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_research_kernels.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_standalone.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_standalone_launch.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_standalone_ptx.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_tricky_triton_kernels.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_triton_vs_torch_compile.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_trt.py +0 -0
- {kernel_lens-1.2.1 → kernel_lens-2.0.0}/tests/test_unit_cpu.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kernel-lens
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
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<
|
|
56
|
-
Requires-Dist: tensorrt-cu12-libs
|
|
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<
|
|
60
|
-
Requires-Dist: tensorrt-cu12-libs
|
|
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
|
|
@@ -114,6 +114,18 @@ compiled_model.run(inputs, backend="onnx"|"tensorrt")
|
|
|
114
114
|
- **Dynamic grids in C++** — launch-grid expressions are transpiled to C++
|
|
115
115
|
integer math over runtime shapes, so one plugin serves dynamic batch and
|
|
116
116
|
sequence lengths.
|
|
117
|
+
- **One package, several TensorRT versions** — the plugin interface is chosen
|
|
118
|
+
from the environment. TensorRT 10 deprecated the whole `IPluginV2*` hierarchy
|
|
119
|
+
and TensorRT 11 removed it, so `plugin_api="auto"` (the default) emits
|
|
120
|
+
`IPluginV3` plugins where the runtime supports them and `IPluginV2DynamicExt`
|
|
121
|
+
plugins otherwise. This spans TensorRT 8.6 through 10.x today; TensorRT 11+
|
|
122
|
+
works when you point `TENSORRT_INCLUDE_DIR` at matching headers.
|
|
123
|
+
- **Shape-generic engines** — `kl.compile(..., dynamic_shapes=True)` exports the
|
|
124
|
+
leading dimension as a symbolic axis, so a single engine serves any size in a
|
|
125
|
+
declared range via a TensorRT optimization profile. Verified on Blackwell
|
|
126
|
+
(`sm_120a`) and Ampere (`sm_80`): one compile at batch 8 serving batches
|
|
127
|
+
1-16, bit-exact on both engines. Off by default, because a shape-specialised
|
|
128
|
+
engine is what the published benchmarks measure.
|
|
117
129
|
- **Zero-copy VRAM binding** — PyTorch `data_ptr()` values are registered
|
|
118
130
|
directly with each engine; no host staging copies.
|
|
119
131
|
- **Blackwell PTX ISA clamping** — a Triton-generated `.version 9.3` header is
|
|
@@ -151,11 +163,34 @@ pip install kernel-lens[all] # both
|
|
|
151
163
|
Triton ≥ 2.1, and `nvcc` + `g++` on `PATH`. TensorRT must be `< 11` (the
|
|
152
164
|
generator emits `IPluginV2DynamicExt`).
|
|
153
165
|
|
|
166
|
+
**TensorRT versions.** Handled automatically. The pip TensorRT wheels ship **no
|
|
167
|
+
headers**, so KernelLens fetches the set matching the installed runtime from the
|
|
168
|
+
TensorRT OSS repository and caches it under `~/.kernel_lens_headers/<major>.<minor>`;
|
|
169
|
+
when the headers it already has match the runtime major, nothing is fetched. If
|
|
170
|
+
the download is unavailable the fallback is the bundled set, and a
|
|
171
|
+
header/runtime major mismatch is then reported instead of crashing inside
|
|
172
|
+
TensorRT. `plugin_api="auto"` picks the interface from the runtime:
|
|
173
|
+
|
|
174
|
+
| TensorRT | `IPluginV2*` | `IPluginV3` | emitted |
|
|
175
|
+
| :--- | :--- | :--- | :--- |
|
|
176
|
+
| < 10 (8.6, 9.x) | present | absent | `v2` |
|
|
177
|
+
| 10.x | deprecated | present | `v3` |
|
|
178
|
+
| 11+ | **removed** | present | `v3` |
|
|
179
|
+
|
|
180
|
+
Verified on TensorRT 10.16 and 11.3, both 16/16 on the conformance suite. Force
|
|
181
|
+
a choice with `plugin_api="v2"` / `"v3"`, or the `KERNEL_LENS_PLUGIN_API`
|
|
182
|
+
environment variable. To supply headers yourself — offline installs, or a TensorRT
|
|
183
|
+
build the OSS repository does not track — set `TENSORRT_INCLUDE_DIR`, or
|
|
184
|
+
`KERNEL_LENS_FETCH_HEADERS=0` to disable fetching entirely.
|
|
185
|
+
|
|
154
186
|
**Environment:** `KERNEL_LENS_CACHE_DIR` (put it on a persistent volume so the
|
|
155
187
|
`.so` / `.engine` artifacts survive `kl.load`), `KERNEL_LENS_CCBIN` (host
|
|
156
188
|
compiler for `nvcc` — CUDA toolkits before 12.9 reject GCC 13's exception
|
|
157
189
|
specifiers, so set it to `g++-12` there), `KERNEL_LENS_DEBUG` (or `KL_VERBOSE`),
|
|
158
|
-
`TENSORRT_INCLUDE_DIR
|
|
190
|
+
`TENSORRT_INCLUDE_DIR` (override the TensorRT headers),
|
|
191
|
+
`KERNEL_LENS_HEADER_CACHE` (where fetched TensorRT headers are kept),
|
|
192
|
+
`KERNEL_LENS_FETCH_HEADERS=0` (disable fetching),
|
|
193
|
+
`KERNEL_LENS_PLUGIN_API` (`auto`, `v2` or `v3`), and `KERNEL_LENS_STREAM_READER=1` to deserialize engines
|
|
159
194
|
above 2 GB from disk rather than from a memory buffer (opt-in; see the
|
|
160
195
|
[changelog](CHANGELOG.md)).
|
|
161
196
|
|
|
@@ -196,6 +231,13 @@ compiled = kl.compile(RMSNorm(4096).cuda(), (x,), name="llama3_rmsnorm",
|
|
|
196
231
|
backends=["onnx", "tensorrt"])
|
|
197
232
|
out_ort = compiled.run((x,), backend="onnx")
|
|
198
233
|
out_trt = compiled.run((x,), backend="tensorrt")
|
|
234
|
+
|
|
235
|
+
# One engine for any batch: mark the leading dim dynamic. dynamic_max bounds
|
|
236
|
+
# the optimization profile (default 4x the traced size).
|
|
237
|
+
serving = kl.compile(RMSNorm(4096).cuda(), (x,), name="llama3_rmsnorm_dyn",
|
|
238
|
+
backends=["onnx", "tensorrt"], dynamic_shapes=True)
|
|
239
|
+
for b in (1, 2, 4, 8, 16): # all through the engine built at b=4
|
|
240
|
+
serving.run((torch.randn(b, 512, 4096, device="cuda"),), backend="tensorrt")
|
|
199
241
|
```
|
|
200
242
|
|
|
201
243
|
## Results at a glance
|
|
@@ -212,6 +254,16 @@ and every raw JSON are on the
|
|
|
212
254
|
it replaces is **1,137 lines across six files** for one fused RMSNorm kernel on
|
|
213
255
|
both backends, measured with `tests/measure_codegen.py`.
|
|
214
256
|
|
|
257
|
+
**One engine, many shapes.** With `dynamic_shapes=True` a single compiled engine
|
|
258
|
+
serves any leading-dimension size in range. Measured with
|
|
259
|
+
`tests/test_conformance.py`, which compiles once and then runs every shape through
|
|
260
|
+
that engine — `0.00e+00` on both backends, on Blackwell and on Ampere:
|
|
261
|
+
|
|
262
|
+
| Case | Compiled at | Served |
|
|
263
|
+
| :--- | :--- | :--- |
|
|
264
|
+
| `dynamic_batch_sweep` | batch 8 | batches 1, 2, 4, 8, 16 |
|
|
265
|
+
| `dynamic_grid_sweep` | 524,288 elements | 65,536 / 131,072 / 524,288 / 1,048,576 |
|
|
266
|
+
|
|
215
267
|
**Real pretrained models.** Every decoder `LayerNorm` of a real OPT checkpoint
|
|
216
268
|
(125M → 6.7B) replaced by the Triton RMSNorm kernel, graded against
|
|
217
269
|
`torch.compile` — the baseline that *captures the same Triton kernels* rather
|
|
@@ -50,6 +50,18 @@ compiled_model.run(inputs, backend="onnx"|"tensorrt")
|
|
|
50
50
|
- **Dynamic grids in C++** — launch-grid expressions are transpiled to C++
|
|
51
51
|
integer math over runtime shapes, so one plugin serves dynamic batch and
|
|
52
52
|
sequence lengths.
|
|
53
|
+
- **One package, several TensorRT versions** — the plugin interface is chosen
|
|
54
|
+
from the environment. TensorRT 10 deprecated the whole `IPluginV2*` hierarchy
|
|
55
|
+
and TensorRT 11 removed it, so `plugin_api="auto"` (the default) emits
|
|
56
|
+
`IPluginV3` plugins where the runtime supports them and `IPluginV2DynamicExt`
|
|
57
|
+
plugins otherwise. This spans TensorRT 8.6 through 10.x today; TensorRT 11+
|
|
58
|
+
works when you point `TENSORRT_INCLUDE_DIR` at matching headers.
|
|
59
|
+
- **Shape-generic engines** — `kl.compile(..., dynamic_shapes=True)` exports the
|
|
60
|
+
leading dimension as a symbolic axis, so a single engine serves any size in a
|
|
61
|
+
declared range via a TensorRT optimization profile. Verified on Blackwell
|
|
62
|
+
(`sm_120a`) and Ampere (`sm_80`): one compile at batch 8 serving batches
|
|
63
|
+
1-16, bit-exact on both engines. Off by default, because a shape-specialised
|
|
64
|
+
engine is what the published benchmarks measure.
|
|
53
65
|
- **Zero-copy VRAM binding** — PyTorch `data_ptr()` values are registered
|
|
54
66
|
directly with each engine; no host staging copies.
|
|
55
67
|
- **Blackwell PTX ISA clamping** — a Triton-generated `.version 9.3` header is
|
|
@@ -87,11 +99,34 @@ pip install kernel-lens[all] # both
|
|
|
87
99
|
Triton ≥ 2.1, and `nvcc` + `g++` on `PATH`. TensorRT must be `< 11` (the
|
|
88
100
|
generator emits `IPluginV2DynamicExt`).
|
|
89
101
|
|
|
102
|
+
**TensorRT versions.** Handled automatically. The pip TensorRT wheels ship **no
|
|
103
|
+
headers**, so KernelLens fetches the set matching the installed runtime from the
|
|
104
|
+
TensorRT OSS repository and caches it under `~/.kernel_lens_headers/<major>.<minor>`;
|
|
105
|
+
when the headers it already has match the runtime major, nothing is fetched. If
|
|
106
|
+
the download is unavailable the fallback is the bundled set, and a
|
|
107
|
+
header/runtime major mismatch is then reported instead of crashing inside
|
|
108
|
+
TensorRT. `plugin_api="auto"` picks the interface from the runtime:
|
|
109
|
+
|
|
110
|
+
| TensorRT | `IPluginV2*` | `IPluginV3` | emitted |
|
|
111
|
+
| :--- | :--- | :--- | :--- |
|
|
112
|
+
| < 10 (8.6, 9.x) | present | absent | `v2` |
|
|
113
|
+
| 10.x | deprecated | present | `v3` |
|
|
114
|
+
| 11+ | **removed** | present | `v3` |
|
|
115
|
+
|
|
116
|
+
Verified on TensorRT 10.16 and 11.3, both 16/16 on the conformance suite. Force
|
|
117
|
+
a choice with `plugin_api="v2"` / `"v3"`, or the `KERNEL_LENS_PLUGIN_API`
|
|
118
|
+
environment variable. To supply headers yourself — offline installs, or a TensorRT
|
|
119
|
+
build the OSS repository does not track — set `TENSORRT_INCLUDE_DIR`, or
|
|
120
|
+
`KERNEL_LENS_FETCH_HEADERS=0` to disable fetching entirely.
|
|
121
|
+
|
|
90
122
|
**Environment:** `KERNEL_LENS_CACHE_DIR` (put it on a persistent volume so the
|
|
91
123
|
`.so` / `.engine` artifacts survive `kl.load`), `KERNEL_LENS_CCBIN` (host
|
|
92
124
|
compiler for `nvcc` — CUDA toolkits before 12.9 reject GCC 13's exception
|
|
93
125
|
specifiers, so set it to `g++-12` there), `KERNEL_LENS_DEBUG` (or `KL_VERBOSE`),
|
|
94
|
-
`TENSORRT_INCLUDE_DIR
|
|
126
|
+
`TENSORRT_INCLUDE_DIR` (override the TensorRT headers),
|
|
127
|
+
`KERNEL_LENS_HEADER_CACHE` (where fetched TensorRT headers are kept),
|
|
128
|
+
`KERNEL_LENS_FETCH_HEADERS=0` (disable fetching),
|
|
129
|
+
`KERNEL_LENS_PLUGIN_API` (`auto`, `v2` or `v3`), and `KERNEL_LENS_STREAM_READER=1` to deserialize engines
|
|
95
130
|
above 2 GB from disk rather than from a memory buffer (opt-in; see the
|
|
96
131
|
[changelog](CHANGELOG.md)).
|
|
97
132
|
|
|
@@ -132,6 +167,13 @@ compiled = kl.compile(RMSNorm(4096).cuda(), (x,), name="llama3_rmsnorm",
|
|
|
132
167
|
backends=["onnx", "tensorrt"])
|
|
133
168
|
out_ort = compiled.run((x,), backend="onnx")
|
|
134
169
|
out_trt = compiled.run((x,), backend="tensorrt")
|
|
170
|
+
|
|
171
|
+
# One engine for any batch: mark the leading dim dynamic. dynamic_max bounds
|
|
172
|
+
# the optimization profile (default 4x the traced size).
|
|
173
|
+
serving = kl.compile(RMSNorm(4096).cuda(), (x,), name="llama3_rmsnorm_dyn",
|
|
174
|
+
backends=["onnx", "tensorrt"], dynamic_shapes=True)
|
|
175
|
+
for b in (1, 2, 4, 8, 16): # all through the engine built at b=4
|
|
176
|
+
serving.run((torch.randn(b, 512, 4096, device="cuda"),), backend="tensorrt")
|
|
135
177
|
```
|
|
136
178
|
|
|
137
179
|
## Results at a glance
|
|
@@ -148,6 +190,16 @@ and every raw JSON are on the
|
|
|
148
190
|
it replaces is **1,137 lines across six files** for one fused RMSNorm kernel on
|
|
149
191
|
both backends, measured with `tests/measure_codegen.py`.
|
|
150
192
|
|
|
193
|
+
**One engine, many shapes.** With `dynamic_shapes=True` a single compiled engine
|
|
194
|
+
serves any leading-dimension size in range. Measured with
|
|
195
|
+
`tests/test_conformance.py`, which compiles once and then runs every shape through
|
|
196
|
+
that engine — `0.00e+00` on both backends, on Blackwell and on Ampere:
|
|
197
|
+
|
|
198
|
+
| Case | Compiled at | Served |
|
|
199
|
+
| :--- | :--- | :--- |
|
|
200
|
+
| `dynamic_batch_sweep` | batch 8 | batches 1, 2, 4, 8, 16 |
|
|
201
|
+
| `dynamic_grid_sweep` | 524,288 elements | 65,536 / 131,072 / 524,288 / 1,048,576 |
|
|
202
|
+
|
|
151
203
|
**Real pretrained models.** Every decoder `LayerNorm` of a real OPT checkpoint
|
|
152
204
|
(125M → 6.7B) replaced by the Triton RMSNorm kernel, graded against
|
|
153
205
|
`torch.compile` — the baseline that *captures the same Triton kernels* rather
|
|
@@ -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")
|
|
@@ -150,31 +150,26 @@ struct {op_name} : Ort::CustomOpBase<{op_name}, {kernel_name}> {{
|
|
|
150
150
|
arg_setup_lines.append("auto ref_in = ctx.GetInput(0);")
|
|
151
151
|
arg_setup_lines.append("auto info = ref_in.GetTensorTypeAndShapeInfo();")
|
|
152
152
|
arg_setup_lines.append("std::vector<int64_t> dim_values = info.GetShape();")
|
|
153
|
+
|
|
154
|
+
# Dims the caller asked to keep dynamic: read them from the tensor that
|
|
155
|
+
# is actually being run, not from the traced shape.
|
|
156
|
+
_dyn_axes = tuple(getattr(manifest, "dynamic_axes", ()) or ())
|
|
153
157
|
|
|
154
158
|
import re
|
|
155
159
|
fn_match = re.search(r'\.entry\s+([a-zA-Z0-9_]+)', manifest.ptx)
|
|
156
160
|
ptx_entry_name = fn_match.group(1) if fn_match else manifest.kernel_name
|
|
157
161
|
|
|
158
|
-
# ---
|
|
159
|
-
grid_strs =
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
expr = str(g.node.expr) if hasattr(g, 'node') else str(g)
|
|
163
|
-
expr = re.sub(r'([a-zA-Z0-9_]+)\*\*([a-zA-Z0-9_]+)', r'std::pow(\1, \2)', expr)
|
|
164
|
-
expr = expr.replace("//", "/")
|
|
165
|
-
expr = re.sub(r'floor\((.*?)\)', r'(\1)', expr)
|
|
166
|
-
|
|
167
|
-
# Replace any s(\d+) symbol dynamically using regex
|
|
168
|
-
expr = re.sub(r'\bs(\d+)\b', r"(int64_t)(dim_values.size() > \1 ? dim_values[\1] : 1)", expr)
|
|
169
|
-
grid_strs.append(expr)
|
|
170
|
-
|
|
162
|
+
# --- GRID EVALUATION, from the manifest's own symbol translation ---
|
|
163
|
+
grid_strs = manifest.grid_exprs(
|
|
164
|
+
lambda i: f"(int64_t)(dim_values.size() > {i} ? dim_values[{i}] : 1)"
|
|
165
|
+
)
|
|
171
166
|
while len(grid_strs) < 3:
|
|
172
167
|
grid_strs.append("1")
|
|
173
168
|
|
|
174
169
|
grid_eval_lines = [
|
|
175
170
|
f"unsigned int grid_x = std::max(1u, (unsigned int)({grid_strs[0]}));",
|
|
176
171
|
f"unsigned int grid_y = std::max(1u, (unsigned int)({grid_strs[1]}));",
|
|
177
|
-
f"unsigned int grid_z = std::max(1u, (unsigned int)({grid_strs[2]}));"
|
|
172
|
+
f"unsigned int grid_z = std::max(1u, (unsigned int)({grid_strs[2]}));",
|
|
178
173
|
]
|
|
179
174
|
|
|
180
175
|
entry_match = re.search(r'\.entry\s+[a-zA-Z0-9_]+\s*\((.*?)\)\s*(?:\.reqntid|\{)', manifest.ptx, re.DOTALL)
|
|
@@ -215,6 +210,23 @@ struct {op_name} : Ort::CustomOpBase<{op_name}, {kernel_name}> {{
|
|
|
215
210
|
|
|
216
211
|
ptx_ordered_slots.append({"type": c_type, "ident": str(param_num), "is_ptr": is_ptr, "decl": p_decl, "param_num": param_num})
|
|
217
212
|
|
|
213
|
+
# The node's inputs, in the order ONNX Runtime presents them. This is
|
|
214
|
+
# the same list GetInputTypeCount() reports, so indexing into it is
|
|
215
|
+
# authoritative. A running counter over manifest.arguments is not: any
|
|
216
|
+
# drift between the two silently points a scalar read at the wrong
|
|
217
|
+
# slot, and the kernel then masks against a garbage element count.
|
|
218
|
+
inputs_to_node = [
|
|
219
|
+
a for a in manifest.arguments
|
|
220
|
+
if (a.kind in ('input', 'inplace')
|
|
221
|
+
or (a.kind == 'scalar' and not getattr(a, 'is_constexpr', False)))
|
|
222
|
+
]
|
|
223
|
+
|
|
224
|
+
def _node_input_index(a, fallback):
|
|
225
|
+
for k, cand in enumerate(inputs_to_node):
|
|
226
|
+
if cand is a:
|
|
227
|
+
return k
|
|
228
|
+
return fallback
|
|
229
|
+
|
|
218
230
|
arg_setup_lines.append("// Extract inputs/outputs/scalars from ORT context")
|
|
219
231
|
onnx_input_counter = 0
|
|
220
232
|
ort_output_counter = 0
|
|
@@ -227,7 +239,7 @@ struct {op_name} : Ort::CustomOpBase<{op_name}, {kernel_name}> {{
|
|
|
227
239
|
if _esz == 0.5
|
|
228
240
|
else f"(in_tensor_{slot_idx}.GetTensorTypeAndShapeInfo().GetElementCount() * {int(_esz)})"
|
|
229
241
|
)
|
|
230
|
-
arg_setup_lines.append(f"auto in_tensor_{slot_idx} = ctx.GetInput({onnx_input_counter});")
|
|
242
|
+
arg_setup_lines.append(f"auto in_tensor_{slot_idx} = ctx.GetInput({_node_input_index(arg, onnx_input_counter)});")
|
|
231
243
|
arg_setup_lines.append(f"static thread_local const void* arg_ptr_{slot_idx};")
|
|
232
244
|
arg_setup_lines.append(f"const void* raw_ptr_{slot_idx} = (const void*)in_tensor_{slot_idx}.GetTensorData<uint8_t>();")
|
|
233
245
|
arg_setup_lines.append(f"static thread_local void* align_buf_{slot_idx} = nullptr;")
|
|
@@ -242,6 +254,9 @@ struct {op_name} : Ort::CustomOpBase<{op_name}, {kernel_name}> {{
|
|
|
242
254
|
elif arg.kind == 'output':
|
|
243
255
|
out_dim_exprs = []
|
|
244
256
|
for dim_idx, d in enumerate(arg.shape):
|
|
257
|
+
if dim_idx in _dyn_axes:
|
|
258
|
+
out_dim_exprs.append(f"(int64_t)(dim_values.size() > {dim_idx} ? dim_values[{dim_idx}] : 1)")
|
|
259
|
+
continue
|
|
245
260
|
try:
|
|
246
261
|
d_int = int(d)
|
|
247
262
|
out_dim_exprs.append(str(d_int))
|
|
@@ -257,6 +272,9 @@ struct {op_name} : Ort::CustomOpBase<{op_name}, {kernel_name}> {{
|
|
|
257
272
|
elif arg.kind == 'inplace':
|
|
258
273
|
out_dim_exprs = []
|
|
259
274
|
for dim_idx, d in enumerate(arg.shape):
|
|
275
|
+
if dim_idx in _dyn_axes:
|
|
276
|
+
out_dim_exprs.append(f"(int64_t)(dim_values.size() > {dim_idx} ? dim_values[{dim_idx}] : 1)")
|
|
277
|
+
continue
|
|
260
278
|
try:
|
|
261
279
|
d_int = int(d)
|
|
262
280
|
out_dim_exprs.append(str(d_int))
|
|
@@ -264,7 +282,7 @@ struct {op_name} : Ort::CustomOpBase<{op_name}, {kernel_name}> {{
|
|
|
264
282
|
out_dim_exprs.append(f"(int64_t)(dim_values.size() > {dim_idx} ? dim_values[{dim_idx}] : 1)")
|
|
265
283
|
out_shape_str = "{" + ", ".join(out_dim_exprs) + "}" if out_dim_exprs else "dim_values"
|
|
266
284
|
|
|
267
|
-
arg_setup_lines.append(f"auto in_tensor_{slot_idx} = ctx.GetInput({onnx_input_counter});")
|
|
285
|
+
arg_setup_lines.append(f"auto in_tensor_{slot_idx} = ctx.GetInput({_node_input_index(arg, onnx_input_counter)});")
|
|
268
286
|
arg_setup_lines.append(f"std::vector<int64_t> out_dims_{ort_output_counter} = {out_shape_str};")
|
|
269
287
|
arg_setup_lines.append(f"auto out_tensor_{slot_idx} = ctx.GetOutput({ort_output_counter}, out_dims_{ort_output_counter}.data(), out_dims_{ort_output_counter}.size());")
|
|
270
288
|
_esz = element_size_bytes(arg.dtype)
|
|
@@ -282,16 +300,33 @@ struct {op_name} : Ort::CustomOpBase<{op_name}, {kernel_name}> {{
|
|
|
282
300
|
onnx_input_counter += 1
|
|
283
301
|
ort_output_counter += 1
|
|
284
302
|
elif arg.kind == 'scalar':
|
|
285
|
-
|
|
286
|
-
|
|
303
|
+
expr = getattr(arg, 'cxx_expr', '') or ''
|
|
304
|
+
if 'dim_values' in expr:
|
|
305
|
+
# Shape-derived (n = x.numel()): compute it from the tensor
|
|
306
|
+
# being run. The exported graph folds this scalar into a
|
|
307
|
+
# constant -- it is not a graph input -- so reading the slot
|
|
308
|
+
# would hand the kernel the element count captured while
|
|
309
|
+
# tracing, and it would then process a fraction of the
|
|
310
|
+
# tensor and leave the rest untouched.
|
|
311
|
+
arg_setup_lines.append(f"double scalar_val_{slot_idx} = (double)({expr});")
|
|
312
|
+
onnx_input_counter += 1
|
|
313
|
+
elif not getattr(arg, 'is_constexpr', False):
|
|
314
|
+
arg_setup_lines.append(f"auto scalar_tensor_{slot_idx} = ctx.GetInput({_node_input_index(arg, onnx_input_counter)});")
|
|
287
315
|
arg_setup_lines.append(f"double scalar_val_{slot_idx} = 0;")
|
|
288
316
|
arg_setup_lines.append(f"if (scalar_tensor_{slot_idx}.GetTensorTypeAndShapeInfo().GetElementType() == ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64) {{ scalar_val_{slot_idx} = (double)(scalar_tensor_{slot_idx}.GetTensorData<int64_t>()[0]); }}")
|
|
289
317
|
arg_setup_lines.append(f"else if (scalar_tensor_{slot_idx}.GetTensorTypeAndShapeInfo().GetElementType() == ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32) {{ scalar_val_{slot_idx} = (double)(scalar_tensor_{slot_idx}.GetTensorData<int32_t>()[0]); }}")
|
|
290
318
|
arg_setup_lines.append(f"else {{ scalar_val_{slot_idx} = (double)(scalar_tensor_{slot_idx}.GetTensorData<float>()[0]); }}")
|
|
291
319
|
onnx_input_counter += 1
|
|
292
320
|
else:
|
|
293
|
-
|
|
294
|
-
|
|
321
|
+
# Prefer the manifest's translated expression: for a scalar
|
|
322
|
+
# derived from shapes (n = x.numel()) that is a runtime read
|
|
323
|
+
# of the input dims; otherwise it is the baked constant.
|
|
324
|
+
expr = getattr(arg, 'cxx_expr', '') or None
|
|
325
|
+
if expr:
|
|
326
|
+
arg_setup_lines.append(f"double scalar_val_{slot_idx} = (double)({expr});")
|
|
327
|
+
else:
|
|
328
|
+
s_val = arg.value if getattr(arg, 'value', None) is not None else 0.0
|
|
329
|
+
arg_setup_lines.append(f"double scalar_val_{slot_idx} = {s_val};")
|
|
295
330
|
|
|
296
331
|
arg_setup_lines.append("static thread_local const void* null_ptr_arg = nullptr;")
|
|
297
332
|
arg_setup_lines.append("static thread_local std::vector<void*> kp;")
|
|
@@ -28,37 +28,31 @@ class TensorRTPluginGenerator:
|
|
|
28
28
|
self.plugin_namespace = plugin_namespace
|
|
29
29
|
self.plugin_version = plugin_version
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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 = [
|
|
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,14 +90,37 @@ 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')]
|
|
113
|
+
_dyn_axes = tuple(getattr(manifest, "dynamic_axes", ()) or ())
|
|
102
114
|
for out_idx, out_arg in enumerate(out_args):
|
|
103
115
|
output_dim_cases.append(f"if (outputIndex == {out_idx}) {{")
|
|
104
116
|
output_dim_cases.append(f" nvinfer1::DimsExprs res;")
|
|
105
117
|
output_dim_cases.append(f" res.nbDims = {len(out_arg.shape)};")
|
|
106
118
|
for d_idx, d in enumerate(out_arg.shape):
|
|
119
|
+
if d_idx in _dyn_axes:
|
|
120
|
+
# Declared dynamic: take the dim from the input at run time
|
|
121
|
+
# instead of freezing the traced value.
|
|
122
|
+
output_dim_cases.append(f" res.d[{d_idx}] = inputs[0].d[{d_idx}];")
|
|
123
|
+
continue
|
|
107
124
|
try:
|
|
108
125
|
d_int = int(d)
|
|
109
126
|
output_dim_cases.append(f" res.d[{d_idx}] = exprBuilder.constant({d_int});")
|
|
@@ -211,30 +228,27 @@ private:
|
|
|
211
228
|
'''
|
|
212
229
|
return textwrap.dedent(tpl).strip()
|
|
213
230
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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
|
+
"""
|
|
220
240
|
scalars = [arg for arg in manifest.arguments if arg.kind == 'scalar']
|
|
221
241
|
nb_outputs = sum(1 for arg in manifest.arguments if arg.kind == 'output')
|
|
222
242
|
nb_outputs = max(1, nb_outputs)
|
|
223
243
|
|
|
224
244
|
# --- LOCAL TRT GRID AST EVALUATION ---
|
|
225
245
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
expr = re.sub(r'floor\((.*?)\)', r'(\1)', expr)
|
|
233
|
-
|
|
234
|
-
# Replace any s(\d+) symbol dynamically using regex
|
|
235
|
-
expr = re.sub(r'\bs(\d+)\b', r"(int64_t)(inputDesc[0].dims.nbDims > \1 ? inputDesc[0].dims.d[\1] : 1)", expr)
|
|
236
|
-
grid_strs.append(expr)
|
|
237
|
-
|
|
246
|
+
_trt_dim = lambda i: f"(int64_t)(inputDesc[0].dims.nbDims > {i} ? inputDesc[0].dims.d[{i}] : 1)" # noqa: E731
|
|
247
|
+
grid_strs = manifest.grid_exprs(_trt_dim)
|
|
248
|
+
# A scalar derived from the shape (n = x.numel()) must be recomputed per
|
|
249
|
+
# enqueue from the runtime input, or the kernel masks against the traced
|
|
250
|
+
# element count and silently does half the work.
|
|
251
|
+
_scalar_exprs = manifest.scalar_exprs(_trt_dim)
|
|
238
252
|
while len(grid_strs) < 3:
|
|
239
253
|
grid_strs.append("1")
|
|
240
254
|
|
|
@@ -356,7 +370,7 @@ private:
|
|
|
356
370
|
arg_setup_lines.append(f"kernelParams[{slot_idx}] = (void*)&tmp_null_{slot_idx};")
|
|
357
371
|
else:
|
|
358
372
|
if arg and arg.kind == 'scalar':
|
|
359
|
-
expr = getattr(arg, 'cxx_expr', '') or f"m_{arg.name}"
|
|
373
|
+
expr = _scalar_exprs.get(arg.name) or getattr(arg, 'cxx_expr', '') or f"m_{arg.name}"
|
|
360
374
|
scalar_ctype = "int64_t" if "64" in str(arg.dtype) else ("float" if ("float" in str(arg.dtype) or "float" in c_type or "double" in c_type) else "int32_t")
|
|
361
375
|
arg_setup_lines.append(f"static thread_local {scalar_ctype} tmp_scalar_{slot_idx}; tmp_scalar_{slot_idx} = ({scalar_ctype})({expr});")
|
|
362
376
|
arg_setup_lines.append(f"kernelParams[{slot_idx}] = (void*)&tmp_scalar_{slot_idx};")
|
|
@@ -388,10 +402,41 @@ private:
|
|
|
388
402
|
|
|
389
403
|
output_type_lines.append(f"if (index == {i}) return {trt_type};")
|
|
390
404
|
|
|
391
|
-
|
|
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
|
-
|
|
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>
|