tensoracle 1.3.0__tar.gz → 1.4.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.
Files changed (91) hide show
  1. {tensoracle-1.3.0 → tensoracle-1.4.0}/PKG-INFO +31 -1
  2. {tensoracle-1.3.0 → tensoracle-1.4.0}/README.md +30 -0
  3. {tensoracle-1.3.0 → tensoracle-1.4.0}/cpp/CMakeLists.txt +4 -0
  4. {tensoracle-1.3.0 → tensoracle-1.4.0}/cpp/cmake/TensoracleCubinPlugin.cmake +4 -0
  5. {tensoracle-1.3.0 → tensoracle-1.4.0}/cpp/cmake/TensoracleCuda.cmake +24 -0
  6. {tensoracle-1.3.0 → tensoracle-1.4.0}/src/tensoracle/_version.py +2 -2
  7. tensoracle-1.4.0/tests/test_cmake_cuda.py +199 -0
  8. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_cmake_plugin.py +71 -0
  9. {tensoracle-1.3.0 → tensoracle-1.4.0}/.gitignore +0 -0
  10. {tensoracle-1.3.0 → tensoracle-1.4.0}/LICENSE +0 -0
  11. {tensoracle-1.3.0 → tensoracle-1.4.0}/build_backend.py +0 -0
  12. {tensoracle-1.3.0 → tensoracle-1.4.0}/cpp/include/tensoracle/cubin_plugin.hpp +0 -0
  13. {tensoracle-1.3.0 → tensoracle-1.4.0}/cpp/src/cubin_plugin.cpp +0 -0
  14. {tensoracle-1.3.0 → tensoracle-1.4.0}/cpp/tests/core.cpp +0 -0
  15. {tensoracle-1.3.0 → tensoracle-1.4.0}/docs/api/bundle.md +0 -0
  16. {tensoracle-1.3.0 → tensoracle-1.4.0}/docs/api/index.md +0 -0
  17. {tensoracle-1.3.0 → tensoracle-1.4.0}/docs/api/producer.md +0 -0
  18. {tensoracle-1.3.0 → tensoracle-1.4.0}/docs/cpp-python-repositories.md +0 -0
  19. {tensoracle-1.3.0 → tensoracle-1.4.0}/docs/index.md +0 -0
  20. {tensoracle-1.3.0 → tensoracle-1.4.0}/docs/optimization.md +0 -0
  21. {tensoracle-1.3.0 → tensoracle-1.4.0}/docs/precision.md +0 -0
  22. {tensoracle-1.3.0 → tensoracle-1.4.0}/docs/tensorrt-sdk.md +0 -0
  23. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/CMakeLists.txt +0 -0
  24. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/README.md +0 -0
  25. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/bundle/bundle.cpp +0 -0
  26. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/bundle/bundle.json +0 -0
  27. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/bundle/cubins/sm120/bias.cubin +0 -0
  28. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/bundle/cubins/sm120/dot.specialized.cubin +0 -0
  29. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/bundle/cubins/sm120/dot.tf32-control.cubin +0 -0
  30. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/bundle/cubins/sm120/dot.unspecialized.cubin +0 -0
  31. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/bundle/cubins/sm120/scale.cubin +0 -0
  32. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/bundle/cubins/sm86/bias.cubin +0 -0
  33. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/bundle/cubins/sm86/dot.specialized.cubin +0 -0
  34. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/bundle/cubins/sm86/dot.tf32-control.cubin +0 -0
  35. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/bundle/cubins/sm86/dot.unspecialized.cubin +0 -0
  36. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/bundle/cubins/sm86/scale.cubin +0 -0
  37. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/bundle/cubins/sm89/bias.cubin +0 -0
  38. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/bundle/cubins/sm89/dot.specialized.cubin +0 -0
  39. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/bundle/cubins/sm89/dot.tf32-control.cubin +0 -0
  40. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/bundle/cubins/sm89/dot.unspecialized.cubin +0 -0
  41. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/bundle/cubins/sm89/scale.cubin +0 -0
  42. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/example_cubin_plugin/__init__.py +0 -0
  43. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/example_cubin_plugin/weights.safetensors +0 -0
  44. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/kernels.py +0 -0
  45. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/plugin.cpp +0 -0
  46. {tensoracle-1.3.0 → tensoracle-1.4.0}/examples/cubin_plugin/pyproject.toml +0 -0
  47. {tensoracle-1.3.0 → tensoracle-1.4.0}/mkdocs.yml +0 -0
  48. {tensoracle-1.3.0 → tensoracle-1.4.0}/pyproject.toml +0 -0
  49. {tensoracle-1.3.0 → tensoracle-1.4.0}/src/tensoracle/__init__.py +0 -0
  50. {tensoracle-1.3.0 → tensoracle-1.4.0}/src/tensoracle/_build.py +0 -0
  51. {tensoracle-1.3.0 → tensoracle-1.4.0}/src/tensoracle/_cache.py +0 -0
  52. {tensoracle-1.3.0 → tensoracle-1.4.0}/src/tensoracle/_comparison.py +0 -0
  53. {tensoracle-1.3.0 → tensoracle-1.4.0}/src/tensoracle/_execution.py +0 -0
  54. {tensoracle-1.3.0 → tensoracle-1.4.0}/src/tensoracle/_memory.py +0 -0
  55. {tensoracle-1.3.0 → tensoracle-1.4.0}/src/tensoracle/_plugins.py +0 -0
  56. {tensoracle-1.3.0 → tensoracle-1.4.0}/src/tensoracle/bundle.py +0 -0
  57. {tensoracle-1.3.0 → tensoracle-1.4.0}/src/tensoracle/convert.py +0 -0
  58. {tensoracle-1.3.0 → tensoracle-1.4.0}/src/tensoracle/producer.py +0 -0
  59. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/build_memory_runtime.py +0 -0
  60. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/cubin_io/check.cpp +0 -0
  61. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/cubin_io/kernels.cu +0 -0
  62. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/cubin_io/plugin.cpp +0 -0
  63. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/cubins/ptxas-12.9.86/sm120.cubin +0 -0
  64. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/cubins/ptxas-12.9.86/sm86.cubin +0 -0
  65. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/cubins/ptxas-12.9.86/sm89.cubin +0 -0
  66. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/example_runtime.py +0 -0
  67. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/native/CMakeLists.txt +0 -0
  68. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/native/export.h +0 -0
  69. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/native_build.py +0 -0
  70. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/plugin_io_runtime.py +0 -0
  71. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/precision_runtime.py +0 -0
  72. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_build.py +0 -0
  73. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_build_memory.py +0 -0
  74. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_bundle.py +0 -0
  75. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_cache.py +0 -0
  76. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_comparison.py +0 -0
  77. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_convert.py +0 -0
  78. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_cpp_core.py +0 -0
  79. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_cuda_graphs.py +0 -0
  80. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_distribution.py +0 -0
  81. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_engine_io.py +0 -0
  82. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_example_plugin.py +0 -0
  83. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_execution.py +0 -0
  84. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_gpu_cache.py +0 -0
  85. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_plugin_io.py +0 -0
  86. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_plugins.py +0 -0
  87. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_precision.py +0 -0
  88. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_producer.py +0 -0
  89. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_shape_tensor_outputs.py +0 -0
  90. {tensoracle-1.3.0 → tensoracle-1.4.0}/tests/test_weight_hash.py +0 -0
  91. {tensoracle-1.3.0 → tensoracle-1.4.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: tensoracle
3
- Version: 1.3.0
3
+ Version: 1.4.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
@@ -354,6 +354,26 @@ Neither cubin production nor native plugin building requires an OS-installed CUD
354
354
 
355
355
  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.
356
356
 
357
+ To record the CUDA inputs used by the plugin build, call `tensoracle_find_cuda` from `TensoracleCuda.cmake` (also included by `TensoracleCubinPlugin.cmake`):
358
+
359
+ ```cmake
360
+ include("${TENSORACLE_CPP_ROOT}/cmake/TensoracleCuda.cmake")
361
+ tensoracle_find_cuda(
362
+ OUT_INCLUDE_DIR cuda_include
363
+ OUT_DRIVER_LIBRARY cuda_driver)
364
+ message(STATUS "CUDA headers: ${cuda_include}")
365
+ message(STATUS "CUDA driver link library: ${cuda_driver}")
366
+ ```
367
+
368
+ Both keywords are required and name variables set in the calling scope: `cuda_include` receives the directory containing `cuda.h`, and `cuda_driver` receives the driver link library's path. Unknown arguments are rejected. The function uses the same `CUDAToolkit_ROOT` CMake variable, environment variable, and default locations as `tensoracle_add_cubin_plugin`, and reports the same error when an input is missing. You can call it repeatedly, before or after adding the plugin.
369
+
370
+ The function also makes the public IMPORTED target `tensoracle_cuda_driver` available. Link another CMake target to it to inherit the same include directory and driver library:
371
+
372
+ ```cmake
373
+ add_library(cuda_consumer SHARED cuda_consumer.cpp)
374
+ target_link_libraries(cuda_consumer PRIVATE tensoracle_cuda_driver)
375
+ ```
376
+
357
377
  `tensoracle::cubin::PluginBase` accepts a `PluginIO` declaration as its fourth constructor argument. `inputs` lists one `TensorSpec` per input in network order; each spec declares a TensorRT `type` and `format`. `output` declares the single output's type and format, and `shape_input_index` selects the input whose shape the output copies. For example, declare two fp16 / HWC8 inputs and one fp16 / HWC8 output with the shape of input 0:
358
378
 
359
379
  ```cpp
@@ -401,6 +421,16 @@ On 2026-10-18, the test suite and a native plugin build were run on Windows:
401
421
 
402
422
  On Windows, the standalone `cpp/` build and CTest passed, the CMake helper built the example plugin DLL against `nvinfer_11.lib`, and the plugin engine was built and reused in a separate process. The `py3-none-any` wheel built on Linux was installed unchanged on Windows. With `PATH` reduced to the Windows system directories and no CUDA or TensorRT SDK paths, the driver's `nvcuda.dll` and the pip-installed TensorRT runtime were sufficient to build and reuse engines.
403
423
 
424
+ On 2026-10-27, `python/tests/test_example_plugin.py` was run on each GPU below with the example cubin bundle (digest `207d41310c87ae8b75b0301e881df881cdd2475eec07b82092e0ec66febbd5c0`). Each example wheel was built with TensorRT SDK `11.2.1.2` and tested with TensorRT runtime `11.4.0.106` (`tensorrt-cu13`). These runs cover one SDK/runtime pair per GPU, separately from the 25-pair matrix above. `inspect_wheel` confirmed that each wheel's library embeds cubins from this bundle.
425
+
426
+ | GPU | Result | Python | OS / glibc / kernel / NVIDIA driver | CUDA toolkit (plugin build) |
427
+ | --- | --- | --- | --- | --- |
428
+ | NVIDIA RTX PRO 4000 Blackwell (sm120) | 7 passed, 0 failed, 0 skipped | 3.13.15 | WSL2 / glibc 2.43 / `6.18.54.1-microsoft-standard-WSL2` / 616.92 | 13.3 |
429
+ | NVIDIA RTX 6000 Ada Generation (sm89) | 7 passed, 0 failed, 0 skipped | 3.13.15 | WSL2 / glibc 2.43 / `6.18.33.2-microsoft-standard-WSL2` / 596.72 | 13.2.86 |
430
+ | NVIDIA RTX A6000 (sm86) | 7 passed, 0 failed, 0 skipped | 3.13.7 | WSL2 / glibc 2.39 / `6.18.54.1-microsoft-standard-WSL2` / 597.16 | 13.0.88 |
431
+
432
+ The tests built and installed the example wheel in a temporary runtime environment, built and ran both plugins, reused a saved TensorRT engine in a separate process without calling the graph, selected a different engine cache entry when the plugin library changed, ran concurrently in two CUDA contexts, compared fp32 and TF32, and rejected a library embedding a different bundle.
433
+
404
434
  Native Linux, other kernels, Windows with sm86 or sm120, and TensorRT 11 versions not listed here have not been tested.
405
435
 
406
436
  ## Compare output arrays
@@ -321,6 +321,26 @@ Neither cubin production nor native plugin building requires an OS-installed CUD
321
321
 
322
322
  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.
323
323
 
324
+ To record the CUDA inputs used by the plugin build, call `tensoracle_find_cuda` from `TensoracleCuda.cmake` (also included by `TensoracleCubinPlugin.cmake`):
325
+
326
+ ```cmake
327
+ include("${TENSORACLE_CPP_ROOT}/cmake/TensoracleCuda.cmake")
328
+ tensoracle_find_cuda(
329
+ OUT_INCLUDE_DIR cuda_include
330
+ OUT_DRIVER_LIBRARY cuda_driver)
331
+ message(STATUS "CUDA headers: ${cuda_include}")
332
+ message(STATUS "CUDA driver link library: ${cuda_driver}")
333
+ ```
334
+
335
+ Both keywords are required and name variables set in the calling scope: `cuda_include` receives the directory containing `cuda.h`, and `cuda_driver` receives the driver link library's path. Unknown arguments are rejected. The function uses the same `CUDAToolkit_ROOT` CMake variable, environment variable, and default locations as `tensoracle_add_cubin_plugin`, and reports the same error when an input is missing. You can call it repeatedly, before or after adding the plugin.
336
+
337
+ The function also makes the public IMPORTED target `tensoracle_cuda_driver` available. Link another CMake target to it to inherit the same include directory and driver library:
338
+
339
+ ```cmake
340
+ add_library(cuda_consumer SHARED cuda_consumer.cpp)
341
+ target_link_libraries(cuda_consumer PRIVATE tensoracle_cuda_driver)
342
+ ```
343
+
324
344
  `tensoracle::cubin::PluginBase` accepts a `PluginIO` declaration as its fourth constructor argument. `inputs` lists one `TensorSpec` per input in network order; each spec declares a TensorRT `type` and `format`. `output` declares the single output's type and format, and `shape_input_index` selects the input whose shape the output copies. For example, declare two fp16 / HWC8 inputs and one fp16 / HWC8 output with the shape of input 0:
325
345
 
326
346
  ```cpp
@@ -368,6 +388,16 @@ On 2026-10-18, the test suite and a native plugin build were run on Windows:
368
388
 
369
389
  On Windows, the standalone `cpp/` build and CTest passed, the CMake helper built the example plugin DLL against `nvinfer_11.lib`, and the plugin engine was built and reused in a separate process. The `py3-none-any` wheel built on Linux was installed unchanged on Windows. With `PATH` reduced to the Windows system directories and no CUDA or TensorRT SDK paths, the driver's `nvcuda.dll` and the pip-installed TensorRT runtime were sufficient to build and reuse engines.
370
390
 
391
+ On 2026-10-27, `python/tests/test_example_plugin.py` was run on each GPU below with the example cubin bundle (digest `207d41310c87ae8b75b0301e881df881cdd2475eec07b82092e0ec66febbd5c0`). Each example wheel was built with TensorRT SDK `11.2.1.2` and tested with TensorRT runtime `11.4.0.106` (`tensorrt-cu13`). These runs cover one SDK/runtime pair per GPU, separately from the 25-pair matrix above. `inspect_wheel` confirmed that each wheel's library embeds cubins from this bundle.
392
+
393
+ | GPU | Result | Python | OS / glibc / kernel / NVIDIA driver | CUDA toolkit (plugin build) |
394
+ | --- | --- | --- | --- | --- |
395
+ | NVIDIA RTX PRO 4000 Blackwell (sm120) | 7 passed, 0 failed, 0 skipped | 3.13.15 | WSL2 / glibc 2.43 / `6.18.54.1-microsoft-standard-WSL2` / 616.92 | 13.3 |
396
+ | NVIDIA RTX 6000 Ada Generation (sm89) | 7 passed, 0 failed, 0 skipped | 3.13.15 | WSL2 / glibc 2.43 / `6.18.33.2-microsoft-standard-WSL2` / 596.72 | 13.2.86 |
397
+ | NVIDIA RTX A6000 (sm86) | 7 passed, 0 failed, 0 skipped | 3.13.7 | WSL2 / glibc 2.39 / `6.18.54.1-microsoft-standard-WSL2` / 597.16 | 13.0.88 |
398
+
399
+ The tests built and installed the example wheel in a temporary runtime environment, built and ran both plugins, reused a saved TensorRT engine in a separate process without calling the graph, selected a different engine cache entry when the plugin library changed, ran concurrently in two CUDA contexts, compared fp32 and TF32, and rejected a library embedding a different bundle.
400
+
371
401
  Native Linux, other kernels, Windows with sm86 or sm120, and TensorRT 11 versions not listed here have not been tested.
372
402
 
373
403
  ## Compare output arrays
@@ -13,6 +13,10 @@ target_compile_features(tensoracle_cubin PUBLIC cxx_std_17)
13
13
  target_include_directories(tensoracle_cubin PUBLIC
14
14
  "${CMAKE_CURRENT_SOURCE_DIR}/include" "${TENSORRT_ROOT}/include")
15
15
  target_link_libraries(tensoracle_cubin PUBLIC tensoracle_internal_cuda_driver)
16
+ if(NOT WIN32)
17
+ find_package(Threads REQUIRED)
18
+ target_link_libraries(tensoracle_cubin PUBLIC Threads::Threads)
19
+ endif()
16
20
  target_compile_options(tensoracle_cubin PRIVATE
17
21
  $<$<CXX_COMPILER_ID:GNU,Clang>:-Wno-deprecated-declarations>)
18
22
 
@@ -30,6 +30,10 @@ function(tensoracle_add_cubin_plugin)
30
30
  "${_tensoracle_cpp}/include" "${TENSORACLE_NVINFER_INCLUDE}")
31
31
  target_link_libraries(${ARG_TARGET} PRIVATE
32
32
  "${TENSORACLE_NVINFER_LIBRARY}" tensoracle_internal_cuda_driver)
33
+ if(NOT WIN32)
34
+ find_package(Threads REQUIRED)
35
+ target_link_libraries(${ARG_TARGET} PRIVATE Threads::Threads)
36
+ endif()
33
37
  set_target_properties(${ARG_TARGET} PROPERTIES
34
38
  CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN YES)
35
39
  endfunction()
@@ -91,5 +91,29 @@ function(_tensoracle_find_cuda)
91
91
  set_target_properties(tensoracle_internal_cuda_driver PROPERTIES
92
92
  IMPORTED_LOCATION "${_driver}" INTERFACE_INCLUDE_DIRECTORIES "${_include}")
93
93
  endif()
94
+ if(NOT TARGET tensoracle_cuda_driver)
95
+ add_library(tensoracle_cuda_driver ALIAS tensoracle_internal_cuda_driver)
96
+ endif()
94
97
  set(_tensoracle_cuda_root "${_root}" PARENT_SCOPE)
95
98
  endfunction()
99
+
100
+ # Return the same CUDA inputs used by tensoracle_add_cubin_plugin and expose
101
+ # tensoracle_cuda_driver for consumers that only need to link the Driver API.
102
+ function(tensoracle_find_cuda)
103
+ cmake_parse_arguments(PARSE_ARGV 0 ARG "" "OUT_INCLUDE_DIR;OUT_DRIVER_LIBRARY" "")
104
+ if(DEFINED ARG_UNPARSED_ARGUMENTS)
105
+ message(FATAL_ERROR "Unrecognized tensoracle_find_cuda arguments: ${ARG_UNPARSED_ARGUMENTS}")
106
+ endif()
107
+ if(ARG_KEYWORDS_MISSING_VALUES OR
108
+ NOT DEFINED ARG_OUT_INCLUDE_DIR OR "${ARG_OUT_INCLUDE_DIR}" STREQUAL "" OR
109
+ NOT DEFINED ARG_OUT_DRIVER_LIBRARY OR "${ARG_OUT_DRIVER_LIBRARY}" STREQUAL "")
110
+ message(FATAL_ERROR
111
+ "tensoracle_find_cuda requires OUT_INCLUDE_DIR and OUT_DRIVER_LIBRARY variable names")
112
+ endif()
113
+
114
+ _tensoracle_find_cuda()
115
+ get_target_property(_include tensoracle_cuda_driver INTERFACE_INCLUDE_DIRECTORIES)
116
+ get_target_property(_driver tensoracle_cuda_driver IMPORTED_LOCATION)
117
+ set("${ARG_OUT_INCLUDE_DIR}" "${_include}" PARENT_SCOPE)
118
+ set("${ARG_OUT_DRIVER_LIBRARY}" "${_driver}" PARENT_SCOPE)
119
+ endfunction()
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '1.3.0'
22
- __version_tuple__ = version_tuple = (1, 3, 0)
21
+ __version__ = version = '1.4.0'
22
+ __version_tuple__ = version_tuple = (1, 4, 0)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -0,0 +1,199 @@
1
+ """Consumers can inspect and link the same CUDA inputs as the cubin plugin helper."""
2
+
3
+ import os
4
+ import re
5
+ import subprocess
6
+ from pathlib import Path
7
+
8
+ import pytest
9
+
10
+ PROJECT = Path(__file__).resolve().parents[1]
11
+ ROOT = PROJECT.parent if PROJECT.name == "python" else PROJECT
12
+ HELPER = ROOT / "cpp/cmake/TensoracleCubinPlugin.cmake"
13
+ FIND_CUDA = "tensoracle_find_cuda(OUT_INCLUDE_DIR cuda_include OUT_DRIVER_LIBRARY cuda_driver)\n"
14
+ ADD_PLUGIN = (
15
+ "tensoracle_add_cubin_plugin(TARGET plugin\n"
16
+ ' TENSORRT_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/sdk"\n'
17
+ ' BUNDLE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}"\n'
18
+ ' SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/plugin.cpp")\n'
19
+ )
20
+
21
+
22
+ def configure(source, build_name, *, cuda, root_input="cmake-root"):
23
+ environment = dict(os.environ)
24
+ environment.pop("CUDAToolkit_ROOT", None)
25
+ arguments = []
26
+ if root_input == "env-root":
27
+ environment["CUDAToolkit_ROOT"] = str(cuda)
28
+ elif root_input == "default-root":
29
+ arguments.append(f"-DCMAKE_CUDA_COMPILER_TOOLKIT_ROOT={cuda.as_posix()}")
30
+ else:
31
+ # The CMake variable takes precedence over an environment root.
32
+ environment["CUDAToolkit_ROOT"] = str(source / "unused-cuda")
33
+ arguments.append(f"-DCUDAToolkit_ROOT={cuda.as_posix()}")
34
+ return subprocess.run(
35
+ ["cmake", "-S", str(source), "-B", str(source / build_name), *arguments],
36
+ env=environment,
37
+ capture_output=True,
38
+ text=True,
39
+ check=False,
40
+ timeout=45,
41
+ )
42
+
43
+
44
+ def platform_settings(windows):
45
+ if windows:
46
+ return (
47
+ "set(WIN32 TRUE)\n"
48
+ 'set(CMAKE_FIND_LIBRARY_PREFIXES "")\n'
49
+ 'set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")\n'
50
+ )
51
+ return (
52
+ "set(WIN32 FALSE)\n"
53
+ 'set(CMAKE_FIND_LIBRARY_PREFIXES "lib")\n'
54
+ 'set(CMAKE_FIND_LIBRARY_SUFFIXES ".so")\n'
55
+ )
56
+
57
+
58
+ @pytest.mark.req("SP-TENSORACLE-040")
59
+ @pytest.mark.parametrize("windows", [False, True], ids=["linux", "windows"])
60
+ @pytest.mark.parametrize("root_input", ["cmake-root", "env-root", "default-root"])
61
+ @pytest.mark.parametrize("plugin_first", [False, True], ids=["paths-first", "plugin-first"])
62
+ def test_public_cuda_paths_match_plugin_and_linked_consumer(
63
+ tmp_path, windows, root_input, plugin_first
64
+ ):
65
+ """CUDA paths match the plugin and linked consumers, including repeated discovery."""
66
+ cuda = tmp_path / "wheel site-packages/nvidia/cu13"
67
+ headers = cuda / "include"
68
+ headers.mkdir(parents=True)
69
+ (headers / "cuda.h").touch()
70
+ driver = cuda / ("lib/x64/cuda.lib" if windows else "lib/libcuda.so")
71
+ driver.parent.mkdir(parents=True)
72
+ driver.touch()
73
+ (tmp_path / "sdk/include").mkdir(parents=True)
74
+ (tmp_path / "sdk/include/NvInfer.h").touch()
75
+ (tmp_path / "sdk/lib").mkdir()
76
+ (tmp_path / "sdk/lib" / ("nvinfer_11.lib" if windows else "libnvinfer.so")).touch()
77
+ (tmp_path / "plugin.cpp").touch()
78
+ (tmp_path / "bundle.cpp").touch()
79
+ calls = ADD_PLUGIN + FIND_CUDA if plugin_first else FIND_CUDA + ADD_PLUGIN
80
+ (tmp_path / "CMakeLists.txt").write_text(
81
+ "cmake_minimum_required(VERSION 3.20)\n"
82
+ "project(check_cuda_paths LANGUAGES CXX)\n"
83
+ + platform_settings(windows)
84
+ + f'include("{HELPER.as_posix()}")\n'
85
+ + calls
86
+ + "tensoracle_find_cuda(OUT_DRIVER_LIBRARY repeated_driver\n"
87
+ " OUT_INCLUDE_DIR repeated_include)\n"
88
+ 'if(NOT "${cuda_include}" STREQUAL "${repeated_include}" OR\n'
89
+ ' NOT "${cuda_driver}" STREQUAL "${repeated_driver}")\n'
90
+ ' message(FATAL_ERROR "Repeated CUDA discovery changed the paths")\n'
91
+ "endif()\n"
92
+ "get_target_property(headers tensoracle_cuda_driver INTERFACE_INCLUDE_DIRECTORIES)\n"
93
+ "get_target_property(driver tensoracle_cuda_driver IMPORTED_LOCATION)\n"
94
+ "get_target_property(imported tensoracle_cuda_driver IMPORTED)\n"
95
+ 'file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/public.txt"\n'
96
+ ' "${cuda_include}\\n${cuda_driver}\\n${headers}\\n${driver}\\n${imported}")\n'
97
+ "get_target_property(dependencies plugin LINK_LIBRARIES)\n"
98
+ "foreach(dependency IN LISTS dependencies)\n"
99
+ ' if(TARGET "${dependency}")\n'
100
+ ' get_target_property(location "${dependency}" IMPORTED_LOCATION)\n'
101
+ ' get_target_property(headers "${dependency}" INTERFACE_INCLUDE_DIRECTORIES)\n'
102
+ " if(location)\n"
103
+ ' file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/plugin.txt" "${headers}\\n${location}")\n'
104
+ " endif()\n"
105
+ " endif()\n"
106
+ "endforeach()\n"
107
+ "add_library(consumer SHARED plugin.cpp)\n"
108
+ "target_link_libraries(consumer PRIVATE tensoracle_cuda_driver)\n"
109
+ "get_target_property(consumer_driver consumer LINK_LIBRARIES)\n"
110
+ 'file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/consumer-$<CONFIG>.txt"\n'
111
+ ' CONTENT "$<TARGET_PROPERTY:consumer,INCLUDE_DIRECTORIES>\\n'
112
+ '$<TARGET_FILE:${consumer_driver}>")\n',
113
+ encoding="utf-8",
114
+ )
115
+ result = configure(tmp_path, "build with spaces", cuda=cuda, root_input=root_input)
116
+ assert result.returncode == 0, result.stdout + result.stderr
117
+ build = tmp_path / "build with spaces"
118
+ include, library, target_include, target_library, imported = (
119
+ (build / "public.txt").read_text(encoding="utf-8").splitlines()
120
+ )
121
+ assert Path(include) == headers
122
+ # Linux may prefer the installed driver's library over the wheel root.
123
+ assert Path(library) == driver if windows else Path(library).name == "libcuda.so"
124
+ assert [target_include, target_library, imported] == [include, library, "TRUE"]
125
+ assert (build / "plugin.txt").read_text(encoding="utf-8").splitlines() == [include, library]
126
+ for consumer in build.glob("consumer-*.txt"):
127
+ assert consumer.read_text(encoding="utf-8").splitlines() == [include, library]
128
+ assert list(build.glob("consumer-*.txt"))
129
+
130
+
131
+ @pytest.mark.req("SP-TENSORACLE-040")
132
+ @pytest.mark.parametrize("windows", [False, True], ids=["linux", "windows"])
133
+ @pytest.mark.parametrize("missing", ["headers", "driver"])
134
+ def test_public_cuda_discovery_reports_the_same_missing_input_as_plugin(tmp_path, windows, missing):
135
+ """Missing CUDA headers and driver libraries report the plugin's discovery error."""
136
+ cuda = tmp_path / "missing cuda"
137
+ if missing == "driver":
138
+ (cuda / "include").mkdir(parents=True)
139
+ (cuda / "include/cuda.h").touch()
140
+ errors = []
141
+ for name, call in [("plugin", ADD_PLUGIN), ("public", FIND_CUDA)]:
142
+ (tmp_path / "CMakeLists.txt").write_text(
143
+ "cmake_minimum_required(VERSION 3.20)\n"
144
+ "project(missing_cuda LANGUAGES NONE)\n"
145
+ + platform_settings(windows)
146
+ # Isolate library lookup from any driver installed on the test host.
147
+ + "set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH FALSE)\n"
148
+ "set(CMAKE_FIND_USE_CMAKE_SYSTEM_PATH FALSE)\n"
149
+ "set(CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH FALSE)\n"
150
+ "set(CMAKE_FIND_USE_CMAKE_PATH FALSE)\n"
151
+ 'set(CMAKE_IGNORE_PATH "/usr/lib/wsl/lib")\n'
152
+ + f'include("{HELPER.as_posix()}")\n'
153
+ + call,
154
+ encoding="utf-8",
155
+ )
156
+ result = configure(tmp_path, f"build-{name}", cuda=cuda)
157
+ assert result.returncode != 0
158
+ message = result.stdout + result.stderr
159
+ match = re.search(
160
+ r"CMake Error at [^\n]*TensoracleCuda.cmake:\d+ \(message\):\n(.*?)\nCall Stack",
161
+ message,
162
+ re.DOTALL,
163
+ )
164
+ assert match, message
165
+ error = " ".join(match.group(1).split())
166
+ assert ("cuda.h" if missing == "headers" else "driver link library") in error
167
+ assert cuda.as_posix() in error
168
+ errors.append(error)
169
+ assert errors[0] == errors[1]
170
+
171
+
172
+ @pytest.mark.req("SP-TENSORACLE-040")
173
+ @pytest.mark.parametrize(
174
+ ("arguments", "expected"),
175
+ [
176
+ ("", "OUT_INCLUDE_DIR"),
177
+ ("OUT_INCLUDE_DIR headers", "OUT_DRIVER_LIBRARY"),
178
+ ("OUT_DRIVER_LIBRARY driver", "OUT_INCLUDE_DIR"),
179
+ ("OUT_INCLUDE_DIR OUT_DRIVER_LIBRARY driver", "OUT_INCLUDE_DIR"),
180
+ ("OUT_INCLUDE_DIR headers OUT_DRIVER_LIBRARY", "OUT_DRIVER_LIBRARY"),
181
+ ("OUT_INCLUDE_DIR inc OUT_DRIVER_LIBRARY lib OUT_INCLUDE_DIR", "OUT_INCLUDE_DIR"),
182
+ ("OUT_INCLUDE_DIR inc OUT_DRIVER_LIBRARY lib OUT_DRIVER_LIBRARY", "OUT_DRIVER_LIBRARY"),
183
+ ("OUT_INCLUDE_DIR headers OUT_DRIVER_LIBRARY driver UNKNOWN value", "UNKNOWN"),
184
+ ],
185
+ )
186
+ def test_public_cuda_discovery_rejects_invalid_output_arguments(tmp_path, arguments, expected):
187
+ """CUDA discovery rejects missing output variable names and unknown arguments."""
188
+ (tmp_path / "CMakeLists.txt").write_text(
189
+ "cmake_minimum_required(VERSION 3.20)\n"
190
+ "project(invalid_cuda_arguments LANGUAGES NONE)\n"
191
+ f'include("{HELPER.as_posix()}")\n'
192
+ f"tensoracle_find_cuda({arguments})\n",
193
+ encoding="utf-8",
194
+ )
195
+ result = configure(tmp_path, "build", cuda=tmp_path / "unused-cuda")
196
+ assert result.returncode != 0
197
+ message = result.stdout + result.stderr
198
+ assert "tensoracle_find_cuda" in message
199
+ assert expected in message
@@ -7,6 +7,77 @@ from pathlib import Path
7
7
  import pytest
8
8
 
9
9
 
10
+ @pytest.mark.req("SP-TENSORACLE-004")
11
+ @pytest.mark.req("SP-TENSORACLE-015")
12
+ @pytest.mark.skipif(os.name == "nt", reason="The pthread link check uses a Unix C++ toolchain")
13
+ @pytest.mark.parametrize("windows", [False, True], ids=["linux", "windows"])
14
+ @pytest.mark.parametrize("target_kind", ["plugin", "static-library"])
15
+ def test_cubin_targets_link_platform_threads(tmp_path, windows, target_kind):
16
+ """Linux plugins and static library consumers link threads; Windows needs no package."""
17
+ project = Path(__file__).resolve().parents[1]
18
+ root = project.parent if project.name == "python" else project
19
+ sdk = tmp_path / "sdk"
20
+ (sdk / "include").mkdir(parents=True)
21
+ (sdk / "include/NvInfer.h").touch()
22
+ (sdk / "lib").mkdir()
23
+ (sdk / "lib" / ("nvinfer_11.lib" if windows else "libnvinfer.so")).touch()
24
+ cuda = tmp_path / "cuda"
25
+ (cuda / "include").mkdir(parents=True)
26
+ (cuda / "include/cuda.h").touch()
27
+ driver = cuda / ("lib/x64/cuda.lib" if windows else "lib/libcuda.so")
28
+ driver.parent.mkdir(parents=True)
29
+ driver.touch()
30
+ (tmp_path / "plugin.cpp").touch()
31
+ (tmp_path / "bundle.cpp").touch()
32
+ platform = (
33
+ 'set(WIN32 TRUE)\nset(CMAKE_FIND_LIBRARY_PREFIXES "")\n'
34
+ 'set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")\n'
35
+ "set(CMAKE_DISABLE_FIND_PACKAGE_Threads TRUE)\n"
36
+ if windows
37
+ else "set(WIN32 FALSE)\n"
38
+ # Model a libc that requires explicit thread linkage, even on glibc >= 2.34.
39
+ 'set(CMAKE_HAVE_LIBC_PTHREAD FALSE CACHE BOOL "" FORCE)\n'
40
+ "set(THREADS_PREFER_PTHREAD_FLAG TRUE)\n"
41
+ )
42
+ target = (
43
+ f'include("{root.as_posix()}/cpp/cmake/TensoracleCubinPlugin.cmake")\n'
44
+ "tensoracle_add_cubin_plugin(TARGET check_threads\n"
45
+ ' TENSORRT_ROOT "${TENSORRT_ROOT}" BUNDLE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}"\n'
46
+ ' SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/plugin.cpp")\n'
47
+ if target_kind == "plugin"
48
+ else 'set(BUILD_TESTING OFF CACHE BOOL "" FORCE)\n'
49
+ f'add_subdirectory("{root.as_posix()}/cpp" cpp)\n'
50
+ "add_executable(check_threads plugin.cpp)\n"
51
+ "target_link_libraries(check_threads PRIVATE tensoracle_cubin)\n"
52
+ )
53
+ (tmp_path / "CMakeLists.txt").write_text(
54
+ "cmake_minimum_required(VERSION 3.20)\n"
55
+ "project(check_threads LANGUAGES CXX)\n" + platform + target,
56
+ encoding="utf-8",
57
+ )
58
+ build = tmp_path / "build"
59
+ result = subprocess.run(
60
+ [
61
+ "cmake",
62
+ "-S",
63
+ str(tmp_path),
64
+ "-B",
65
+ str(build),
66
+ "-G",
67
+ "Unix Makefiles",
68
+ f"-DTENSORRT_ROOT={sdk}",
69
+ f"-DCUDAToolkit_ROOT={cuda}",
70
+ ],
71
+ capture_output=True,
72
+ text=True,
73
+ check=False,
74
+ timeout=45,
75
+ )
76
+ assert result.returncode == 0, result.stdout + result.stderr
77
+ link = (build / "CMakeFiles/check_threads.dir/link.txt").read_text(encoding="utf-8")
78
+ assert ("-pthread" in link.split()) is not windows, link
79
+
80
+
10
81
  @pytest.mark.req("SP-TENSORACLE-004")
11
82
  @pytest.mark.req("SP-TENSORACLE-015")
12
83
  @pytest.mark.req("SP-TENSORACLE-038")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes