File size: 5,245 Bytes
9422383 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | #include "arm_yolo26n.h"
#include <pthreadpool.h>
#include <xnnpack.h>
#include <array>
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <memory>
#include "buffer_validation.h"
#include "fixed_graph.h"
#include "fixed_schedule.h"
#include "model_store.h"
namespace {
// Owns the complete lifetime of one runtime instance. Members are declared in
// dependency order; explicit teardown releases graph runtimes before their
// shared workspace, threadpool, scratch buffers, and model storage disappear.
struct NativeRuntime {
NativeRuntime() = default;
NativeRuntime(const NativeRuntime&) = delete;
NativeRuntime& operator=(const NativeRuntime&) = delete;
~NativeRuntime() {
for (xnn_runtime_t runtime : runtimes) {
if (runtime) xnn_delete_runtime(runtime);
}
if (workspace) xnn_release_workspace(workspace);
if (threadpool) pthreadpool_destroy(threadpool);
std::free(arena);
std::free(project);
}
ModelStore model;
ScheduleState schedule;
std::array<xnn_runtime_t, kGraphCount> runtimes{};
xnn_workspace_t workspace = nullptr;
pthreadpool_t threadpool = nullptr;
uint8_t* arena = nullptr;
uint16_t* project = nullptr;
std::atomic<uint64_t> calls{0};
};
bool Allocate(void** output, size_t bytes) {
return bytes != 0 && posix_memalign(output, yolo26::kTensorAlignment, bytes) == 0;
}
bool Initialize(NativeRuntime* native, const void* model_data, size_t model_size) {
// Validate model-derived dimensions before creating any native execution
// resources. The destructor handles every partially initialized state.
if (!native->model.Load(model_data, model_size) ||
!InitializeSchedule(native->model.resolution(), native->model.class_count(),
&native->schedule) ||
xnn_initialize(nullptr) != xnn_status_success ||
xnn_create_workspace(&native->workspace) != xnn_status_success) {
return false;
}
native->threadpool = pthreadpool_create(yolo26::kThreadCount);
if (!native->threadpool ||
pthreadpool_get_threads_count(native->threadpool) != yolo26::kThreadCount ||
!Allocate(reinterpret_cast<void**>(&native->arena), native->schedule.arena_bytes) ||
!Allocate(reinterpret_cast<void**>(&native->project), native->schedule.project_bytes)) {
return false;
}
const GraphContext graphs{
&native->model,
native->workspace,
native->threadpool,
&native->runtimes,
};
return BuildFixedGraphs(graphs) && ConfigureFixedProjection(native->runtimes);
}
} // namespace
extern "C" y26_native_runtime* y26_native_create(const void* model_data, size_t model_size) {
if (!model_data) return nullptr;
auto runtime = std::make_unique<NativeRuntime>();
if (!Initialize(runtime.get(), model_data, model_size)) return nullptr;
return reinterpret_cast<y26_native_runtime*>(runtime.release());
}
extern "C" y26_native_status y26_native_execute(y26_native_runtime* runtime, const float* input,
size_t input_bytes, float* output,
size_t output_bytes) {
auto* native = reinterpret_cast<NativeRuntime*>(runtime);
if (!native || !input || !output || input_bytes != native->schedule.input_bytes ||
output_bytes != native->schedule.output_bytes ||
yolo26::BuffersOverlap(input, input_bytes, output, output_bytes)) {
return Y26_NATIVE_INVALID_ARGUMENT;
}
if (!RunFixedSchedule(native->schedule, native->runtimes, native->threadpool, native->arena,
native->project, input, output)) {
return Y26_NATIVE_EXECUTION_FAILED;
}
if (!OutputIsFinite(native->schedule, output)) return Y26_NATIVE_NONFINITE_OUTPUT;
++native->calls;
return Y26_NATIVE_OK;
}
extern "C" void y26_native_destroy(y26_native_runtime* runtime) {
delete reinterpret_cast<NativeRuntime*>(runtime);
}
extern "C" uint64_t y26_native_calls(const y26_native_runtime* runtime) {
const auto* native = reinterpret_cast<const NativeRuntime*>(runtime);
return native ? native->calls.load() : 0;
}
extern "C" uint32_t y26_native_graphs(const y26_native_runtime* runtime) {
return runtime ? kGraphCount : 0;
}
extern "C" uint32_t y26_native_resolution(const y26_native_runtime* runtime) {
const auto* native = reinterpret_cast<const NativeRuntime*>(runtime);
return native ? native->model.resolution() : 0;
}
extern "C" uint32_t y26_native_class_count(const y26_native_runtime* runtime) {
const auto* native = reinterpret_cast<const NativeRuntime*>(runtime);
return native ? native->model.class_count() : 0;
}
extern "C" size_t y26_native_input_bytes(const y26_native_runtime* runtime) {
const auto* native = reinterpret_cast<const NativeRuntime*>(runtime);
return native ? native->schedule.input_bytes : 0;
}
extern "C" size_t y26_native_output_bytes(const y26_native_runtime* runtime) {
const auto* native = reinterpret_cast<const NativeRuntime*>(runtime);
return native ? native->schedule.output_bytes : 0;
}
extern "C" size_t y26_native_arena_bytes(const y26_native_runtime* runtime) {
const auto* native = reinterpret_cast<const NativeRuntime*>(runtime);
return native ? native->schedule.arena_bytes : 0;
}
|