tensoracle 1.0.1__tar.gz → 1.2.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.
- {tensoracle-1.0.1 → tensoracle-1.2.0}/PKG-INFO +70 -7
- {tensoracle-1.0.1 → tensoracle-1.2.0}/README.md +69 -4
- tensoracle-1.2.0/docs/api/producer.md +7 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/docs/index.md +69 -4
- {tensoracle-1.0.1 → tensoracle-1.2.0}/examples/cubin_plugin/README.md +4 -4
- {tensoracle-1.0.1 → tensoracle-1.2.0}/examples/cubin_plugin/bundle/bundle.cpp +2121 -1776
- {tensoracle-1.0.1 → tensoracle-1.2.0}/examples/cubin_plugin/bundle/bundle.json +33 -33
- tensoracle-1.2.0/examples/cubin_plugin/bundle/cubins/sm120/bias.cubin +0 -0
- tensoracle-1.2.0/examples/cubin_plugin/bundle/cubins/sm120/dot.specialized.cubin +0 -0
- tensoracle-1.2.0/examples/cubin_plugin/bundle/cubins/sm120/dot.tf32-control.cubin +0 -0
- tensoracle-1.2.0/examples/cubin_plugin/bundle/cubins/sm120/dot.unspecialized.cubin +0 -0
- tensoracle-1.2.0/examples/cubin_plugin/bundle/cubins/sm120/scale.cubin +0 -0
- tensoracle-1.2.0/examples/cubin_plugin/bundle/cubins/sm86/bias.cubin +0 -0
- {tensoracle-1.0.1/examples/cubin_plugin/bundle/cubins/sm89 → tensoracle-1.2.0/examples/cubin_plugin/bundle/cubins/sm86}/dot.specialized.cubin +0 -0
- {tensoracle-1.0.1/examples/cubin_plugin/bundle/cubins/sm89 → tensoracle-1.2.0/examples/cubin_plugin/bundle/cubins/sm86}/dot.tf32-control.cubin +0 -0
- {tensoracle-1.0.1/examples/cubin_plugin/bundle/cubins/sm89 → tensoracle-1.2.0/examples/cubin_plugin/bundle/cubins/sm86}/dot.unspecialized.cubin +0 -0
- tensoracle-1.2.0/examples/cubin_plugin/bundle/cubins/sm86/scale.cubin +0 -0
- tensoracle-1.2.0/examples/cubin_plugin/bundle/cubins/sm89/bias.cubin +0 -0
- {tensoracle-1.0.1/examples/cubin_plugin/bundle/cubins/sm86 → tensoracle-1.2.0/examples/cubin_plugin/bundle/cubins/sm89}/dot.specialized.cubin +0 -0
- tensoracle-1.2.0/examples/cubin_plugin/bundle/cubins/sm89/dot.tf32-control.cubin +0 -0
- {tensoracle-1.0.1/examples/cubin_plugin/bundle/cubins/sm86 → tensoracle-1.2.0/examples/cubin_plugin/bundle/cubins/sm89}/dot.unspecialized.cubin +0 -0
- tensoracle-1.2.0/examples/cubin_plugin/bundle/cubins/sm89/scale.cubin +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/pyproject.toml +9 -5
- {tensoracle-1.0.1 → tensoracle-1.2.0}/src/tensoracle/_version.py +2 -2
- {tensoracle-1.0.1 → tensoracle-1.2.0}/src/tensoracle/bundle.py +10 -7
- {tensoracle-1.0.1 → tensoracle-1.2.0}/src/tensoracle/producer.py +11 -17
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_bundle.py +34 -1
- tensoracle-1.2.0/tests/test_cuda_graphs.py +191 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_producer.py +100 -57
- {tensoracle-1.0.1 → tensoracle-1.2.0}/uv.lock +46 -247
- tensoracle-1.0.1/docs/api/producer.md +0 -7
- tensoracle-1.0.1/examples/cubin_plugin/bundle/cubins/sm120/bias.cubin +0 -0
- tensoracle-1.0.1/examples/cubin_plugin/bundle/cubins/sm120/dot.specialized.cubin +0 -0
- tensoracle-1.0.1/examples/cubin_plugin/bundle/cubins/sm120/dot.tf32-control.cubin +0 -0
- tensoracle-1.0.1/examples/cubin_plugin/bundle/cubins/sm120/dot.unspecialized.cubin +0 -0
- tensoracle-1.0.1/examples/cubin_plugin/bundle/cubins/sm86/bias.cubin +0 -0
- tensoracle-1.0.1/examples/cubin_plugin/bundle/cubins/sm86/dot.tf32-control.cubin +0 -0
- tensoracle-1.0.1/examples/cubin_plugin/bundle/cubins/sm89/bias.cubin +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/.gitignore +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/LICENSE +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/build_backend.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/cpp/CMakeLists.txt +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/cpp/cmake/TensoracleCubinPlugin.cmake +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/cpp/include/tensoracle/cubin_plugin.hpp +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/cpp/src/cubin_plugin.cpp +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/cpp/tests/core.cpp +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/docs/api/bundle.md +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/docs/api/index.md +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/docs/cpp-python-repositories.md +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/docs/optimization.md +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/docs/precision.md +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/docs/tensorrt-sdk.md +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/examples/cubin_plugin/CMakeLists.txt +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/examples/cubin_plugin/example_cubin_plugin/__init__.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/examples/cubin_plugin/example_cubin_plugin/weights.safetensors +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/examples/cubin_plugin/kernels.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/examples/cubin_plugin/plugin.cpp +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/examples/cubin_plugin/pyproject.toml +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/mkdocs.yml +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/src/tensoracle/__init__.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/src/tensoracle/_build.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/src/tensoracle/_cache.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/src/tensoracle/_comparison.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/src/tensoracle/_execution.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/src/tensoracle/_memory.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/src/tensoracle/_plugins.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/src/tensoracle/convert.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/build_memory_runtime.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/cubin_io/check.cpp +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/cubin_io/kernels.cu +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/cubin_io/plugin.cpp +0 -0
- /tensoracle-1.0.1/examples/cubin_plugin/bundle/cubins/sm120/scale.cubin → /tensoracle-1.2.0/tests/cubins/ptxas-12.9.86/sm120.cubin +0 -0
- /tensoracle-1.0.1/examples/cubin_plugin/bundle/cubins/sm86/scale.cubin → /tensoracle-1.2.0/tests/cubins/ptxas-12.9.86/sm86.cubin +0 -0
- /tensoracle-1.0.1/examples/cubin_plugin/bundle/cubins/sm89/scale.cubin → /tensoracle-1.2.0/tests/cubins/ptxas-12.9.86/sm89.cubin +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/example_runtime.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/native/CMakeLists.txt +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/native/export.h +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/native_build.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/plugin_io_runtime.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/precision_runtime.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_build.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_build_memory.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_cache.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_cmake_plugin.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_comparison.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_convert.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_cpp_core.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_distribution.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_engine_io.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_example_plugin.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_execution.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_gpu_cache.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_plugin_io.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_plugins.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_precision.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_shape_tensor_outputs.py +0 -0
- {tensoracle-1.0.1 → tensoracle-1.2.0}/tests/test_weight_hash.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: tensoracle
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Build, save, reuse, and execute TensorRT engines from safetensors weights
|
|
5
5
|
Project-URL: documentation, https://sync-dev-org.github.io/tensoracle/
|
|
6
6
|
Project-URL: repository, https://github.com/sync-dev-org/tensoracle
|
|
@@ -24,8 +24,6 @@ Requires-Dist: tensorrt-cu13<12,>=11.0
|
|
|
24
24
|
Provides-Extra: convert
|
|
25
25
|
Requires-Dist: torch>=2.6; extra == 'convert'
|
|
26
26
|
Provides-Extra: producer
|
|
27
|
-
Requires-Dist: nvidia-cuda-cuobjdump<13.4,>=13.3.73; extra == 'producer'
|
|
28
|
-
Requires-Dist: nvidia-cuda-nvcc-cu12==12.9.86; extra == 'producer'
|
|
29
27
|
Requires-Dist: triton==3.8.0; extra == 'producer'
|
|
30
28
|
Description-Content-Type: text/markdown
|
|
31
29
|
|
|
@@ -53,8 +51,8 @@ Choose the path that matches your work:
|
|
|
53
51
|
| `tensorrt-cu13` 11.x | Open and run engines | Build and open engines | Open plugin engines |
|
|
54
52
|
| NVIDIA GPU and driver | Open and run engines | Build and run engines | Run and test engines; cubin production itself can run without a GPU |
|
|
55
53
|
| CuPy or `cuda-python` | The application chooses its buffer and stream library | The application chooses its buffer and stream library | `cuda-python` is used by the example runtime and tests, not by `tensoracle` |
|
|
56
|
-
| Triton 3.8.0
|
|
57
|
-
| CUDA toolkit | Not needed | Not needed |
|
|
54
|
+
| Triton 3.8.0 | Not needed | Not needed | Installed with `tensoracle[producer]` for cubin production |
|
|
55
|
+
| CUDA toolkit | Not needed | Not needed | Cubin production (`ptxas >=13.2,<14` and `cuobjdump`) and native plugin build |
|
|
58
56
|
| TensorRT 11 SDK | Not needed | Not needed | Native plugin build |
|
|
59
57
|
| CMake 3.20 or later and C++17 compiler | Not needed | Not needed | Native plugin build |
|
|
60
58
|
|
|
@@ -255,10 +253,75 @@ with handle.create_execution() as execution:
|
|
|
255
253
|
|
|
256
254
|
The caller selects the CUDA device and context, orders inputs written on other streams before enqueue, and keeps buffers, streams, plugin preparation resources, and the execution unit alive until completion. Use one execution unit serially; do not call it concurrently from multiple threads. Confirm completion before changing shapes or streams, reusing buffers, or closing. `close()` and context exit release the TensorRT context before the handle, without waiting, and repeated close calls do nothing. Operations on a closed unit raise `RuntimeError` before touching TensorRT. The unit does not retain caller arrays or expose its TensorRT context.
|
|
257
255
|
|
|
258
|
-
Tensoracle neither allocates or frees device buffers, copies data, nor calls stream or device synchronization. TensorRT itself may allocate internal resources or act synchronously for some networks and plugins. Execution units reject HOST-location tensors, externally supplied shape tensor values, and data-dependent output sizes at creation. Ordinary networks that compute shapes internally from input dimensions are supported.
|
|
256
|
+
Tensoracle neither allocates or frees device buffers, copies data, nor calls stream or device synchronization. TensorRT itself may allocate internal resources or act synchronously for some networks and plugins. Execution units reject HOST-location tensors, externally supplied shape tensor values, and data-dependent output sizes at creation. Ordinary networks that compute shapes internally from input dimensions are supported. Profile switching and caller-owned TensorRT workspace memory are outside this API.
|
|
259
257
|
|
|
260
258
|
Networks with outputs marked as shape tensors emit `tensoracle.ShapeTensorOutputWarning` during building and when creating an execution unit (`create_execution()` or `EngineExecution(handle)`). The warning names the affected tensors: `create_execution()` cannot handle these engines, and calling it crashes the process. Building continues by default. To stop either operation safely, turn this warning into an exception with `warnings.filterwarnings("error", category=tensoracle.ShapeTensorOutputWarning)` after importing `warnings` and `tensoracle`. Saved engines retain the shape output names outside the cache conditions; older files without these names are reused without an execution warning.
|
|
261
259
|
|
|
260
|
+
### Capture and replay with CUDA Graphs
|
|
261
|
+
|
|
262
|
+
Tensoracle supports recording one `EngineExecution.enqueue` call with CUDA stream capture and replaying the resulting graph. The application owns graph creation, recapture, and destruction; tensoracle provides no capture or replay operations.
|
|
263
|
+
|
|
264
|
+
Use a dedicated execution unit (`handle.create_execution()`) for each graph. After setting input shapes, enqueue once and wait for completion before starting capture, so TensorRT finishes deferred initialization. Capture and replay on a nondefault stream; the example uses a nonblocking stream. Keep synchronous CUDA calls and work on the legacy default stream out of capture.
|
|
265
|
+
|
|
266
|
+
The graph fixes the input shapes, tensor addresses, and execution unit. Keep the execution unit, its handle, buffers, and plugin preparation resources alive until the graph is destroyed and outstanding work has finished. To use different shapes or addresses, capture a new graph for that combination or select another graph with its own execution unit. Input contents may change at the same addresses between completed replays.
|
|
267
|
+
|
|
268
|
+
For the `features` / `result` engine above, use the `cuda(...)` helper from the preceding example:
|
|
269
|
+
|
|
270
|
+
```python
|
|
271
|
+
from contextlib import ExitStack
|
|
272
|
+
|
|
273
|
+
import numpy as np
|
|
274
|
+
import tensorrt as trt
|
|
275
|
+
from cuda.bindings import runtime as cudart
|
|
276
|
+
|
|
277
|
+
with handle.create_execution() as execution:
|
|
278
|
+
execution.set_input_shapes({"features": (1, 4, 2)})
|
|
279
|
+
# Omit set_input_shapes for fixed inputs and single-point profiles.
|
|
280
|
+
features = np.arange(8, dtype=np.float32).reshape(1, 4, 2) / 4
|
|
281
|
+
output = np.empty(
|
|
282
|
+
execution.get_tensor_shape("result"),
|
|
283
|
+
dtype=trt.nptype(execution.get_tensor_dtype("result")),
|
|
284
|
+
)
|
|
285
|
+
with ExitStack() as resources:
|
|
286
|
+
stream = cuda(cudart.cudaStreamCreateWithFlags(cudart.cudaStreamNonBlocking))
|
|
287
|
+
resources.callback(lambda: cuda(cudart.cudaStreamDestroy(stream)))
|
|
288
|
+
source = cuda(cudart.cudaMalloc(features.nbytes))
|
|
289
|
+
resources.callback(lambda: cuda(cudart.cudaFree(source)))
|
|
290
|
+
target = cuda(cudart.cudaMalloc(output.nbytes))
|
|
291
|
+
resources.callback(lambda: cuda(cudart.cudaFree(target)))
|
|
292
|
+
addresses = {"features": int(source), "result": int(target)}
|
|
293
|
+
try:
|
|
294
|
+
cuda(cudart.cudaMemcpyAsync(
|
|
295
|
+
source, features.ctypes.data, features.nbytes,
|
|
296
|
+
cudart.cudaMemcpyKind.cudaMemcpyHostToDevice, stream,
|
|
297
|
+
))
|
|
298
|
+
execution.enqueue(addresses, stream=int(stream))
|
|
299
|
+
cuda(cudart.cudaStreamSynchronize(stream)) # Warm up before capture.
|
|
300
|
+
|
|
301
|
+
cuda(cudart.cudaStreamBeginCapture(
|
|
302
|
+
stream, cudart.cudaStreamCaptureMode.cudaStreamCaptureModeThreadLocal,
|
|
303
|
+
))
|
|
304
|
+
try:
|
|
305
|
+
execution.enqueue(addresses, stream=int(stream)) # Exactly one call.
|
|
306
|
+
finally:
|
|
307
|
+
graph = cuda(cudart.cudaStreamEndCapture(stream))
|
|
308
|
+
resources.callback(lambda: cuda(cudart.cudaGraphDestroy(graph)))
|
|
309
|
+
instance = cuda(cudart.cudaGraphInstantiate(graph, 0))
|
|
310
|
+
resources.callback(lambda: cuda(cudart.cudaGraphExecDestroy(instance)))
|
|
311
|
+
|
|
312
|
+
for _ in range(3):
|
|
313
|
+
cuda(cudart.cudaGraphLaunch(instance, stream))
|
|
314
|
+
cuda(cudart.cudaMemcpyAsync(
|
|
315
|
+
output.ctypes.data, target, output.nbytes,
|
|
316
|
+
cudart.cudaMemcpyKind.cudaMemcpyDeviceToHost, stream,
|
|
317
|
+
))
|
|
318
|
+
finally:
|
|
319
|
+
# Wait before ExitStack destroys the graph and releases its buffers.
|
|
320
|
+
cuda(cudart.cudaStreamSynchronize(stream))
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Engines with loops or conditionals, or layers or plugins that synchronize with the host during inference, cannot be captured. CUDA reports capture failures through `cudaErrorStreamCapture*` errors. Always end an attempted capture and release any graph resources before falling back to ordinary `enqueue`. See [TensorRT's CUDA Graph limitations](https://docs.nvidia.com/deeplearning/tensorrt/latest/performance/optimization.html#inference-with-cuda-graphs).
|
|
324
|
+
|
|
262
325
|
## Build a cubin plugin
|
|
263
326
|
|
|
264
327
|
Follow [Prepare a TensorRT SDK](https://github.com/sync-dev-org/tensoracle/blob/main/docs/tensorrt-sdk.md) to acquire and verify the headers and native library for a build SDK, including the fixed inputs for SDK 11.2.1.2 and the `TENSORRT_ROOT` setup.
|
|
@@ -281,7 +344,7 @@ python/
|
|
|
281
344
|
|
|
282
345
|
Keep C++ sources in `cpp/`, with a CMake project that builds and runs its tests through CTest without Python. Keep the Python project, its src-layout package, and its uv environment in `python/`; run the project's uv commands from that directory. Tensoracle itself follows this layout, and the installed C++ helper paths described below remain inside its Python package.
|
|
283
346
|
|
|
284
|
-
`tensoracle.producer.compile_bundle` uses the extra's **Triton 3.8.0
|
|
347
|
+
`tensoracle.producer.compile_bundle` uses the extra's **Triton 3.8.0** with **ptxas >=13.2,<14** and **cuobjdump** from the host CUDA toolkit. It uses the toolkit directory named by `CUDA_HOME`, or `/usr/local/cuda` when `CUDA_HOME` is unset; explicit `ptxas` and `cuobjdump` paths override these defaults independently. The normal import, engine build, and engine reuse paths do not import the producer or Triton. Cubin production does not need a GPU or import torch; run it without importing torch first. The caller supplies Triton functions and `KernelSpec` records with their public argument types, compile time constants, and any divisibility assumptions. The producer writes sm86, sm89, and sm120 cubins, `bundle.json`, and a C++ translation unit that embeds exactly those cubins. The generated C++ entry records carry each public argument's order, type, count, and divisibility rule into the common launcher. It rejects an unexpected parameter ABI or nonzero scratch requirement. The included [example](https://github.com/sync-dev-org/tensoracle/blob/main/examples/cubin_plugin/README.md#rebuild-the-cubins) has the command to rebuild its cubins from a repository clone.
|
|
285
348
|
|
|
286
349
|
The wheel also contains `tensoracle/cpp/include`, `tensoracle/cpp/src`, and `tensoracle/cpp/cmake`. Pass the installed `tensoracle/cpp` directory to CMake as `TENSORACLE_CPP_ROOT` and include `TensoracleCubinPlugin.cmake`. Its `tensoracle_add_cubin_plugin` function compiles the common C++ source, the caller's plugin source, and the generated `bundle.cpp` into the caller's library. The caller implements the graph's meaning, field meanings, weight placement, launch sequence, and variant selection. The common source owns typed fields in their original order, handles `IPluginV3` lifecycle methods, checks cubin digests and resources, loads one module per CUDA context, checks the generated argument count and specialization rules, appends the two supported zero scratch pointers, and launches kernels. The caller selects a variant using `Kernel::accepts` and derives the count passed to `Kernel::launch` from its argument array. The common source releases modules and device allocations in their owning contexts. The library must export TensorRT's `getCreators`; a static registration constructor is not supported.
|
|
287
350
|
|
|
@@ -22,8 +22,8 @@ Choose the path that matches your work:
|
|
|
22
22
|
| `tensorrt-cu13` 11.x | Open and run engines | Build and open engines | Open plugin engines |
|
|
23
23
|
| NVIDIA GPU and driver | Open and run engines | Build and run engines | Run and test engines; cubin production itself can run without a GPU |
|
|
24
24
|
| CuPy or `cuda-python` | The application chooses its buffer and stream library | The application chooses its buffer and stream library | `cuda-python` is used by the example runtime and tests, not by `tensoracle` |
|
|
25
|
-
| Triton 3.8.0
|
|
26
|
-
| CUDA toolkit | Not needed | Not needed |
|
|
25
|
+
| Triton 3.8.0 | Not needed | Not needed | Installed with `tensoracle[producer]` for cubin production |
|
|
26
|
+
| CUDA toolkit | Not needed | Not needed | Cubin production (`ptxas >=13.2,<14` and `cuobjdump`) and native plugin build |
|
|
27
27
|
| TensorRT 11 SDK | Not needed | Not needed | Native plugin build |
|
|
28
28
|
| CMake 3.20 or later and C++17 compiler | Not needed | Not needed | Native plugin build |
|
|
29
29
|
|
|
@@ -224,10 +224,75 @@ with handle.create_execution() as execution:
|
|
|
224
224
|
|
|
225
225
|
The caller selects the CUDA device and context, orders inputs written on other streams before enqueue, and keeps buffers, streams, plugin preparation resources, and the execution unit alive until completion. Use one execution unit serially; do not call it concurrently from multiple threads. Confirm completion before changing shapes or streams, reusing buffers, or closing. `close()` and context exit release the TensorRT context before the handle, without waiting, and repeated close calls do nothing. Operations on a closed unit raise `RuntimeError` before touching TensorRT. The unit does not retain caller arrays or expose its TensorRT context.
|
|
226
226
|
|
|
227
|
-
Tensoracle neither allocates or frees device buffers, copies data, nor calls stream or device synchronization. TensorRT itself may allocate internal resources or act synchronously for some networks and plugins. Execution units reject HOST-location tensors, externally supplied shape tensor values, and data-dependent output sizes at creation. Ordinary networks that compute shapes internally from input dimensions are supported.
|
|
227
|
+
Tensoracle neither allocates or frees device buffers, copies data, nor calls stream or device synchronization. TensorRT itself may allocate internal resources or act synchronously for some networks and plugins. Execution units reject HOST-location tensors, externally supplied shape tensor values, and data-dependent output sizes at creation. Ordinary networks that compute shapes internally from input dimensions are supported. Profile switching and caller-owned TensorRT workspace memory are outside this API.
|
|
228
228
|
|
|
229
229
|
Networks with outputs marked as shape tensors emit `tensoracle.ShapeTensorOutputWarning` during building and when creating an execution unit (`create_execution()` or `EngineExecution(handle)`). The warning names the affected tensors: `create_execution()` cannot handle these engines, and calling it crashes the process. Building continues by default. To stop either operation safely, turn this warning into an exception with `warnings.filterwarnings("error", category=tensoracle.ShapeTensorOutputWarning)` after importing `warnings` and `tensoracle`. Saved engines retain the shape output names outside the cache conditions; older files without these names are reused without an execution warning.
|
|
230
230
|
|
|
231
|
+
### Capture and replay with CUDA Graphs
|
|
232
|
+
|
|
233
|
+
Tensoracle supports recording one `EngineExecution.enqueue` call with CUDA stream capture and replaying the resulting graph. The application owns graph creation, recapture, and destruction; tensoracle provides no capture or replay operations.
|
|
234
|
+
|
|
235
|
+
Use a dedicated execution unit (`handle.create_execution()`) for each graph. After setting input shapes, enqueue once and wait for completion before starting capture, so TensorRT finishes deferred initialization. Capture and replay on a nondefault stream; the example uses a nonblocking stream. Keep synchronous CUDA calls and work on the legacy default stream out of capture.
|
|
236
|
+
|
|
237
|
+
The graph fixes the input shapes, tensor addresses, and execution unit. Keep the execution unit, its handle, buffers, and plugin preparation resources alive until the graph is destroyed and outstanding work has finished. To use different shapes or addresses, capture a new graph for that combination or select another graph with its own execution unit. Input contents may change at the same addresses between completed replays.
|
|
238
|
+
|
|
239
|
+
For the `features` / `result` engine above, use the `cuda(...)` helper from the preceding example:
|
|
240
|
+
|
|
241
|
+
```python
|
|
242
|
+
from contextlib import ExitStack
|
|
243
|
+
|
|
244
|
+
import numpy as np
|
|
245
|
+
import tensorrt as trt
|
|
246
|
+
from cuda.bindings import runtime as cudart
|
|
247
|
+
|
|
248
|
+
with handle.create_execution() as execution:
|
|
249
|
+
execution.set_input_shapes({"features": (1, 4, 2)})
|
|
250
|
+
# Omit set_input_shapes for fixed inputs and single-point profiles.
|
|
251
|
+
features = np.arange(8, dtype=np.float32).reshape(1, 4, 2) / 4
|
|
252
|
+
output = np.empty(
|
|
253
|
+
execution.get_tensor_shape("result"),
|
|
254
|
+
dtype=trt.nptype(execution.get_tensor_dtype("result")),
|
|
255
|
+
)
|
|
256
|
+
with ExitStack() as resources:
|
|
257
|
+
stream = cuda(cudart.cudaStreamCreateWithFlags(cudart.cudaStreamNonBlocking))
|
|
258
|
+
resources.callback(lambda: cuda(cudart.cudaStreamDestroy(stream)))
|
|
259
|
+
source = cuda(cudart.cudaMalloc(features.nbytes))
|
|
260
|
+
resources.callback(lambda: cuda(cudart.cudaFree(source)))
|
|
261
|
+
target = cuda(cudart.cudaMalloc(output.nbytes))
|
|
262
|
+
resources.callback(lambda: cuda(cudart.cudaFree(target)))
|
|
263
|
+
addresses = {"features": int(source), "result": int(target)}
|
|
264
|
+
try:
|
|
265
|
+
cuda(cudart.cudaMemcpyAsync(
|
|
266
|
+
source, features.ctypes.data, features.nbytes,
|
|
267
|
+
cudart.cudaMemcpyKind.cudaMemcpyHostToDevice, stream,
|
|
268
|
+
))
|
|
269
|
+
execution.enqueue(addresses, stream=int(stream))
|
|
270
|
+
cuda(cudart.cudaStreamSynchronize(stream)) # Warm up before capture.
|
|
271
|
+
|
|
272
|
+
cuda(cudart.cudaStreamBeginCapture(
|
|
273
|
+
stream, cudart.cudaStreamCaptureMode.cudaStreamCaptureModeThreadLocal,
|
|
274
|
+
))
|
|
275
|
+
try:
|
|
276
|
+
execution.enqueue(addresses, stream=int(stream)) # Exactly one call.
|
|
277
|
+
finally:
|
|
278
|
+
graph = cuda(cudart.cudaStreamEndCapture(stream))
|
|
279
|
+
resources.callback(lambda: cuda(cudart.cudaGraphDestroy(graph)))
|
|
280
|
+
instance = cuda(cudart.cudaGraphInstantiate(graph, 0))
|
|
281
|
+
resources.callback(lambda: cuda(cudart.cudaGraphExecDestroy(instance)))
|
|
282
|
+
|
|
283
|
+
for _ in range(3):
|
|
284
|
+
cuda(cudart.cudaGraphLaunch(instance, stream))
|
|
285
|
+
cuda(cudart.cudaMemcpyAsync(
|
|
286
|
+
output.ctypes.data, target, output.nbytes,
|
|
287
|
+
cudart.cudaMemcpyKind.cudaMemcpyDeviceToHost, stream,
|
|
288
|
+
))
|
|
289
|
+
finally:
|
|
290
|
+
# Wait before ExitStack destroys the graph and releases its buffers.
|
|
291
|
+
cuda(cudart.cudaStreamSynchronize(stream))
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Engines with loops or conditionals, or layers or plugins that synchronize with the host during inference, cannot be captured. CUDA reports capture failures through `cudaErrorStreamCapture*` errors. Always end an attempted capture and release any graph resources before falling back to ordinary `enqueue`. See [TensorRT's CUDA Graph limitations](https://docs.nvidia.com/deeplearning/tensorrt/latest/performance/optimization.html#inference-with-cuda-graphs).
|
|
295
|
+
|
|
231
296
|
## Build a cubin plugin
|
|
232
297
|
|
|
233
298
|
Follow [Prepare a TensorRT SDK](https://github.com/sync-dev-org/tensoracle/blob/main/docs/tensorrt-sdk.md) to acquire and verify the headers and native library for a build SDK, including the fixed inputs for SDK 11.2.1.2 and the `TENSORRT_ROOT` setup.
|
|
@@ -250,7 +315,7 @@ python/
|
|
|
250
315
|
|
|
251
316
|
Keep C++ sources in `cpp/`, with a CMake project that builds and runs its tests through CTest without Python. Keep the Python project, its src-layout package, and its uv environment in `python/`; run the project's uv commands from that directory. Tensoracle itself follows this layout, and the installed C++ helper paths described below remain inside its Python package.
|
|
252
317
|
|
|
253
|
-
`tensoracle.producer.compile_bundle` uses the extra's **Triton 3.8.0
|
|
318
|
+
`tensoracle.producer.compile_bundle` uses the extra's **Triton 3.8.0** with **ptxas >=13.2,<14** and **cuobjdump** from the host CUDA toolkit. It uses the toolkit directory named by `CUDA_HOME`, or `/usr/local/cuda` when `CUDA_HOME` is unset; explicit `ptxas` and `cuobjdump` paths override these defaults independently. The normal import, engine build, and engine reuse paths do not import the producer or Triton. Cubin production does not need a GPU or import torch; run it without importing torch first. The caller supplies Triton functions and `KernelSpec` records with their public argument types, compile time constants, and any divisibility assumptions. The producer writes sm86, sm89, and sm120 cubins, `bundle.json`, and a C++ translation unit that embeds exactly those cubins. The generated C++ entry records carry each public argument's order, type, count, and divisibility rule into the common launcher. It rejects an unexpected parameter ABI or nonzero scratch requirement. The included [example](https://github.com/sync-dev-org/tensoracle/blob/main/examples/cubin_plugin/README.md#rebuild-the-cubins) has the command to rebuild its cubins from a repository clone.
|
|
254
319
|
|
|
255
320
|
The wheel also contains `tensoracle/cpp/include`, `tensoracle/cpp/src`, and `tensoracle/cpp/cmake`. Pass the installed `tensoracle/cpp` directory to CMake as `TENSORACLE_CPP_ROOT` and include `TensoracleCubinPlugin.cmake`. Its `tensoracle_add_cubin_plugin` function compiles the common C++ source, the caller's plugin source, and the generated `bundle.cpp` into the caller's library. The caller implements the graph's meaning, field meanings, weight placement, launch sequence, and variant selection. The common source owns typed fields in their original order, handles `IPluginV3` lifecycle methods, checks cubin digests and resources, loads one module per CUDA context, checks the generated argument count and specialization rules, appends the two supported zero scratch pointers, and launches kernels. The caller selects a variant using `Kernel::accepts` and derives the count passed to `Kernel::launch` from its argument array. The common source releases modules and device allocations in their owning contexts. The library must export TensorRT's `getCreators`; a static registration constructor is not supported.
|
|
256
321
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Cubin producer API
|
|
2
|
+
|
|
3
|
+
The following names are available from `tensoracle.producer`. Install `tensoracle[producer]` for Triton 3.8.0 and provide a host CUDA toolkit with `ptxas >=13.2,<14` and `cuobjdump`. `compile_bundle` uses the toolkit directory named by `CUDA_HOME`, or `/usr/local/cuda` when `CUDA_HOME` is unset. Explicit `ptxas` and `cuobjdump` paths override the defaults independently. A missing tool reports the searched path and how to set `CUDA_HOME` or pass an explicit path. Cubin production does not need a GPU. Normal imports, engine building, and engine reuse do not import the producer or Triton.
|
|
4
|
+
|
|
5
|
+
::: tensoracle.producer.KernelSpec
|
|
6
|
+
|
|
7
|
+
::: tensoracle.producer.compile_bundle
|
|
@@ -26,8 +26,8 @@ Follow [Build a C++ and Python repository](cpp-python-repositories.md) for sourc
|
|
|
26
26
|
| `tensorrt-cu13` 11.x | Open and run engines | Build and open engines | Open plugin engines |
|
|
27
27
|
| NVIDIA GPU and driver | Open and run engines | Build and run engines | Run and test engines; cubin production itself can run without a GPU |
|
|
28
28
|
| CuPy or `cuda-python` | The application chooses its buffer and stream library | The application chooses its buffer and stream library | `cuda-python` is used by the example runtime and tests, not by `tensoracle` |
|
|
29
|
-
| Triton 3.8.0
|
|
30
|
-
| CUDA toolkit | Not needed | Not needed |
|
|
29
|
+
| Triton 3.8.0 | Not needed | Not needed | Installed with `tensoracle[producer]` for cubin production |
|
|
30
|
+
| CUDA toolkit | Not needed | Not needed | Cubin production (`ptxas >=13.2,<14` and `cuobjdump`) and native plugin build |
|
|
31
31
|
| TensorRT 11 SDK | Not needed | Not needed | Native plugin build |
|
|
32
32
|
| CMake 3.20 or later and C++17 compiler | Not needed | Not needed | Native plugin build |
|
|
33
33
|
|
|
@@ -155,12 +155,77 @@ with handle.create_execution() as execution:
|
|
|
155
155
|
|
|
156
156
|
The caller selects the CUDA device and context, orders inputs written on other streams before enqueue, and keeps buffers, streams, plugin preparation resources, and the execution unit alive until completion. Use one execution unit serially; do not call it concurrently from multiple threads. Confirm completion before changing shapes or streams, reusing buffers, or closing. `close()` and context exit release the TensorRT context before the handle, without waiting, and repeated close calls do nothing. Operations on a closed unit raise `RuntimeError` before touching TensorRT. The unit does not retain caller arrays or expose its TensorRT context.
|
|
157
157
|
|
|
158
|
-
Tensoracle neither allocates or frees device buffers, copies data, nor calls stream or device synchronization. TensorRT itself may allocate internal resources or act synchronously for some networks and plugins. Execution units reject HOST-location tensors, externally supplied shape tensor values, and data-dependent output sizes at creation. Ordinary networks that compute shapes internally from input dimensions are supported.
|
|
158
|
+
Tensoracle neither allocates or frees device buffers, copies data, nor calls stream or device synchronization. TensorRT itself may allocate internal resources or act synchronously for some networks and plugins. Execution units reject HOST-location tensors, externally supplied shape tensor values, and data-dependent output sizes at creation. Ordinary networks that compute shapes internally from input dimensions are supported. Profile switching and caller-owned TensorRT workspace memory are outside this API.
|
|
159
159
|
|
|
160
160
|
Networks with outputs marked as shape tensors emit `tensoracle.ShapeTensorOutputWarning` during building and when creating an execution unit (`create_execution()` or `EngineExecution(handle)`). The warning names the affected tensors: `create_execution()` cannot handle these engines, and calling it crashes the process. Building continues by default. To stop either operation safely, turn this warning into an exception with `warnings.filterwarnings("error", category=tensoracle.ShapeTensorOutputWarning)` after importing `warnings` and `tensoracle`. Saved engines retain the shape output names outside the cache conditions; older files without these names are reused without an execution warning.
|
|
161
161
|
|
|
162
162
|
`TensorSpec` accepts optional `location=trt.TensorLocation.DEVICE` and `format=trt.TensorFormat.LINEAR`. `open_engine` checks these only when declared, together with tensor names, modes, dtypes, build-time shapes, and profiles. An `EngineIOError` names the tensor, field, observed value, expected value, and saved file path. The execution unit does not accept a second declaration.
|
|
163
163
|
|
|
164
|
+
#### Capture and replay with CUDA Graphs
|
|
165
|
+
|
|
166
|
+
Tensoracle supports recording one `EngineExecution.enqueue` call with CUDA stream capture and replaying the resulting graph. The application owns graph creation, recapture, and destruction; tensoracle provides no capture or replay operations.
|
|
167
|
+
|
|
168
|
+
Use a dedicated execution unit (`handle.create_execution()`) for each graph. After setting input shapes, enqueue once and wait for completion before starting capture, so TensorRT finishes deferred initialization. Capture and replay on a nondefault stream; the example uses a nonblocking stream. Keep synchronous CUDA calls and work on the legacy default stream out of capture.
|
|
169
|
+
|
|
170
|
+
The graph fixes the input shapes, tensor addresses, and execution unit. Keep the execution unit, its handle, buffers, and plugin preparation resources alive until the graph is destroyed and outstanding work has finished. To use different shapes or addresses, capture a new graph for that combination or select another graph with its own execution unit. Input contents may change at the same addresses between completed replays.
|
|
171
|
+
|
|
172
|
+
For the `features` / `result` engine above, use the `cuda(...)` helper from the preceding example:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
from contextlib import ExitStack
|
|
176
|
+
|
|
177
|
+
import numpy as np
|
|
178
|
+
import tensorrt as trt
|
|
179
|
+
from cuda.bindings import runtime as cudart
|
|
180
|
+
|
|
181
|
+
with handle.create_execution() as execution:
|
|
182
|
+
execution.set_input_shapes({"features": (1, 4, 2)})
|
|
183
|
+
# Omit set_input_shapes for fixed inputs and single-point profiles.
|
|
184
|
+
features = np.arange(8, dtype=np.float32).reshape(1, 4, 2) / 4
|
|
185
|
+
output = np.empty(
|
|
186
|
+
execution.get_tensor_shape("result"),
|
|
187
|
+
dtype=trt.nptype(execution.get_tensor_dtype("result")),
|
|
188
|
+
)
|
|
189
|
+
with ExitStack() as resources:
|
|
190
|
+
stream = cuda(cudart.cudaStreamCreateWithFlags(cudart.cudaStreamNonBlocking))
|
|
191
|
+
resources.callback(lambda: cuda(cudart.cudaStreamDestroy(stream)))
|
|
192
|
+
source = cuda(cudart.cudaMalloc(features.nbytes))
|
|
193
|
+
resources.callback(lambda: cuda(cudart.cudaFree(source)))
|
|
194
|
+
target = cuda(cudart.cudaMalloc(output.nbytes))
|
|
195
|
+
resources.callback(lambda: cuda(cudart.cudaFree(target)))
|
|
196
|
+
addresses = {"features": int(source), "result": int(target)}
|
|
197
|
+
try:
|
|
198
|
+
cuda(cudart.cudaMemcpyAsync(
|
|
199
|
+
source, features.ctypes.data, features.nbytes,
|
|
200
|
+
cudart.cudaMemcpyKind.cudaMemcpyHostToDevice, stream,
|
|
201
|
+
))
|
|
202
|
+
execution.enqueue(addresses, stream=int(stream))
|
|
203
|
+
cuda(cudart.cudaStreamSynchronize(stream)) # Warm up before capture.
|
|
204
|
+
|
|
205
|
+
cuda(cudart.cudaStreamBeginCapture(
|
|
206
|
+
stream, cudart.cudaStreamCaptureMode.cudaStreamCaptureModeThreadLocal,
|
|
207
|
+
))
|
|
208
|
+
try:
|
|
209
|
+
execution.enqueue(addresses, stream=int(stream)) # Exactly one call.
|
|
210
|
+
finally:
|
|
211
|
+
graph = cuda(cudart.cudaStreamEndCapture(stream))
|
|
212
|
+
resources.callback(lambda: cuda(cudart.cudaGraphDestroy(graph)))
|
|
213
|
+
instance = cuda(cudart.cudaGraphInstantiate(graph, 0))
|
|
214
|
+
resources.callback(lambda: cuda(cudart.cudaGraphExecDestroy(instance)))
|
|
215
|
+
|
|
216
|
+
for _ in range(3):
|
|
217
|
+
cuda(cudart.cudaGraphLaunch(instance, stream))
|
|
218
|
+
cuda(cudart.cudaMemcpyAsync(
|
|
219
|
+
output.ctypes.data, target, output.nbytes,
|
|
220
|
+
cudart.cudaMemcpyKind.cudaMemcpyDeviceToHost, stream,
|
|
221
|
+
))
|
|
222
|
+
finally:
|
|
223
|
+
# Wait before ExitStack destroys the graph and releases its buffers.
|
|
224
|
+
cuda(cudart.cudaStreamSynchronize(stream))
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Engines with loops or conditionals, or layers or plugins that synchronize with the host during inference, cannot be captured. CUDA reports capture failures through `cudaErrorStreamCapture*` errors. Always end an attempted capture and release any graph resources before falling back to ordinary `enqueue`. See [TensorRT's CUDA Graph limitations](https://docs.nvidia.com/deeplearning/tensorrt/latest/performance/optimization.html#inference-with-cuda-graphs).
|
|
228
|
+
|
|
164
229
|
### Build a standard graph
|
|
165
230
|
|
|
166
231
|
Define `graph(network)` with TensorRT's Python network API and load model weights from safetensors. Describe each graph input with `InputShape.fixed` or `InputShape.ranged`, and pass an `EngineBuild` declaration to `build_serialized_engine`. `EngineBuild` declares input shapes and builder settings; the graph function determines precision through the tensor types it places in the network. The supported precisions are fp32 (with TF32 disabled), fp16, bf16, int8, and fp8. The [bf16, int8, and fp8 guide](precision.md) shows tensor casts, explicit Q/DQ layers, and scales supplied through safetensors; fp8 targets sm89 and sm120. `open_engine` uses the same declaration plus a name, graph version, weight files, and `EngineIO` to save and reuse a checked engine. Use a different `name` or `graph_version` for engines with different tensor types, such as fp32 and fp16. The [graph example](https://github.com/sync-dev-org/tensoracle#define-and-build-a-standard-graph) shows the exact calls.
|
|
@@ -177,7 +242,7 @@ Install `tensoracle[producer]` when you need to compile cubins from your own ker
|
|
|
177
242
|
pip install 'tensoracle[producer]'
|
|
178
243
|
```
|
|
179
244
|
|
|
180
|
-
`tensoracle.producer.compile_bundle` uses the extra's Triton 3.8.0
|
|
245
|
+
`tensoracle.producer.compile_bundle` uses the extra's Triton 3.8.0 with `ptxas >=13.2,<14` and `cuobjdump` from the host CUDA toolkit to produce cubins for sm86, sm89, and sm120. It uses the toolkit directory named by `CUDA_HOME`, or `/usr/local/cuda` when `CUDA_HOME` is unset, and accepts explicit paths as independent overrides. Cubin production does not need a GPU or import torch; run it without importing torch first. Build the native plugin with a TensorRT 11 SDK, CUDA toolkit, CMake, and a C++17 compiler. Inspect the resulting bundle or wheel with `tensoracle.bundle`. The [cubin plugin example](https://github.com/sync-dev-org/tensoracle/tree/main/examples/cubin_plugin) covers rebuilding from a repository clone, packaging, and runtime use. Normal import, engine building, and engine reuse do not import the producer or Triton, and do not need the producer extra or native build tools.
|
|
181
246
|
|
|
182
247
|
Pass a `tensoracle::cubin::PluginIO` declaration as the fourth argument to `PluginBase(name, plugin_namespace, fields, io)`. The `inputs` vector determines the input count and declares each input's TensorRT `type` and `format` through `TensorSpec`; `output` declares the single output's type and format. `shape_input_index` selects the input whose shape the output copies. This example declares two fp16 / HWC8 inputs and an fp16 / HWC8 output with input 0's shape:
|
|
183
248
|
|
|
@@ -6,21 +6,21 @@ The first plugin computes an fp32 32 by 16 dot product and then scales it in a s
|
|
|
6
6
|
|
|
7
7
|
## Rebuild the cubins
|
|
8
8
|
|
|
9
|
-
From the tensoracle repository root, run:
|
|
9
|
+
Provide a CUDA toolkit with `ptxas >=13.2,<14` and `cuobjdump`. Set `CUDA_HOME` to its directory; when unset, the producer uses `/usr/local/cuda`. From the tensoracle repository root, run:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
12
|
uv run --project python --extra producer python -c 'from pathlib import Path; from examples.cubin_plugin.kernels import kernel_specs; from tensoracle.producer import compile_bundle; compile_bundle(kernel_specs(), Path("examples/cubin_plugin/bundle"))'
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
This installs
|
|
15
|
+
This installs Triton 3.8.0 with `tensoracle[producer]` and recreates `bundle/` with the host toolkit tools without using a GPU. Explicit `ptxas` and `cuobjdump` paths passed to `compile_bundle` override the toolkit defaults independently. The producer checks the cubin ELF SM, public and hidden argument layout, register count, and zero scratch sizes before writing the manifest. Run the tests below with the producer extra alone so torch is absent; `compile_bundle` rejects an already imported torch.
|
|
16
16
|
|
|
17
|
-
Check that the
|
|
17
|
+
Check that the generated bundle has the expected files and passes inspection without using a GPU:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
20
|
uv run --project python --extra producer pytest -m "not gpu" python/tests/test_producer.py
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
Without the
|
|
23
|
+
Without Triton or the toolkit tools, the compilation tests skip with an explanation of what is missing.
|
|
24
24
|
|
|
25
25
|
## Build and inspect the wheel
|
|
26
26
|
|