tensoracle 2.0.0__tar.gz → 2.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tensoracle-2.0.0 → tensoracle-2.1.1}/PKG-INFO +1 -1
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/include/tensoracle/builder.h +33 -2
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/include/tensoracle/builder.hpp +38 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/include/tensoracle/tensoracle.h +2 -2
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/builder.cpp +54 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/safetensors.cpp +2 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/safetensors.hpp +1 -0
- tensoracle-2.1.1/cpp/src/sha256.hpp +195 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/tensoracle.map +8 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/CMakeLists.txt +1 -1
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/builder.cpp +51 -0
- tensoracle-2.1.1/cpp/tests/c_consumer.c +76 -0
- tensoracle-2.1.1/cpp/tests/utilities.cpp +64 -0
- tensoracle-2.1.1/cpp/tests/weights.cpp +344 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/docs/api/index.md +1 -1
- {tensoracle-2.0.0 → tensoracle-2.1.1}/docs/index.md +30 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/src/tensoracle/_version.py +2 -2
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/native_build.py +10 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/test_distribution.py +7 -6
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/test_native.py +3 -1
- tensoracle-2.0.0/cpp/src/sha256.hpp +0 -102
- tensoracle-2.0.0/cpp/tests/c_consumer.c +0 -31
- tensoracle-2.0.0/cpp/tests/utilities.cpp +0 -29
- tensoracle-2.0.0/cpp/tests/weights.cpp +0 -133
- {tensoracle-2.0.0 → tensoracle-2.1.1}/.gitignore +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/CMakeLists.txt +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/LICENSE +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/README.md +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/bindings.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/build_backend.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/CMakeLists.txt +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/cmake/TensoracleCubinPlugin.cmake +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/cmake/TensoracleCuda.cmake +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/cmake/TensoracleDependencies.cmake +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/cmake/TensoracleJson.cmake +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/cmake/tensoracleConfig.cmake.in +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/include/tensoracle/cache.h +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/include/tensoracle/cache.hpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/include/tensoracle/cubin.h +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/include/tensoracle/cubin.hpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/include/tensoracle/cubin_plugin.hpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/include/tensoracle/engine.h +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/include/tensoracle/engine.hpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/include/tensoracle/plugins.h +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/include/tensoracle/plugins.hpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/include/tensoracle/tensoracle.hpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/abi.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/builder_internal.hpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/bundle.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/bundle_internal.hpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/cache.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/cache.hpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/cache_management.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/cache_management_internal.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/cache_management_internal.hpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/cache_open.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/comparison.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/cubin_plugin.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/engine.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/engine_internal.hpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/error.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/error.hpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/native_exports.hpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/plugins.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/producer.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/src/structure.hpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/abi.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/builder_fixture.hpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/builder_probe.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/cache.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/cache_management.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/cache_probe.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/comparison.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/consumer/CMakeLists.txt +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/consumer/main.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/core.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/cubin.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/driver_failures.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/execution.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/installed.cmake +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/native_exports.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/native_exports_fixture.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/plugin_fixture.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/plugins.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cpp/tests/precision.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/cubin_bindings.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/docs/api/bundle.md +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/docs/api/producer.md +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/docs/cpp-python-repositories.md +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/docs/migration.md +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/docs/optimization.md +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/docs/precision.md +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/docs/tensorrt-sdk.md +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/CMakeLists.txt +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/README.md +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bindings.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bundle/bundle.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bundle/bundle.json +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bundle/cubins/sm120/bias.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bundle/cubins/sm120/dot.specialized.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bundle/cubins/sm120/dot.tf32-control.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bundle/cubins/sm120/dot.unspecialized.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bundle/cubins/sm120/scale.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bundle/cubins/sm86/bias.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bundle/cubins/sm86/dot.specialized.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bundle/cubins/sm86/dot.tf32-control.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bundle/cubins/sm86/dot.unspecialized.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bundle/cubins/sm86/scale.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bundle/cubins/sm89/bias.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bundle/cubins/sm89/dot.specialized.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bundle/cubins/sm89/dot.tf32-control.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bundle/cubins/sm89/dot.unspecialized.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/bundle/cubins/sm89/scale.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/example_cubin_plugin/__init__.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/example_cubin_plugin/weights.safetensors +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/kernels.cu +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/kernels.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/plugin.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/cubin_plugin/pyproject.toml +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/wheel_consumer/CMakeLists.txt +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/wheel_consumer/README.md +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/wheel_consumer/bindings.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/wheel_consumer/pyproject.toml +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/examples/wheel_consumer/src/tensoracle_consumer/__init__.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/mkdocs.yml +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/pyproject.toml +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/src/tensoracle/__init__.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/src/tensoracle/_cli.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/src/tensoracle/_comparison.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/src/tensoracle/bundle.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/src/tensoracle/convert.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/src/tensoracle/producer.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/cubin_io/check.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/cubins/ptxas-12.9.86/sm120.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/cubins/ptxas-12.9.86/sm86.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/cubins/ptxas-12.9.86/sm89.cubin +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/native/CMakeLists.txt +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/native/cache/CMakeLists.txt +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/native/cache/writer.cpp +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/native/export.h +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/test_bundle.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/test_cache_cli.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/test_cmake_cuda.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/test_cmake_plugin.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/test_comparison.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/test_comparison_binding.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/test_convert.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/test_cpp_core.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/test_example_plugin.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/test_plugin_io.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/test_producer.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/tests/test_public_api.py +0 -0
- {tensoracle-2.0.0 → tensoracle-2.1.1}/uv.lock +0 -0
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
extern "C" {
|
|
6
6
|
#endif
|
|
7
7
|
typedef struct tensoracle_weights tensoracle_weights;
|
|
8
|
-
/*
|
|
9
|
-
*
|
|
8
|
+
/* Views into safetensors. For owned weights, all names, shapes and values
|
|
9
|
+
* remain valid until weights_destroy. For borrowed callback weights, they
|
|
10
|
+
* remain valid until the outer open_engine call returns, including after the
|
|
11
|
+
* network callback returns.
|
|
10
12
|
* Values are contiguous little-endian scalars; data is naturally aligned.
|
|
11
13
|
* Tensor names must be unique across ALL declared files. A duplicate rejects
|
|
12
14
|
* the build before its callback, identifying the name and both source paths.
|
|
@@ -26,6 +28,35 @@ TENSORACLE_API tensoracle_status tensoracle_weights_count(const tensoracle_weigh
|
|
|
26
28
|
TENSORACLE_API tensoracle_status tensoracle_weights_at(const tensoracle_weights*, size_t, tensoracle_weight*, tensoracle_error**) TENSORACLE_NOEXCEPT;
|
|
27
29
|
TENSORACLE_API tensoracle_status tensoracle_weights_find(const tensoracle_weights*, const char*, tensoracle_weight*, tensoracle_error**) TENSORACLE_NOEXCEPT;
|
|
28
30
|
|
|
31
|
+
/* Open one safetensors file without initializing CUDA or using a GPU. The same
|
|
32
|
+
* reader and validation are used by open_engine. On failure *weights is NULL.
|
|
33
|
+
* Destroy only handles returned by weights_open: NEVER destroy a borrowed
|
|
34
|
+
* handle supplied to a network callback. Destroy accepts NULL. */
|
|
35
|
+
TENSORACLE_API tensoracle_status tensoracle_weights_open(const char* path, tensoracle_weights** weights, tensoracle_error**) TENSORACLE_NOEXCEPT;
|
|
36
|
+
TENSORACLE_API tensoracle_status tensoracle_weights_destroy(tensoracle_weights*) TENSORACLE_NOEXCEPT;
|
|
37
|
+
|
|
38
|
+
typedef struct tensoracle_weights_metadata_entry {
|
|
39
|
+
size_t struct_size;
|
|
40
|
+
const char* key;
|
|
41
|
+
size_t key_size;
|
|
42
|
+
const char* value;
|
|
43
|
+
size_t value_size;
|
|
44
|
+
} tensoracle_weights_metadata_entry;
|
|
45
|
+
/* Metadata is a map of UTF-8 byte strings, including embedded NUL bytes. Sizes
|
|
46
|
+
* exclude the additional NUL terminator present after each key/value. Pointers
|
|
47
|
+
* have the same lifetime as the weight's names and values. Initialize the
|
|
48
|
+
* output entry's struct_size before reading it.
|
|
49
|
+
* Missing __metadata__ means an empty map. Indexes enumerate keys in byte
|
|
50
|
+
* order. Missing keys and out-of-range indexes return INVALID_ARGUMENT.
|
|
51
|
+
* find accepts a NUL-terminated key; enumerate with at to read keys containing
|
|
52
|
+
* embedded NUL bytes. Both functions preserve byte lengths in their output.
|
|
53
|
+
* These operations also accept borrowed network callback weights: metadata
|
|
54
|
+
* from all declared files is merged, with the first declared file's value
|
|
55
|
+
* retained for repeated keys. This does not change file validation. */
|
|
56
|
+
TENSORACLE_API tensoracle_status tensoracle_weights_metadata_count(const tensoracle_weights*, size_t*, tensoracle_error**) TENSORACLE_NOEXCEPT;
|
|
57
|
+
TENSORACLE_API tensoracle_status tensoracle_weights_metadata_at(const tensoracle_weights*, size_t, tensoracle_weights_metadata_entry*, tensoracle_error**) TENSORACLE_NOEXCEPT;
|
|
58
|
+
TENSORACLE_API tensoracle_status tensoracle_weights_metadata_find(const tensoracle_weights*, const char*, tensoracle_weights_metadata_entry*, tensoracle_error**) TENSORACLE_NOEXCEPT;
|
|
59
|
+
|
|
29
60
|
/* network borrows nvinfer1::INetworkDefinition*. Callback/context are borrowed
|
|
30
61
|
* only during this call and never retained. On failure return a nonzero status
|
|
31
62
|
* and optionally a message valid until open_engine returns (literal/context
|
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
#include "builder.h"
|
|
3
3
|
#include "engine.hpp"
|
|
4
4
|
#include <exception>
|
|
5
|
+
#include <filesystem>
|
|
5
6
|
#include <optional>
|
|
6
7
|
#include <string>
|
|
8
|
+
#include <string_view>
|
|
7
9
|
#include <type_traits>
|
|
10
|
+
#include <utility>
|
|
8
11
|
#include <vector>
|
|
9
12
|
|
|
10
13
|
namespace nvinfer1 { class INetworkDefinition; }
|
|
@@ -24,9 +27,44 @@ public:
|
|
|
24
27
|
tensoracle_weight output{}; output.struct_size = sizeof(output); tensoracle_error* error = nullptr;
|
|
25
28
|
auto status = tensoracle_weights_find(value_, name, &output, &error); check(status, error); return output;
|
|
26
29
|
}
|
|
30
|
+
size_t metadata_size() const {
|
|
31
|
+
size_t output = 0; tensoracle_error* error = nullptr;
|
|
32
|
+
auto status = tensoracle_weights_metadata_count(value_, &output, &error); check(status, error); return output;
|
|
33
|
+
}
|
|
34
|
+
std::pair<std::string_view, std::string_view> metadata_at(size_t index) const {
|
|
35
|
+
tensoracle_weights_metadata_entry output{}; output.struct_size = sizeof(output); tensoracle_error* error = nullptr;
|
|
36
|
+
auto status = tensoracle_weights_metadata_at(value_, index, &output, &error); check(status, error);
|
|
37
|
+
return {{output.key, output.key_size}, {output.value, output.value_size}};
|
|
38
|
+
}
|
|
39
|
+
std::string_view metadata_at(const char* key) const {
|
|
40
|
+
tensoracle_weights_metadata_entry output{}; output.struct_size = sizeof(output); tensoracle_error* error = nullptr;
|
|
41
|
+
auto status = tensoracle_weights_metadata_find(value_, key, &output, &error); check(status, error);
|
|
42
|
+
return {output.value, output.value_size};
|
|
43
|
+
}
|
|
27
44
|
private:
|
|
28
45
|
const tensoracle_weights* value_;
|
|
29
46
|
};
|
|
47
|
+
|
|
48
|
+
class weights_handle {
|
|
49
|
+
public:
|
|
50
|
+
weights_handle() = default;
|
|
51
|
+
explicit weights_handle(tensoracle_weights* handle) : handle_(handle) {}
|
|
52
|
+
tensoracle_weights* get() const noexcept { return handle_.get(); }
|
|
53
|
+
tensoracle_weights* release() noexcept { return handle_.release(); }
|
|
54
|
+
void close() noexcept { handle_.reset(); }
|
|
55
|
+
weights_view view() const noexcept { return weights_view(get()); }
|
|
56
|
+
size_t metadata_size() const { return view().metadata_size(); }
|
|
57
|
+
std::pair<std::string_view, std::string_view> metadata_at(size_t index) const { return view().metadata_at(index); }
|
|
58
|
+
std::string_view metadata_at(const char* key) const { return view().metadata_at(key); }
|
|
59
|
+
private:
|
|
60
|
+
unique_handle<tensoracle_weights, tensoracle_weights_destroy> handle_;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
inline weights_handle open_weights(const std::filesystem::path& path) {
|
|
64
|
+
tensoracle_weights* result = nullptr; tensoracle_error* diagnostic = nullptr;
|
|
65
|
+
auto status = tensoracle_weights_open(path.string().c_str(), &result, &diagnostic);
|
|
66
|
+
check(status, diagnostic); return weights_handle(result);
|
|
67
|
+
}
|
|
30
68
|
struct input_profile { std::string name; std::vector<int64_t> minimum, optimum, maximum; };
|
|
31
69
|
struct tensor_spec {
|
|
32
70
|
std::string name; tensoracle_dtype dtype; std::vector<int64_t> shape; bool input;
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
#include <stdint.h>
|
|
6
6
|
|
|
7
7
|
#define TENSORACLE_VERSION_MAJOR 2
|
|
8
|
-
#define TENSORACLE_VERSION_MINOR
|
|
9
|
-
#define TENSORACLE_VERSION_PATCH
|
|
8
|
+
#define TENSORACLE_VERSION_MINOR 1
|
|
9
|
+
#define TENSORACLE_VERSION_PATCH 1
|
|
10
10
|
|
|
11
11
|
#if defined(_WIN32)
|
|
12
12
|
# if defined(TENSORACLE_BUILDING_LIBRARY)
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#include "safetensors.hpp"
|
|
6
6
|
#include "structure.hpp"
|
|
7
7
|
#include <algorithm>
|
|
8
|
+
#include <iterator>
|
|
8
9
|
#include <set>
|
|
9
10
|
#if defined(__GLIBC__)
|
|
10
11
|
#include <malloc.h>
|
|
@@ -74,6 +75,8 @@ cache_request request_from(const tensoracle_builder_options* options) {
|
|
|
74
75
|
built_plan build_plan(const cache_request& request, const tensoracle_network_builder& callback) {
|
|
75
76
|
auto weights = load_safetensors(request.weights);
|
|
76
77
|
auto& logger = process_engine_logger();
|
|
78
|
+
// TensorRT requires the timing cache to outlive the builder using it.
|
|
79
|
+
std::unique_ptr<nvinfer1::ITimingCache> timing;
|
|
77
80
|
std::unique_ptr<nvinfer1::IBuilder> builder(nvinfer1::createInferBuilder(logger));
|
|
78
81
|
if (!builder) throw std::runtime_error("TensorRT failed to create a builder");
|
|
79
82
|
std::unique_ptr<nvinfer1::INetworkDefinition> network(builder->createNetworkV2(0));
|
|
@@ -112,6 +115,16 @@ built_plan build_plan(const cache_request& request, const tensoracle_network_bui
|
|
|
112
115
|
}
|
|
113
116
|
}
|
|
114
117
|
if (profile) require(profile->isValid() && config->addOptimizationProfile(profile) >= 0, "TensorRT rejected the optimization profile");
|
|
118
|
+
timing.reset(config->createTimingCache(nullptr, 0));
|
|
119
|
+
if (!timing) throw std::runtime_error("TensorRT failed to create a timing cache");
|
|
120
|
+
if (!config->setTimingCache(*timing, false)) throw std::runtime_error("TensorRT rejected the timing cache");
|
|
121
|
+
// A cold TensorRT build can serialize large zero-filled buffers. Rebuild
|
|
122
|
+
// with the populated in-memory cache before persisting the plan, releasing
|
|
123
|
+
// the first plan to avoid retaining both serialized engines at once.
|
|
124
|
+
{
|
|
125
|
+
std::unique_ptr<nvinfer1::IHostMemory> warmup(builder->buildSerializedNetwork(*network, *config));
|
|
126
|
+
if (!warmup) throw std::runtime_error("TensorRT failed to build the serialized engine");
|
|
127
|
+
}
|
|
115
128
|
std::unique_ptr<nvinfer1::IHostMemory> plan(builder->buildSerializedNetwork(*network, *config));
|
|
116
129
|
if (!plan) throw std::runtime_error("TensorRT failed to build the serialized engine");
|
|
117
130
|
auto* first = static_cast<const uint8_t*>(plan->data());
|
|
@@ -124,6 +137,47 @@ void write_weight(const tensoracle::detail::weight_record& value, tensoracle_wei
|
|
|
124
137
|
FIELD(dimensions, value.shape.data()); FIELD(data, value.data()); FIELD(element_count, value.count); FIELD(byte_size, value.bytes);
|
|
125
138
|
#undef FIELD
|
|
126
139
|
}
|
|
140
|
+
void write_metadata(const std::pair<const std::string, std::string>& entry, tensoracle_weights_metadata_entry* output) {
|
|
141
|
+
fields(output, sizeof(size_t)); auto size = structure_size(output);
|
|
142
|
+
write_field(output, size, offsetof(tensoracle_weights_metadata_entry, key), entry.first.c_str());
|
|
143
|
+
write_field(output, size, offsetof(tensoracle_weights_metadata_entry, key_size), entry.first.size());
|
|
144
|
+
write_field(output, size, offsetof(tensoracle_weights_metadata_entry, value), entry.second.c_str());
|
|
145
|
+
write_field(output, size, offsetof(tensoracle_weights_metadata_entry, value_size), entry.second.size());
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
extern "C" tensoracle_status tensoracle_weights_open(const char* path, tensoracle_weights** output, tensoracle_error** error) noexcept {
|
|
149
|
+
return tensoracle::detail::guard(error, [&] {
|
|
150
|
+
if (output) *output = nullptr;
|
|
151
|
+
require(output, "weights output is required");
|
|
152
|
+
auto weights = tensoracle::detail::load_safetensors({text(path)});
|
|
153
|
+
*output = weights.release(); return TENSORACLE_SUCCESS;
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
extern "C" tensoracle_status tensoracle_weights_destroy(tensoracle_weights* weights) noexcept {
|
|
157
|
+
delete weights;
|
|
158
|
+
return TENSORACLE_SUCCESS;
|
|
159
|
+
}
|
|
160
|
+
extern "C" tensoracle_status tensoracle_weights_metadata_count(const tensoracle_weights* weights, size_t* count, tensoracle_error** error) noexcept {
|
|
161
|
+
return tensoracle::detail::guard(error, [&] {
|
|
162
|
+
if (count) *count = 0;
|
|
163
|
+
require(weights && count, "weights and metadata count output are required"); *count = weights->metadata.size(); return TENSORACLE_SUCCESS;
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
extern "C" tensoracle_status tensoracle_weights_metadata_at(const tensoracle_weights* weights, size_t index,
|
|
167
|
+
tensoracle_weights_metadata_entry* output, tensoracle_error** error) noexcept {
|
|
168
|
+
return tensoracle::detail::guard(error, [&] {
|
|
169
|
+
require(weights && index < weights->metadata.size(), "metadata index is out of range");
|
|
170
|
+
auto entry = weights->metadata.begin(); std::advance(entry, index);
|
|
171
|
+
write_metadata(*entry, output); return TENSORACLE_SUCCESS;
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
extern "C" tensoracle_status tensoracle_weights_metadata_find(const tensoracle_weights* weights, const char* key,
|
|
175
|
+
tensoracle_weights_metadata_entry* output, tensoracle_error** error) noexcept {
|
|
176
|
+
return tensoracle::detail::guard(error, [&] {
|
|
177
|
+
require(weights && key, "weights and metadata key are required");
|
|
178
|
+
auto entry = weights->metadata.find(key); require(entry != weights->metadata.end(), std::string("unknown weight metadata ") + key);
|
|
179
|
+
write_metadata(*entry, output); return TENSORACLE_SUCCESS;
|
|
180
|
+
});
|
|
127
181
|
}
|
|
128
182
|
extern "C" tensoracle_status tensoracle_weights_count(const tensoracle_weights* weights, size_t* count, tensoracle_error** error) noexcept {
|
|
129
183
|
return tensoracle::detail::guard(error, [&] {
|
|
@@ -76,6 +76,8 @@ std::unique_ptr<tensoracle_weights> load_safetensors(const std::vector<std::file
|
|
|
76
76
|
if (name == "__metadata__") {
|
|
77
77
|
if (!value.is_object()) invalid(path, "metadata must be a string map");
|
|
78
78
|
for (const auto& entry : value) if (!entry.is_string()) invalid(path, "metadata values must be strings");
|
|
79
|
+
for (auto entry = value.begin(); entry != value.end(); ++entry)
|
|
80
|
+
weights->metadata.emplace(entry.key(), entry.value().get<std::string>());
|
|
79
81
|
continue;
|
|
80
82
|
}
|
|
81
83
|
if (name.find('\0') != std::string::npos) invalid(path, "tensor name contains NUL");
|
|
@@ -27,6 +27,7 @@ struct tensoracle_weights {
|
|
|
27
27
|
std::vector<std::unique_ptr<tensoracle::detail::mapped_weights_file>> files;
|
|
28
28
|
std::vector<tensoracle::detail::weight_record> tensors;
|
|
29
29
|
std::map<std::string, size_t> names;
|
|
30
|
+
std::map<std::string, std::string> metadata;
|
|
30
31
|
};
|
|
31
32
|
namespace tensoracle::detail {
|
|
32
33
|
std::unique_ptr<tensoracle_weights> load_safetensors(const std::vector<std::filesystem::path>& paths);
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <array>
|
|
3
|
+
#include <algorithm>
|
|
4
|
+
#include <cstddef>
|
|
5
|
+
#include <cstdint>
|
|
6
|
+
#include <cstring>
|
|
7
|
+
#include <string>
|
|
8
|
+
|
|
9
|
+
// Other architectures and MSVC compile only the portable implementation.
|
|
10
|
+
#if (defined(__i386__) || defined(__x86_64__)) && \
|
|
11
|
+
(defined(__GNUC__) || defined(__clang__)) && !defined(_MSC_VER)
|
|
12
|
+
#include <cpuid.h>
|
|
13
|
+
#include <immintrin.h>
|
|
14
|
+
#define TENSORACLE_DETAIL_SHA256_X86
|
|
15
|
+
#endif
|
|
16
|
+
|
|
17
|
+
namespace tensoracle::detail {
|
|
18
|
+
inline std::uint32_t rotate_right(std::uint32_t value, unsigned int count) noexcept
|
|
19
|
+
{
|
|
20
|
+
return (value >> count) | (value << (32U - count));
|
|
21
|
+
}
|
|
22
|
+
inline constexpr std::array<std::uint32_t, 64> sha256_constants{{
|
|
23
|
+
0x428a2f98U,0x71374491U,0xb5c0fbcfU,0xe9b5dba5U,0x3956c25bU,0x59f111f1U,0x923f82a4U,0xab1c5ed5U,
|
|
24
|
+
0xd807aa98U,0x12835b01U,0x243185beU,0x550c7dc3U,0x72be5d74U,0x80deb1feU,0x9bdc06a7U,0xc19bf174U,
|
|
25
|
+
0xe49b69c1U,0xefbe4786U,0x0fc19dc6U,0x240ca1ccU,0x2de92c6fU,0x4a7484aaU,0x5cb0a9dcU,0x76f988daU,
|
|
26
|
+
0x983e5152U,0xa831c66dU,0xb00327c8U,0xbf597fc7U,0xc6e00bf3U,0xd5a79147U,0x06ca6351U,0x14292967U,
|
|
27
|
+
0x27b70a85U,0x2e1b2138U,0x4d2c6dfcU,0x53380d13U,0x650a7354U,0x766a0abbU,0x81c2c92eU,0x92722c85U,
|
|
28
|
+
0xa2bfe8a1U,0xa81a664bU,0xc24b8b70U,0xc76c51a3U,0xd192e819U,0xd6990624U,0xf40e3585U,0x106aa070U,
|
|
29
|
+
0x19a4c116U,0x1e376c08U,0x2748774cU,0x34b0bcb5U,0x391c0cb3U,0x4ed8aa4aU,0x5b9cca4fU,0x682e6ff3U,
|
|
30
|
+
0x748f82eeU,0x78a5636fU,0x84c87814U,0x8cc70208U,0x90befffaU,0xa4506cebU,0xbef9a3f7U,0xc67178f2U,
|
|
31
|
+
}};
|
|
32
|
+
|
|
33
|
+
inline void sha256_compress_portable(std::uint32_t* state, const std::uint8_t* message,
|
|
34
|
+
std::size_t blocks) noexcept {
|
|
35
|
+
while (blocks--) {
|
|
36
|
+
std::array<std::uint32_t, 64> words{};
|
|
37
|
+
for (std::size_t index = 0; index < 16; ++index) {
|
|
38
|
+
auto const position = index * 4U;
|
|
39
|
+
words[index] = (static_cast<std::uint32_t>(message[position]) << 24U) |
|
|
40
|
+
(static_cast<std::uint32_t>(message[position + 1U]) << 16U) |
|
|
41
|
+
(static_cast<std::uint32_t>(message[position + 2U]) << 8U) |
|
|
42
|
+
message[position + 3U];
|
|
43
|
+
}
|
|
44
|
+
for (std::size_t index = 16; index < 64; ++index) {
|
|
45
|
+
auto const a = words[index - 15U];
|
|
46
|
+
auto const b = words[index - 2U];
|
|
47
|
+
words[index] = words[index - 16U] +
|
|
48
|
+
(rotate_right(a, 7U) ^ rotate_right(a, 18U) ^ (a >> 3U)) +
|
|
49
|
+
words[index - 7U] +
|
|
50
|
+
(rotate_right(b, 17U) ^ rotate_right(b, 19U) ^ (b >> 10U));
|
|
51
|
+
}
|
|
52
|
+
auto a = state[0], b = state[1], c = state[2], d = state[3];
|
|
53
|
+
auto e = state[4], f = state[5], g = state[6], h = state[7];
|
|
54
|
+
for (std::size_t index = 0; index < 64; ++index) {
|
|
55
|
+
auto const s1 = rotate_right(e, 6U) ^ rotate_right(e, 11U) ^ rotate_right(e, 25U);
|
|
56
|
+
auto const choice = (e & f) ^ (~e & g);
|
|
57
|
+
auto const t1 = h + s1 + choice + sha256_constants[index] + words[index];
|
|
58
|
+
auto const s0 = rotate_right(a, 2U) ^ rotate_right(a, 13U) ^ rotate_right(a, 22U);
|
|
59
|
+
auto const majority = (a & b) ^ (a & c) ^ (b & c);
|
|
60
|
+
auto const t2 = s0 + majority;
|
|
61
|
+
h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;
|
|
62
|
+
}
|
|
63
|
+
state[0] += a; state[1] += b; state[2] += c; state[3] += d;
|
|
64
|
+
state[4] += e; state[5] += f; state[6] += g; state[7] += h;
|
|
65
|
+
message += 64;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
#ifdef TENSORACLE_DETAIL_SHA256_X86
|
|
70
|
+
// Keep SHA/SSSE3 instructions inside this function, including when the header is
|
|
71
|
+
// compiled by a consumer without CPU-specific build flags.
|
|
72
|
+
__attribute__((target("sha,ssse3")))
|
|
73
|
+
inline void sha256_compress_x86(std::uint32_t* state, const std::uint8_t* message,
|
|
74
|
+
std::size_t blocks) noexcept {
|
|
75
|
+
// SHA256RNDS2 packs ABEF and CDGH from the high lane to the low lane.
|
|
76
|
+
auto abef = _mm_set_epi32(state[0], state[1], state[4], state[5]);
|
|
77
|
+
auto cdgh = _mm_set_epi32(state[2], state[3], state[6], state[7]);
|
|
78
|
+
const auto endian = _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11,
|
|
79
|
+
4, 5, 6, 7, 0, 1, 2, 3);
|
|
80
|
+
while (blocks--) {
|
|
81
|
+
const auto saved_abef = abef, saved_cdgh = cdgh;
|
|
82
|
+
__m128i words[4];
|
|
83
|
+
for (std::size_t i = 0; i < 4; ++i)
|
|
84
|
+
words[i] = _mm_shuffle_epi8(
|
|
85
|
+
_mm_loadu_si128(reinterpret_cast<const __m128i*>(message + 16 * i)), endian);
|
|
86
|
+
// A four-vector ring holds W[t-16..t-1]. Each expansion generates four
|
|
87
|
+
// new words; MSG2 includes the dependencies within those four words.
|
|
88
|
+
#if defined(__clang__)
|
|
89
|
+
#pragma clang loop unroll(full)
|
|
90
|
+
#else
|
|
91
|
+
#pragma GCC unroll 16
|
|
92
|
+
#endif
|
|
93
|
+
for (std::size_t group = 0; group < 16; ++group) {
|
|
94
|
+
const auto i = group % 4;
|
|
95
|
+
if (group >= 4) {
|
|
96
|
+
auto next = _mm_sha256msg1_epu32(words[i], words[(i + 1) % 4]);
|
|
97
|
+
next = _mm_add_epi32(next,
|
|
98
|
+
_mm_alignr_epi8(words[(i + 3) % 4], words[(i + 2) % 4], 4));
|
|
99
|
+
words[i] = _mm_sha256msg2_epu32(next, words[(i + 3) % 4]);
|
|
100
|
+
}
|
|
101
|
+
auto rounds = _mm_add_epi32(words[i], _mm_loadu_si128(
|
|
102
|
+
reinterpret_cast<const __m128i*>(sha256_constants.data() + 4 * group)));
|
|
103
|
+
cdgh = _mm_sha256rnds2_epu32(cdgh, abef, rounds);
|
|
104
|
+
rounds = _mm_shuffle_epi32(rounds, 0x0e);
|
|
105
|
+
abef = _mm_sha256rnds2_epu32(abef, cdgh, rounds);
|
|
106
|
+
}
|
|
107
|
+
abef = _mm_add_epi32(abef, saved_abef);
|
|
108
|
+
cdgh = _mm_add_epi32(cdgh, saved_cdgh);
|
|
109
|
+
message += 64;
|
|
110
|
+
}
|
|
111
|
+
std::uint32_t first[4], second[4];
|
|
112
|
+
_mm_storeu_si128(reinterpret_cast<__m128i*>(first), abef);
|
|
113
|
+
_mm_storeu_si128(reinterpret_cast<__m128i*>(second), cdgh);
|
|
114
|
+
state[0] = first[3]; state[1] = first[2]; state[2] = second[3]; state[3] = second[2];
|
|
115
|
+
state[4] = first[1]; state[5] = first[0]; state[6] = second[1]; state[7] = second[0];
|
|
116
|
+
}
|
|
117
|
+
#endif
|
|
118
|
+
|
|
119
|
+
enum class sha256_backend { automatic, portable };
|
|
120
|
+
using sha256_compressor = void (*)(std::uint32_t*, const std::uint8_t*, std::size_t) noexcept;
|
|
121
|
+
|
|
122
|
+
inline sha256_compressor sha256_default_compressor() noexcept {
|
|
123
|
+
// Resolve once per process rather than querying CPUID for each file or block.
|
|
124
|
+
static const auto selected = []() noexcept -> sha256_compressor {
|
|
125
|
+
#ifdef TENSORACLE_DETAIL_SHA256_X86
|
|
126
|
+
unsigned int eax, ebx, ecx, edx;
|
|
127
|
+
if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && (ecx & bit_SSSE3) &&
|
|
128
|
+
__get_cpuid_count(7, 0, &eax, &ebx, &ecx, &edx) && (ebx & (1U << 29)))
|
|
129
|
+
return sha256_compress_x86;
|
|
130
|
+
#endif
|
|
131
|
+
return sha256_compress_portable;
|
|
132
|
+
}();
|
|
133
|
+
return selected;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Constant-memory SHA-256, shared with native plugin helpers and cache files.
|
|
137
|
+
class sha256_state {
|
|
138
|
+
public:
|
|
139
|
+
explicit sha256_state(sha256_backend backend = sha256_backend::automatic) noexcept
|
|
140
|
+
: compress_(backend == sha256_backend::portable ? sha256_compress_portable
|
|
141
|
+
: sha256_default_compressor()) {}
|
|
142
|
+
void update(const void* bytes, std::size_t size) noexcept {
|
|
143
|
+
if (!size) return;
|
|
144
|
+
auto* input = static_cast<const std::uint8_t*>(bytes);
|
|
145
|
+
length_ += size;
|
|
146
|
+
if (used_) {
|
|
147
|
+
auto take = std::min(size, block_.size() - used_);
|
|
148
|
+
std::memcpy(block_.data() + used_, input, take);
|
|
149
|
+
used_ += take; input += take; size -= take;
|
|
150
|
+
if (used_ == block_.size()) { compress_(state_.data(), block_.data(), 1); used_ = 0; }
|
|
151
|
+
}
|
|
152
|
+
if (size >= block_.size()) {
|
|
153
|
+
const auto blocks = size / block_.size();
|
|
154
|
+
compress_(state_.data(), input, blocks);
|
|
155
|
+
const auto consumed = blocks * block_.size();
|
|
156
|
+
input += consumed; size -= consumed;
|
|
157
|
+
}
|
|
158
|
+
if (size) { std::memcpy(block_.data(), input, size); used_ = size; }
|
|
159
|
+
}
|
|
160
|
+
std::string finish() const {
|
|
161
|
+
auto copy = *this;
|
|
162
|
+
const auto bits = length_ * 8U;
|
|
163
|
+
std::uint8_t padding[128]{};
|
|
164
|
+
padding[0] = 0x80U;
|
|
165
|
+
auto count = used_ < 56 ? 56 - used_ : 120 - used_;
|
|
166
|
+
copy.update(padding, count);
|
|
167
|
+
for (int i = 0; i < 8; ++i) padding[i] = static_cast<std::uint8_t>(bits >> (56 - 8 * i));
|
|
168
|
+
copy.update(padding, 8);
|
|
169
|
+
constexpr char hex[] = "0123456789abcdef";
|
|
170
|
+
std::string result(64U, '0');
|
|
171
|
+
for (std::size_t word = 0; word < 8; ++word)
|
|
172
|
+
for (std::size_t nibble = 0; nibble < 8; ++nibble)
|
|
173
|
+
result[word * 8U + nibble] = hex[(copy.state_[word] >> (4U * (7U - nibble))) & 15U];
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
private:
|
|
177
|
+
sha256_compressor compress_;
|
|
178
|
+
std::array<std::uint32_t, 8> state_{{
|
|
179
|
+
0x6a09e667U,0xbb67ae85U,0x3c6ef372U,0xa54ff53aU,
|
|
180
|
+
0x510e527fU,0x9b05688cU,0x1f83d9abU,0x5be0cd19U,
|
|
181
|
+
}};
|
|
182
|
+
std::array<std::uint8_t, 64> block_{};
|
|
183
|
+
std::size_t used_ = 0;
|
|
184
|
+
std::uint64_t length_ = 0;
|
|
185
|
+
};
|
|
186
|
+
inline std::string sha256(void const* bytes, std::size_t size) {
|
|
187
|
+
sha256_state state;
|
|
188
|
+
state.update(bytes, size);
|
|
189
|
+
return state.finish();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
#ifdef TENSORACLE_DETAIL_SHA256_X86
|
|
194
|
+
#undef TENSORACLE_DETAIL_SHA256_X86
|
|
195
|
+
#endif
|
|
@@ -40,3 +40,11 @@ TENSORACLE_2 {
|
|
|
40
40
|
tensoracle_weights_find;
|
|
41
41
|
local: *;
|
|
42
42
|
};
|
|
43
|
+
TENSORACLE_2.1 {
|
|
44
|
+
global:
|
|
45
|
+
tensoracle_weights_open;
|
|
46
|
+
tensoracle_weights_destroy;
|
|
47
|
+
tensoracle_weights_metadata_count;
|
|
48
|
+
tensoracle_weights_metadata_at;
|
|
49
|
+
tensoracle_weights_metadata_find;
|
|
50
|
+
} TENSORACLE_2;
|
|
@@ -17,7 +17,7 @@ target_compile_options(tensoracle_c_consumer PRIVATE
|
|
|
17
17
|
$<$<C_COMPILER_ID:GNU,Clang>:-pedantic-errors;-Wall;-Wextra;-Werror>)
|
|
18
18
|
target_link_libraries(tensoracle_c_consumer PRIVATE tensoracle::tensoracle)
|
|
19
19
|
add_test(NAME "C callers use the ABI without C++ headers" COMMAND tensoracle_c_consumer)
|
|
20
|
-
set_tests_properties("C callers use the ABI without C++ headers" PROPERTIES LABELS "SP-TENSORACLE-014;SP-TENSORACLE-056")
|
|
20
|
+
set_tests_properties("C callers use the ABI without C++ headers" PROPERTIES LABELS "SP-TENSORACLE-014;SP-TENSORACLE-056;SP-TENSORACLE-061")
|
|
21
21
|
|
|
22
22
|
add_test(NAME "Installed SDK builds a separate C++ application"
|
|
23
23
|
COMMAND "${CMAKE_COMMAND}"
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
#include "builder_internal.hpp"
|
|
3
3
|
#include <tensoracle/cache.hpp>
|
|
4
4
|
#include <catch2/catch_test_macros.hpp>
|
|
5
|
+
#include <chrono>
|
|
5
6
|
#include <cstdio>
|
|
6
7
|
#include <sys/wait.h>
|
|
7
8
|
#include <unistd.h>
|
|
@@ -10,6 +11,56 @@
|
|
|
10
11
|
#endif
|
|
11
12
|
|
|
12
13
|
using namespace builder_fixture;
|
|
14
|
+
TEST_CASE("Saved LeakyReLU engines stay small and reuse correct half precision outputs", "[SP-TENSORACLE-009][gpu]") {
|
|
15
|
+
context gpu; temporary_directory files; auto path = files.path / "weights"; write_weights(path);
|
|
16
|
+
auto request = options(path); request.name = "leaky-relu";
|
|
17
|
+
request.workspace_limit = 4ULL * 1024 * 1024 * 1024; request.optimization_level = 3;
|
|
18
|
+
const std::vector<int64_t> dimensions{1, 64, 135, 240};
|
|
19
|
+
request.inputs = {{"features", dimensions, dimensions, dimensions}};
|
|
20
|
+
request.io = {{"features", TENSORACLE_FLOAT16, dimensions, true}, {"result", TENSORACLE_FLOAT16, dimensions, false}};
|
|
21
|
+
int calls = 0;
|
|
22
|
+
auto define = [&](nvinfer1::INetworkDefinition& network, const tensoracle::weights_view&) {
|
|
23
|
+
++calls;
|
|
24
|
+
auto* input = network.addInput("features", nvinfer1::DataType::kHALF, nvinfer1::Dims4(1, 64, 135, 240));
|
|
25
|
+
REQUIRE(input);
|
|
26
|
+
auto* activation = network.addActivation(*input, nvinfer1::ActivationType::kLEAKY_RELU);
|
|
27
|
+
REQUIRE(activation); activation->setAlpha(0.1f);
|
|
28
|
+
auto* result = activation->getOutput(0); REQUIRE(result);
|
|
29
|
+
result->setName("result"); network.markOutput(*result);
|
|
30
|
+
};
|
|
31
|
+
auto started = std::chrono::steady_clock::now();
|
|
32
|
+
auto engine = tensoracle::open_engine(request, define);
|
|
33
|
+
auto elapsed = std::chrono::duration<double>(std::chrono::steady_clock::now() - started).count();
|
|
34
|
+
auto bytes = fs::file_size(engine.path());
|
|
35
|
+
std::printf("LeakyReLU saved bytes=%llu build seconds=%.6f\n", (unsigned long long)bytes, elapsed);
|
|
36
|
+
// Without a warm timing cache, TensorRT 11.4 serializes about 29 MB for this one layer.
|
|
37
|
+
CHECK(bytes < 1024 * 1024);
|
|
38
|
+
REQUIRE(calls == 1);
|
|
39
|
+
|
|
40
|
+
// IEEE binary16 values: [-10, -5, -2.5, -1.25, 0, 1, 2, 4].
|
|
41
|
+
const uint16_t input_pattern[]{0xc900, 0xc500, 0xc100, 0xbd00, 0, 0x3c00, 0x4000, 0x4400};
|
|
42
|
+
// LeakyReLU(x, 0.1): [-1, -0.5, -0.25, -0.125, 0, 1, 2, 4].
|
|
43
|
+
const uint16_t output_pattern[]{0xbc00, 0xb800, 0xb400, 0xb000, 0, 0x3c00, 0x4000, 0x4400};
|
|
44
|
+
const size_t count = 64 * 135 * 240;
|
|
45
|
+
std::vector<uint16_t> values(count), expected(count), actual(count);
|
|
46
|
+
for (size_t i = 0; i < count; ++i) {
|
|
47
|
+
values[i] = input_pattern[i % 8]; expected[i] = output_pattern[i % 8];
|
|
48
|
+
}
|
|
49
|
+
device_buffer source(count * sizeof(uint16_t)), target(count * sizeof(uint16_t)); stream queue;
|
|
50
|
+
cuda_check(cuMemcpyHtoD(source.value, values.data(), count * sizeof(uint16_t)));
|
|
51
|
+
auto run_activation = [&](const tensoracle::engine_handle& saved) {
|
|
52
|
+
auto execution = saved.create_execution();
|
|
53
|
+
execution.enqueue({{"features", reinterpret_cast<void*>(source.value)}, {"result", reinterpret_cast<void*>(target.value)}}, queue.value);
|
|
54
|
+
cuda_check(cuStreamSynchronize(queue.value));
|
|
55
|
+
cuda_check(cuMemcpyDtoH(actual.data(), target.value, count * sizeof(uint16_t)));
|
|
56
|
+
REQUIRE(std::equal(actual.begin(), actual.end(), expected.begin()));
|
|
57
|
+
};
|
|
58
|
+
run_activation(engine);
|
|
59
|
+
auto reopened = tensoracle::open_engine(request, define);
|
|
60
|
+
REQUIRE(calls == 1); REQUIRE(reopened.path() == engine.path());
|
|
61
|
+
run_activation(reopened);
|
|
62
|
+
}
|
|
63
|
+
|
|
13
64
|
TEST_CASE("Public builder retains weights through serialization and reuses ranged named engines", "[SP-TENSORACLE-007][SP-TENSORACLE-008][SP-TENSORACLE-009][SP-TENSORACLE-052][SP-TENSORACLE-059][gpu]") {
|
|
14
65
|
context gpu; temporary_directory files; auto path = files.path / "linear.safetensors"; write_weights(path);
|
|
15
66
|
auto request = options(path, "fp32", true); int calls = 0;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#define _POSIX_C_SOURCE 200809L
|
|
2
|
+
/* SP-TENSORACLE-014, SP-TENSORACLE-055, SP-TENSORACLE-056, SP-TENSORACLE-061:
|
|
3
|
+
* C11 callers compare CPU arrays through the public header. */
|
|
4
|
+
#include <tensoracle/tensoracle.h>
|
|
5
|
+
#include <tensoracle/engine.h>
|
|
6
|
+
#include <tensoracle/plugins.h>
|
|
7
|
+
#include <tensoracle/cache.h>
|
|
8
|
+
#include <tensoracle/builder.h>
|
|
9
|
+
#include <stdio.h>
|
|
10
|
+
#include <stdlib.h>
|
|
11
|
+
#include <string.h>
|
|
12
|
+
#include <unistd.h>
|
|
13
|
+
|
|
14
|
+
static int read_weights(void) {
|
|
15
|
+
char path[] = "/tmp/tensoracle-c-weights-XXXXXX";
|
|
16
|
+
const char header[] = "{\"__metadata__\":{\"format\":\"test\"},"
|
|
17
|
+
"\"bias\":{\"dtype\":\"I8\",\"shape\":[1],\"data_offsets\":[0,1]}}";
|
|
18
|
+
int fd = mkstemp(path);
|
|
19
|
+
if (fd < 0) return 10;
|
|
20
|
+
FILE* file = fdopen(fd, "wb");
|
|
21
|
+
if (!file) { close(fd); unlink(path); return 11; }
|
|
22
|
+
uint64_t length = sizeof(header) - 1;
|
|
23
|
+
for (int i = 0; i < 8; ++i) fputc((int)((length >> (8 * i)) & 255), file);
|
|
24
|
+
fwrite(header, 1, (size_t)length, file);
|
|
25
|
+
fputc(7, file);
|
|
26
|
+
if (fclose(file)) { unlink(path); return 12; }
|
|
27
|
+
tensoracle_weights* weights = NULL;
|
|
28
|
+
tensoracle_error* error = NULL;
|
|
29
|
+
int result = 13;
|
|
30
|
+
if (tensoracle_weights_open(path, &weights, &error) != TENSORACLE_SUCCESS || error) goto cleanup;
|
|
31
|
+
size_t count = 0;
|
|
32
|
+
if (tensoracle_weights_count(weights, &count, &error) != TENSORACLE_SUCCESS || count != 1) goto cleanup;
|
|
33
|
+
tensoracle_weight tensor = {0}; tensor.struct_size = sizeof(tensor);
|
|
34
|
+
if (tensoracle_weights_at(weights, 0, &tensor, &error) != TENSORACLE_SUCCESS) goto cleanup;
|
|
35
|
+
if (strcmp(tensor.name, "bias") || tensor.dtype != TENSORACLE_INT8 || tensor.rank != 1 ||
|
|
36
|
+
tensor.dimensions[0] != 1 || tensor.element_count != 1 || tensor.byte_size != 1 ||
|
|
37
|
+
*(const int8_t*)tensor.data != 7) goto cleanup;
|
|
38
|
+
if (tensoracle_weights_metadata_count(weights, &count, &error) != TENSORACLE_SUCCESS || count != 1) goto cleanup;
|
|
39
|
+
tensoracle_weights_metadata_entry entry = {0}; entry.struct_size = sizeof(entry);
|
|
40
|
+
if (tensoracle_weights_metadata_at(weights, 0, &entry, &error) != TENSORACLE_SUCCESS ||
|
|
41
|
+
entry.key_size != 6 || strcmp(entry.key, "format") || entry.value_size != 4 || strcmp(entry.value, "test")) goto cleanup;
|
|
42
|
+
if (tensoracle_weights_metadata_find(weights, "format", &entry, &error) != TENSORACLE_SUCCESS ||
|
|
43
|
+
entry.value_size != 4 || strcmp(entry.value, "test")) goto cleanup;
|
|
44
|
+
result = 0;
|
|
45
|
+
cleanup:
|
|
46
|
+
tensoracle_error_destroy(error);
|
|
47
|
+
tensoracle_weights_destroy(weights);
|
|
48
|
+
unlink(path);
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
int main(void) {
|
|
53
|
+
int weights_result = read_weights();
|
|
54
|
+
if (weights_result) return weights_result;
|
|
55
|
+
tensoracle_version version = {sizeof(tensoracle_version), 0, 0, 0};
|
|
56
|
+
tensoracle_error* error = NULL;
|
|
57
|
+
tensoracle_cuda_stream stream = NULL;
|
|
58
|
+
(void)stream;
|
|
59
|
+
if (tensoracle_cache_result_destroy(NULL) != TENSORACLE_SUCCESS) return 5;
|
|
60
|
+
tensoracle_engine* unused_engine = NULL;
|
|
61
|
+
if (tensoracle_open_engine(NULL, NULL, &unused_engine, NULL) != TENSORACLE_INVALID_ARGUMENT || unused_engine) return 6;
|
|
62
|
+
if (tensoracle_get_version(&version, &error) != TENSORACLE_SUCCESS || error) return 1;
|
|
63
|
+
if (version.major != TENSORACLE_VERSION_MAJOR) return 2;
|
|
64
|
+
if (tensoracle_check_version(&version, &error) != TENSORACLE_SUCCESS) return 3;
|
|
65
|
+
const size_t shape[] = {2};
|
|
66
|
+
const uint64_t candidate[] = {UINT64_MAX, 1}, reference[] = {UINT64_MAX - 1, 1};
|
|
67
|
+
const tensoracle_array a = {sizeof(a), TENSORACLE_UINT64, 1, shape, candidate};
|
|
68
|
+
const tensoracle_array b = {sizeof(b), TENSORACLE_UINT64, 1, shape, reference};
|
|
69
|
+
tensoracle_output_comparison result = {0};
|
|
70
|
+
result.struct_size = sizeof(result);
|
|
71
|
+
if (tensoracle_compare_outputs(&a, &b, NULL, &result, &error) != TENSORACLE_SUCCESS || error)
|
|
72
|
+
return 5;
|
|
73
|
+
if (result.available != TENSORACLE_HAS_MISMATCH || result.mismatch_count != 1 ||
|
|
74
|
+
result.mismatch_fraction != 0.5) return 6;
|
|
75
|
+
return tensoracle_error_destroy(error) == TENSORACLE_SUCCESS ? 0 : 4;
|
|
76
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#include "sha256.hpp"
|
|
2
|
+
#include <nlohmann/json.hpp>
|
|
3
|
+
#include <catch2/catch_test_macros.hpp>
|
|
4
|
+
#include <utility>
|
|
5
|
+
|
|
6
|
+
TEST_CASE("SHA-256 preserves standard digests with automatic and portable processing", "[SP-TENSORACLE-055]") {
|
|
7
|
+
using tensoracle::detail::sha256;
|
|
8
|
+
using tensoracle::detail::sha256_backend;
|
|
9
|
+
// hashlib.sha256 over bytes(i % 251 for i in range(size)), independent of either backend.
|
|
10
|
+
const std::pair<std::size_t, const char*> vectors[] = {
|
|
11
|
+
{0, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
|
|
12
|
+
{55, "463eb28e72f82e0a96c0a4cc53690c571281131f672aa229e0d45ae59b598b59"},
|
|
13
|
+
{56, "da2ae4d6b36748f2a318f23e7ab1dfdf45acdc9d049bd80e59de82a60895f562"},
|
|
14
|
+
{63, "29af2686fd53374a36b0846694cc342177e428d1647515f078784d69cdb9e488"},
|
|
15
|
+
{64, "fdeab9acf3710362bd2658cdc9a29e8f9c757fcf9811603a8c447cd1d9151108"},
|
|
16
|
+
{65, "4bfd2c8b6f1eec7a2afeb48b934ee4b2694182027e6d0fc075074f2fabb31781"},
|
|
17
|
+
{129, "5099c6a56203f9687f7d33f4bfdf576d31dc91f6b695ecea38b2770c87631135"},
|
|
18
|
+
{4 * 1024 * 1024 + 17, "7fa1366968edf9a8490fffac3eab7e0b1619480a152d8e75c7471f753a8c1231"},
|
|
19
|
+
};
|
|
20
|
+
for (auto backend : {sha256_backend::automatic, sha256_backend::portable}) {
|
|
21
|
+
CAPTURE(static_cast<int>(backend));
|
|
22
|
+
for (const auto& [size, expected] : vectors) {
|
|
23
|
+
CAPTURE(size);
|
|
24
|
+
// Offset by one byte to exercise unaligned block loads.
|
|
25
|
+
std::string input(size + 1, '\0');
|
|
26
|
+
for (std::size_t i = 0; i < size; ++i) input[i + 1] = static_cast<char>(i % 251);
|
|
27
|
+
tensoracle::detail::sha256_state state(backend);
|
|
28
|
+
state.update(input.data() + 1, size);
|
|
29
|
+
REQUIRE(state.finish() == expected);
|
|
30
|
+
if (backend == sha256_backend::automatic)
|
|
31
|
+
REQUIRE(sha256(input.data() + 1, size) == expected);
|
|
32
|
+
}
|
|
33
|
+
for (const auto& [input, expected] : {
|
|
34
|
+
std::pair{"abc", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"},
|
|
35
|
+
std::pair{"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
|
36
|
+
"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"}}) {
|
|
37
|
+
tensoracle::detail::sha256_state state(backend);
|
|
38
|
+
state.update(input, std::strlen(input));
|
|
39
|
+
REQUIRE(state.finish() == expected);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
TEST_CASE("Internal JSON supports ordered serialization and UTF-8 metadata", "[SP-TENSORACLE-021]") {
|
|
44
|
+
auto json = nlohmann::json::parse("{\"z\":[1,2],\"name\":\"重み\"}");
|
|
45
|
+
REQUIRE(json["name"] == "重み");
|
|
46
|
+
REQUIRE(json.dump(-1, ' ', true) == "{\"name\":\"\\u91cd\\u307f\",\"z\":[1,2]}");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
TEST_CASE("Weight SHA-256 accepts chunks across padding and block boundaries", "[SP-TENSORACLE-009]") {
|
|
50
|
+
using tensoracle::detail::sha256_backend;
|
|
51
|
+
std::string input(1000000, 'a');
|
|
52
|
+
for (auto backend : {sha256_backend::automatic, sha256_backend::portable}) {
|
|
53
|
+
CAPTURE(static_cast<int>(backend));
|
|
54
|
+
for (size_t chunk : {size_t(1), size_t(55), size_t(56), size_t(63), size_t(64), size_t(65), size_t(4096)}) {
|
|
55
|
+
CAPTURE(chunk);
|
|
56
|
+
tensoracle::detail::sha256_state state(backend);
|
|
57
|
+
state.update(nullptr, 0);
|
|
58
|
+
for (size_t i = 0; i < input.size(); i += chunk)
|
|
59
|
+
state.update(input.data() + i, std::min(chunk, input.size() - i));
|
|
60
|
+
REQUIRE(state.finish() == "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
|
|
61
|
+
REQUIRE(state.finish() == tensoracle::detail::sha256(input.data(), input.size()));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|