From 946d5b1e711b8c9ffe84a3377c1686be9a66c130 Mon Sep 17 00:00:00 2001 From: QHarshil Date: Thu, 30 Jul 2026 00:13:22 -0700 Subject: [PATCH 1/4] Add the in-process engine, validated against the backends it replaces anytime_runtime is a pybind11 extension running ONNX Runtime in the caller's process. The subprocess worker and the Python wheel backend are both retained, so the new tensor path is checked against them rather than trusted. Measured on DistilBERT at batch size one, 60 requests after warm-up: backend inference p50 wall p50 transport python 13.667 ms 13.673 ms 0.006 ms extension 13.609 ms 13.628 ms 0.018 ms subprocess 13.629 ms 13.926 ms 0.296 ms All three agree bitwise on the logits and their inference times agree within 0.4%. Transport falls from 0.296 ms to 0.018 ms, which is not the reason for the change: a subprocess boundary rules out batching across requests and sharing a KV cache between them. The ONNX Runtime version is no longer written down twice. CMake reads onnxruntime.__version__ from the target interpreter and resolves an SDK to match, downloading it once into ~/.cache/anytime-inference-planner. Equality is enforced at configure time, asserted at compile time against ORT_API_VERSION read from the resolved headers, and re-checked when the extension is imported. Stage 1 built the worker against 1.20.1 while profiling against the 1.26.0 wheel and measured DistilBERT at 98.9 ms against 13.0 ms inside session->Run(); under pybind11 both copies are loaded at once, so this is a correctness gate rather than a performance one. The CI job that pinned ONNXRUNTIME_VERSION is gone, which also resolves the drift that had CI building against 1.26.0 while installing 1.28.0. The version probe clears PYTHONPATH so it reads the target environment rather than pip's build overlay, falling back to the overlay only on a first install into a clean environment, where no wheel exists yet. A clean install was verified to resolve 1.28.0 consistently for both the extension and the wheel. Tensors cross the boundary without copying. Inputs borrow the numpy buffer, whose references are held for the whole call; outputs are numpy views over ONNX Runtime's buffers, kept alive by a capsule owning the Ort::Value. A non-contiguous input is made contiguous rather than misread. The GIL is released around inference, without which a pool would serialise and the M/M/c model would describe a machine that does not exist. The backend comparison skips a backend that is not built, which would let a job compare one backend against itself and report success. ANYTIME_REQUIRE_BACKENDS turns that into a failure, and the new engine CI job builds both native backends against one SDK and requires all three. --- .github/workflows/ci.yml | 93 +++-- .gitignore | 4 + docs/development.md | 40 +- docs/runtime.md | 31 +- pyproject.toml | 28 +- pytest.ini | 2 +- runtime/CMakeLists.txt | 56 +++ runtime/README.md | 99 +++++ runtime/bindings/module.cpp | 179 +++++++++ runtime/cmake/ResolveOnnxRuntime.cmake | 264 +++++++++++++ runtime/include/anytime/engine.hpp | 88 +++++ runtime/include/anytime/tensor.hpp | 58 +++ runtime/src/engine.cpp | 158 ++++++++ runtime/src/tensor.cpp | 115 ++++++ src/anytime_serving/serving/__init__.py | 6 + src/anytime_serving/serving/onnx_runtime.py | 320 +++++++++++----- tests/test_runtime_engine.py | 394 ++++++++++++++++++++ 17 files changed, 1798 insertions(+), 137 deletions(-) create mode 100644 runtime/CMakeLists.txt create mode 100644 runtime/README.md create mode 100644 runtime/bindings/module.cpp create mode 100644 runtime/cmake/ResolveOnnxRuntime.cmake create mode 100644 runtime/include/anytime/engine.hpp create mode 100644 runtime/include/anytime/tensor.hpp create mode 100644 runtime/src/engine.cpp create mode 100644 runtime/src/tensor.cpp create mode 100644 tests/test_runtime_engine.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f41e80a..cc5282b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,6 +23,15 @@ jobs: with: python-version: "3.12" cache: pip + # Installing the package compiles the extension, which needs an ONNX + # Runtime SDK matching the wheel. CMake downloads it here and reuses it on + # later runs. + - name: Cache the ONNX Runtime SDK + uses: actions/cache@v4 + with: + path: ~/.cache/anytime-inference-planner + key: ort-sdk-${{ runner.os }}-${{ hashFiles('pyproject.toml') }} + restore-keys: ort-sdk-${{ runner.os }}- - name: Install run: pip install -e ".[dev]" - name: ruff check @@ -45,9 +54,28 @@ jobs: with: python-version: ${{ matrix.python-version }} cache: pip + - name: Cache the ONNX Runtime SDK + uses: actions/cache@v4 + with: + path: ~/.cache/anytime-inference-planner + key: ort-sdk-${{ runner.os }}-${{ hashFiles('pyproject.toml') }} + restore-keys: ort-sdk-${{ runner.os }}- - name: Install run: pip install -e ".[bench]" pytest + # The extension is the runtime, so an install that silently fell back to + # the Python backend would hide a broken build behind passing tests. + - name: Assert the extension was built + run: | + python -c " + from anytime_serving.serving import extension_available, load_extension + import onnxruntime + assert extension_available(), 'anytime_runtime did not build or import' + print('anytime_runtime links ONNX Runtime', load_extension().onnxruntime_version()) + print('onnxruntime wheel reports ', onnxruntime.__version__) + " - name: Run tests + env: + ANYTIME_REQUIRE_BACKENDS: extension,python run: pytest -q test-minimal: @@ -59,6 +87,12 @@ jobs: with: python-version: "3.12" cache: pip + - name: Cache the ONNX Runtime SDK + uses: actions/cache@v4 + with: + path: ~/.cache/anytime-inference-planner + key: ort-sdk-${{ runner.os }}-${{ hashFiles('pyproject.toml') }} + restore-keys: ort-sdk-${{ runner.os }}- # The serving control plane must run without the research stack. Installing # only the base dependencies enforces that: a module-scope torch or pandas # import anywhere on the serving path fails this job. @@ -75,50 +109,63 @@ jobs: run: python -c "import anytime_serving.serving, anytime_serving.models.cascade" # The remaining suites need pandas/scipy and are covered by the `test` job. - name: Run serving tests and import-boundary guards + env: + ANYTIME_REQUIRE_BACKENDS: extension,python run: | pytest -q \ tests/test_admission.py \ tests/test_selector.py \ tests/test_serving.py \ tests/test_load_monitor.py \ + tests/test_runtime_engine.py \ tests/test_import_boundaries.py - runtime: - name: C++ runtime build + engine: + name: Engine parity across all three backends runs-on: ubuntu-latest - env: - # Must match the onnxruntime wheel the Python side installs. The version is - # not cosmetic: building the worker against 1.20.1 while profiling with the - # 1.26.0 wheel measured DistilBERT at 98.9 ms in the worker versus 13.0 ms - # in the profiler, a 7.6x gap that made every admission decision wrong. - ONNXRUNTIME_VERSION: 1.26.0 + # The whole point of this job is comparing the extension against the + # subprocess worker it replaces, which means building both and refusing to + # skip either. steps: - uses: actions/checkout@v4 - - name: Fetch ONNX Runtime + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: pip + - name: Cache the ONNX Runtime SDK + uses: actions/cache@v4 + with: + path: ~/.cache/anytime-inference-planner + key: ort-sdk-${{ runner.os }}-${{ hashFiles('pyproject.toml') }} + restore-keys: ort-sdk-${{ runner.os }}- + - name: Install + run: pip install -e . pytest + # The subprocess worker links its own SDK. Reuse the one CMake resolved for + # the extension, so both halves of the comparison are the same build of + # ONNX Runtime and a disagreement cannot be blamed on versions. + - name: Locate the resolved SDK run: | - curl -fsSL -o onnxruntime.tgz \ - "https://github.com/microsoft/onnxruntime/releases/download/v${ONNXRUNTIME_VERSION}/onnxruntime-linux-x64-${ONNXRUNTIME_VERSION}.tgz" - mkdir -p "$RUNNER_TEMP/onnxruntime" - # Release tarball layouts differ between versions: some nest a - # versioned directory, some do not. Locate the one holding include/. - tar -xzf onnxruntime.tgz -C "$RUNNER_TEMP/onnxruntime" --strip-components=1 - root="$RUNNER_TEMP/onnxruntime" - if [ ! -d "$root/include" ]; then - root=$(find "$RUNNER_TEMP/onnxruntime" -maxdepth 2 -type d -name include \ - -exec dirname {} \; | head -1) + root=$(find ~/.cache/anytime-inference-planner -maxdepth 3 -type d \ + -name include -exec dirname {} \; | head -1) + if [ -z "$root" ]; then + echo "no ONNX Runtime SDK found in the cache"; exit 1 fi echo "ONNXRUNTIME_ROOT_PATH=$root" >> "$GITHUB_ENV" - - name: Configure + echo "resolved $root ($(cat "$root/VERSION_NUMBER"))" + - name: Build the subprocess worker run: | cmake -S runtime_cpp -B runtime_cpp/build \ -DCMAKE_BUILD_TYPE=Release \ -DONNXRUNTIME_ROOT_PATH="$ONNXRUNTIME_ROOT_PATH" - - name: Build - run: cmake --build runtime_cpp/build -j"$(nproc)" - - name: Verify the binary starts and reports its usage + cmake --build runtime_cpp/build -j"$(nproc)" + - name: Verify the worker starts and reports its usage run: | # No --model argument is an error; the binary must exit non-zero with a # message rather than hang waiting on stdin. if runtime_cpp/build/anytime_runtime =1.21"] -build-backend = "hatchling.build" +# The runtime is a compiled extension rather than a subprocess, so building the +# package means running CMake. +# +# onnxruntime appears here as a fallback, not as the authority. The extension has +# to link the version the *target* environment imports at runtime, so +# runtime/cmake/ResolveOnnxRuntime.cmake reads that environment first and only +# falls back to this copy when installing into a clean environment, where no wheel +# exists yet at build time. The specifier matches the runtime dependency so the two +# resolve alike, and the equality is re-checked when the extension is imported. +requires = [ + "scikit-build-core>=0.10", + "pybind11>=3.0", + "onnxruntime>=1.16", +] +build-backend = "scikit_build_core.build" [project] name = "anytime-serving" @@ -55,8 +68,15 @@ dev = [ "ruff>=0.4", ] -[tool.hatch.build.targets.wheel] -packages = ["src/anytime_serving"] +[tool.scikit-build] +cmake.source-dir = "runtime" +cmake.version = ">=3.20" +wheel.packages = ["src/anytime_serving"] +# Keep the configure and build output visible. A version mismatch against the +# onnxruntime wheel is reported as a configure-time error, and that message is +# worth reading rather than burying. +build.verbose = true +logging.level = "INFO" [tool.ruff] line-length = 100 diff --git a/pytest.ini b/pytest.ini index 49e44b4..f5a73b2 100644 --- a/pytest.ini +++ b/pytest.ini @@ -8,7 +8,7 @@ addopts = markers = slow: takes more than a few seconds; deselect with -m "not slow" needs_torch: requires torch/torchvision/transformers - needs_runtime: requires the compiled C++ runtime binary + needs_runtime: requires a compiled native runtime (the anytime_runtime extension or the subprocess worker) filterwarnings = error::DeprecationWarning:anytime_serving.* default diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt new file mode 100644 index 0000000..1428355 --- /dev/null +++ b/runtime/CMakeLists.txt @@ -0,0 +1,56 @@ +cmake_minimum_required(VERSION 3.20) +project(anytime_runtime CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE Release) +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +find_package(Python REQUIRED COMPONENTS Interpreter Development.Module) +find_package(pybind11 CONFIG REQUIRED) + +# Resolves an SDK whose version equals the onnxruntime wheel's. See the module +# for why that equality is enforced at configure time rather than documented. +include(ResolveOnnxRuntime) +anytime_resolve_onnxruntime() + +add_library(anytime_core STATIC + src/tensor.cpp + src/engine.cpp) + +target_include_directories(anytime_core + PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/include" + "${ANYTIME_ORT_ROOT}/include") + +# Asserted in tensor.cpp against the value ORT_API_VERSION actually has, so a +# header arriving from some other include path fails the build rather than the +# run. +target_compile_definitions(anytime_core + PUBLIC ANYTIME_EXPECTED_ORT_API_VERSION=${ANYTIME_ORT_API_VERSION}) + +target_link_libraries(anytime_core PUBLIC "${ANYTIME_ORT_LIBRARY}") + +pybind11_add_module(anytime_runtime MODULE bindings/module.cpp) +target_link_libraries(anytime_runtime PRIVATE anytime_core) + +# The extension loads libonnxruntime from the resolved SDK. The path is absolute +# because the SDK lives outside the wheel; ONNXRUNTIME_ROOT_PATH is how a +# relocatable build points somewhere else. +cmake_path(GET ANYTIME_ORT_LIBRARY PARENT_PATH ANYTIME_ORT_LIBDIR) +if(APPLE) + set_target_properties(anytime_runtime PROPERTIES + BUILD_RPATH "${ANYTIME_ORT_LIBDIR}" + INSTALL_RPATH "${ANYTIME_ORT_LIBDIR}") +elseif(UNIX) + set_target_properties(anytime_runtime PROPERTIES + BUILD_RPATH "${ANYTIME_ORT_LIBDIR}" + INSTALL_RPATH "${ANYTIME_ORT_LIBDIR}") +endif() + +install(TARGETS anytime_runtime DESTINATION .) diff --git a/runtime/README.md b/runtime/README.md new file mode 100644 index 0000000..6ad9ea6 --- /dev/null +++ b/runtime/README.md @@ -0,0 +1,99 @@ +# anytime_runtime (C++ extension) + +In-process ONNX Runtime engine, exposed to Python through pybind11. Replaces the +Stage 1 subprocess worker: the transport is a function call, so there is no JSON +framing, no base64, and no copy in either direction. + +## Build + +The extension is built by installing the package. `scikit-build-core` drives +CMake, so there is no separate build step: + +```bash +pip install -e . +``` + +`onnxruntime` must already be installed in the target environment, because the +extension is linked against the version that environment will import. + +## The version is derived, never written down twice + +`cmake/ResolveOnnxRuntime.cmake` reads `onnxruntime.__version__` from the target +interpreter and resolves an SDK to match: + +- `ONNXRUNTIME_ROOT_PATH`, if set, must contain a `VERSION_NUMBER` equal to the + wheel version. Configuration fails otherwise. +- Otherwise the matching release archive is downloaded once into + `~/.cache/anytime-inference-planner/` and reused. `ANYTIME_ORT_CACHE` overrides + the location. + +This matters more than it looks. Stage 1 built the worker against 1.20.1 while the +Python side used the 1.26.0 wheel and measured DistilBERT at **98.9 ms against +13.0 ms** inside `session->Run()`, a 7.6x gap that made every admission decision +wrong. Nothing failed; the numbers were just false. With the extension both copies +of the library are loaded into one process, so the equality is enforced in three +places: + +1. **Configure time.** The SDK version must equal the wheel version. +2. **Compile time.** `ORT_API_VERSION` is read out of the resolved headers and + asserted in `src/tensor.cpp`, so a header from another include path fails the + build rather than the run. +3. **Import time.** `load_extension()` in `serving/onnx_runtime.py` compares + `anytime_runtime.onnxruntime_version()` against `onnxruntime.__version__` and + raises on a mismatch, which covers an extension carried into a different + environment. + +The probe deliberately clears `PYTHONPATH`. pip builds in an isolated environment +layered onto the target interpreter through that variable, and reading its +onnxruntime instead of the target's would reintroduce the mismatch through the +build system. + +## Layout + +```text +include/anytime/tensor.hpp element types, borrowed tensor views +include/anytime/engine.hpp sessions, input filtering, one run +src/ implementations +bindings/module.cpp the pybind11 module +cmake/ ONNX Runtime resolution +``` + +Headers arrive as the work that needs them lands, rather than as empty +placeholders: the scheduler, batch assembly, and KV cache are not here yet. + +## Behaviour + +- **Tensors are borrowed, not copied.** Inputs point into the numpy buffer, whose + references the bindings hold for the whole call. Outputs are numpy views over + ONNX Runtime's own buffers, kept alive by a capsule owning the `Ort::Value`. A + response therefore holds runtime memory until it is dropped. +- **A non-contiguous input is made contiguous.** ONNX Runtime reads the buffer + directly, so a strided array would otherwise be misread. +- **The GIL is released around inference.** Without that a pool would serialise on + the interpreter lock, and the M/M/c model the admission controller uses would + describe a machine that does not exist. +- **One session set per engine.** The Python pool holds one engine per slot, so N + workers stay N independent single-threaded servers. Intra-op and inter-op + threads default to one each, matching how the service times in + `configs/serving.yaml` were measured. +- **Input filtering.** Variants of one task can declare different inputs, so + callers pass the union and each graph takes the subset it declares. A declared + input that is missing raises instead, since running on a partial feed would + silently produce wrong output. +- **Error contract.** Anything meaning "the runtime could not serve this request" + (an unknown variant, a missing input) raises `RuntimeError`. A malformed + argument (a dtype the engine does not accept) raises `ValueError`. +- **Supported input dtypes.** float32, float64, int32, int64, bool. Outputs are + mapped back from the same set. + +## Tests + +`tests/test_runtime_engine.py` compares the extension against the two backends it +replaces on a graph with real arithmetic in it, and asserts they agree bitwise. +`ANYTIME_REQUIRE_BACKENDS` turns a missing backend from a skip into a failure, so +the comparison cannot decay into a backend checked against itself. + +```bash +pytest -q tests/test_runtime_engine.py +ANYTIME_REQUIRE_BACKENDS=extension,python,subprocess pytest -q tests/test_runtime_engine.py +``` diff --git a/runtime/bindings/module.cpp b/runtime/bindings/module.cpp new file mode 100644 index 0000000..8a5262d --- /dev/null +++ b/runtime/bindings/module.cpp @@ -0,0 +1,179 @@ +// pybind11 bindings for the in-process engine. +// +// Two things here are load-bearing beyond wiring: +// +// Tensors cross the boundary without copying. Inputs are borrowed straight from +// the numpy buffer, so the references are held on the stack for the whole call. +// Outputs are numpy views over the buffers ONNX Runtime allocated, kept alive by +// a capsule that owns the Ort::Value. +// +// The GIL is released around Session::Run. Without that, a pool of workers would +// serialise on the interpreter lock and the M/M/c model the admission controller +// relies on would describe a machine that does not exist. + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "anytime/engine.hpp" +#include "anytime/tensor.hpp" + +namespace py = pybind11; + +namespace { + +anytime::DType dtype_from_numpy(const py::array& array, const std::string& name) { + const py::dtype dtype = array.dtype(); + if (dtype.is(py::dtype::of())) return anytime::DType::Float32; + if (dtype.is(py::dtype::of())) return anytime::DType::Float64; + if (dtype.is(py::dtype::of())) return anytime::DType::Int32; + if (dtype.is(py::dtype::of())) return anytime::DType::Int64; + if (dtype.is(py::dtype::of())) return anytime::DType::Bool; + throw std::invalid_argument( + "feed '" + name + "' has dtype " + + py::str(dtype).cast() + + ", which the engine does not accept. Supported: float32, float64, int32, " + "int64, bool. Cast before submitting rather than relying on an implicit " + "conversion."); +} + +py::dtype numpy_dtype_from_ort(ONNXTensorElementDataType type) { + switch (type) { + case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT: return py::dtype::of(); + case ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE: return py::dtype::of(); + case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32: return py::dtype::of(); + case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64: return py::dtype::of(); + case ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL: return py::dtype::of(); + default: + throw std::runtime_error( + "graph produced an output of type " + anytime::ort_type_name(type) + + ", which the bindings cannot map to numpy"); + } +} + +// Hands ONNX Runtime's output buffer to numpy without copying it. The capsule +// owns the Ort::Value, so the buffer outlives this call for exactly as long as +// the returned array is referenced. +py::array wrap_output(Ort::Value&& value) { + const auto info = value.GetTensorTypeAndShapeInfo(); + const ONNXTensorElementDataType element_type = info.GetElementType(); + const py::dtype dtype = numpy_dtype_from_ort(element_type); + const std::vector raw_shape = info.GetShape(); + + std::vector shape(raw_shape.begin(), raw_shape.end()); + std::vector strides(shape.size()); + py::ssize_t stride = static_cast(dtype.itemsize()); + for (std::size_t i = shape.size(); i-- > 0;) { + strides[i] = stride; + stride *= shape[i]; + } + + if (info.GetElementCount() == 0) { + // Nothing to share. An owning empty array avoids handing numpy a base + // object for a buffer that may not exist. + return py::array(dtype, shape, strides); + } + + auto* owned = new Ort::Value(std::move(value)); + py::capsule owner(owned, [](void* pointer) { + delete static_cast(pointer); + }); + return py::array(dtype, shape, strides, owned->GetTensorMutableRawData(), owner); +} + +py::tuple run_engine(anytime::Engine& engine, const std::string& variant, + const py::dict& feeds) { + // Built while the GIL is held. `retained` keeps every numpy buffer alive + // across the release below; the views point into those buffers. + std::vector retained; + std::vector> views; + retained.reserve(feeds.size()); + views.reserve(feeds.size()); + + for (const auto item : feeds) { + const auto name = py::cast(item.first); + // ONNX Runtime reads the buffer directly, so it has to be C-contiguous. + // ensure() returns the same object when it already is, and converts only + // when it is not, rather than misreading a strided array. + py::array array = py::array::ensure(item.second, py::array::c_style); + if (!array) { + throw std::invalid_argument("feed '" + name + "' is not array-like"); + } + + anytime::TensorView view; + view.dtype = dtype_from_numpy(array, name); + view.shape.assign(array.shape(), array.shape() + array.ndim()); + view.data = array.data(); + + retained.push_back(std::move(array)); + views.emplace_back(name, std::move(view)); + } + + anytime::RunResult result; + { + py::gil_scoped_release release; + result = engine.run(variant, views); + } + + py::list outputs; + for (auto& value : result.outputs) { + outputs.append(wrap_output(std::move(value))); + } + return py::make_tuple(std::move(outputs), result.latency_ms); +} + +} // namespace + +PYBIND11_MODULE(anytime_runtime, module) { + module.doc() = + "In-process ONNX Runtime engine for the Anytime Inference Planner.\n\n" + "Tensors cross the boundary as borrowed buffers rather than copies, and " + "the GIL is released around inference so a pool of workers runs " + "concurrently."; + + module.def("onnxruntime_version", []() { + return std::string(OrtGetApiBase()->GetVersionString()); + }, "Version of the ONNX Runtime this extension is linked against.\n\n" + "Must equal onnxruntime.__version__: both libraries are loaded into this " + "process, and Stage 1 measured a 7.6x difference in inference time from a " + "mismatch between them."); + + module.def("ort_api_version", []() { return ORT_API_VERSION; }, + "ORT_API_VERSION of the headers this extension was compiled " + "against."); + + py::class_(module, "Engine", + "Holds one ONNX Runtime session per named variant.\n\n" + "Thread counts default to one of each so that N pooled engines behave as " + "N independent single-threaded servers, which is what makes the queueing " + "model in the admission controller valid.") + .def(py::init([](const std::vector>& models, + int intra_op_threads, int inter_op_threads) { + return std::make_unique(models, intra_op_threads, + inter_op_threads); + }), + py::arg("models"), py::arg("intra_op_threads") = 1, + py::arg("inter_op_threads") = 1, + "models is a sequence of (variant, onnx_path) pairs.") + .def("run", &run_engine, py::arg("variant"), py::arg("feeds"), + "Run one variant.\n\n" + "Returns (outputs, latency_ms), where outputs are numpy views over " + "ONNX Runtime's buffers in the order the graph declares them, and " + "latency_ms is the time spent inside Session::Run.\n\n" + "Feeds the graph does not declare are dropped, since variants of one " + "task can declare different inputs and callers pass the union. A " + "declared input that is missing raises instead: running on a partial " + "feed would silently produce wrong output.") + .def_property_readonly("variants", &anytime::Engine::variants, + "Loaded variant names.") + .def("input_names", &anytime::Engine::input_names, py::arg("variant"), + "Input names the variant's graph declares.") + .def("output_names", &anytime::Engine::output_names, py::arg("variant"), + "Output names the variant's graph declares, in run order."); +} diff --git a/runtime/cmake/ResolveOnnxRuntime.cmake b/runtime/cmake/ResolveOnnxRuntime.cmake new file mode 100644 index 0000000..be2bcb1 --- /dev/null +++ b/runtime/cmake/ResolveOnnxRuntime.cmake @@ -0,0 +1,264 @@ +# Resolve an ONNX Runtime SDK that matches the installed onnxruntime wheel. +# +# The extension and the Python wheel run in one process, so their ONNX Runtime +# versions cannot be allowed to differ. Stage 1 built the worker against 1.20.1 +# while the wheel was 1.26.0 and measured DistilBERT at 98.9 ms against 13.0 ms +# inside session->Run(); every service time the planner used was wrong by almost +# an order of magnitude. Under pybind11 a mismatch is worse than a performance +# cliff, because both copies of the library are loaded at once. +# +# The version is therefore never written down twice. It is read from the wheel +# that the target interpreter will import at runtime, and everything else is +# derived from it: +# +# 1. ONNXRUNTIME_ROOT_PATH, if set, must contain a VERSION_NUMBER equal to the +# wheel version. Configuration fails otherwise. +# 2. Otherwise the matching release archive is downloaded once into a cache +# directory and reused. +# +# Sets, in the parent scope: +# ANYTIME_ORT_ROOT directory holding include/ and lib/ +# ANYTIME_ORT_VERSION version string, as reported by the wheel +# ANYTIME_ORT_LIBRARY full path to the shared library +# ANYTIME_ORT_API_VERSION ORT_API_VERSION as written in the resolved headers + +include_guard(GLOBAL) + +function(_anytime_ort_wheel_version out_var) + if(NOT Python_EXECUTABLE) + message(FATAL_ERROR + "Python_EXECUTABLE is not set, so the onnxruntime wheel version cannot " + "be read. Build through pip (which supplies it via scikit-build-core) " + "or pass -DPython_EXECUTABLE=/path/to/python.") + endif() + + # Probed twice, in order of authority. + # + # First with PYTHONPATH cleared. pip builds in an isolated environment layered + # onto the target interpreter through that variable, and the overlay carries + # its own onnxruntime, which can be a different version from the one the target + # environment imports at runtime. Reading the overlay when the target already + # has a wheel would reintroduce the mismatch this module exists to prevent, + # through the build system instead of through the developer. + execute_process( + COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONPATH + "${Python_EXECUTABLE}" -c + "import onnxruntime; print(onnxruntime.__version__)" + OUTPUT_VARIABLE version + ERROR_VARIABLE target_error + RESULT_VARIABLE probe_status + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(probe_status EQUAL 0) + message(STATUS "onnxruntime resolved from the target environment") + set(${out_var} "${version}" PARENT_SCOPE) + return() + endif() + + # Then with the build environment left intact. On a first install into a clean + # environment there is no wheel to read yet: pip installs build requirements, + # builds, and only then installs runtime dependencies. The build requirement + # pins the same specifier as the runtime dependency, so the version resolved + # here is the one pip is about to install. load_extension() re-checks the + # equality at import time, which is what catches the case where it is not. + execute_process( + COMMAND "${Python_EXECUTABLE}" -c + "import onnxruntime; print(onnxruntime.__version__)" + OUTPUT_VARIABLE version + ERROR_VARIABLE build_error + RESULT_VARIABLE probe_status + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(probe_status EQUAL 0) + message(STATUS + "onnxruntime is not installed in the target environment yet; resolved " + "${version} from the build environment instead. The version is " + "re-checked when anytime_runtime is imported.") + set(${out_var} "${version}" PARENT_SCOPE) + return() + endif() + + message(FATAL_ERROR + "Could not import onnxruntime with ${Python_EXECUTABLE}, with or without " + "the build environment on the path. The extension is linked against the " + "same ONNX Runtime that interpreter imports at runtime, so a wheel has to " + "be resolvable:\n" + " ${Python_EXECUTABLE} -m pip install onnxruntime\n" + "target environment:\n${target_error}\n" + "build environment:\n${build_error}") +endfunction() + +# Release archives are published per platform under a stable naming scheme. +function(_anytime_ort_archive_name version out_name out_extension) + if(APPLE) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64") + set(platform "osx-arm64") + else() + set(platform "osx-x86_64") + endif() + set(extension "tgz") + elseif(UNIX) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64") + set(platform "linux-aarch64") + else() + set(platform "linux-x64") + endif() + set(extension "tgz") + else() + # Windows archives are zips with a different internal layout. Rather than + # guess, ask for an explicit SDK. + message(FATAL_ERROR + "Automatic ONNX Runtime download is implemented for macOS and Linux " + "only. Download the ${version} release for this platform from " + "https://github.com/microsoft/onnxruntime/releases and pass " + "-DONNXRUNTIME_ROOT_PATH=/path/to/onnxruntime.") + endif() + + set(${out_name} "onnxruntime-${platform}-${version}" PARENT_SCOPE) + set(${out_extension} "${extension}" PARENT_SCOPE) +endfunction() + +# The unpacked tree is the directory holding include/. Some releases nest a +# versioned directory inside the archive and some do not, so locate it rather +# than assuming either layout. +function(_anytime_ort_find_root search_dir out_var) + if(EXISTS "${search_dir}/include/onnxruntime_c_api.h") + set(${out_var} "${search_dir}" PARENT_SCOPE) + return() + endif() + file(GLOB candidates LIST_DIRECTORIES true "${search_dir}/*") + foreach(candidate IN LISTS candidates) + if(IS_DIRECTORY "${candidate}" AND + EXISTS "${candidate}/include/onnxruntime_c_api.h") + set(${out_var} "${candidate}" PARENT_SCOPE) + return() + endif() + endforeach() + set(${out_var} "" PARENT_SCOPE) +endfunction() + +function(_anytime_ort_download version out_root) + _anytime_ort_archive_name("${version}" archive_name archive_extension) + + # A durable cache, so the SDK is fetched once per version per machine rather + # than once per build tree. Stage 1 kept it in a temporary directory and lost + # it between sessions. + if(DEFINED ENV{ANYTIME_ORT_CACHE}) + set(cache_root "$ENV{ANYTIME_ORT_CACHE}") + elseif(DEFINED ENV{XDG_CACHE_HOME}) + set(cache_root "$ENV{XDG_CACHE_HOME}/anytime-inference-planner") + else() + set(cache_root "$ENV{HOME}/.cache/anytime-inference-planner") + endif() + set(unpacked "${cache_root}/${archive_name}") + + _anytime_ort_find_root("${unpacked}" cached_root) + if(cached_root) + message(STATUS "ONNX Runtime ${version}: using cached SDK at ${cached_root}") + set(${out_root} "${cached_root}" PARENT_SCOPE) + return() + endif() + + set(url "https://github.com/microsoft/onnxruntime/releases/download/v${version}/${archive_name}.${archive_extension}") + set(archive "${cache_root}/${archive_name}.${archive_extension}") + message(STATUS "ONNX Runtime ${version}: downloading ${url}") + + file(MAKE_DIRECTORY "${cache_root}") + file(DOWNLOAD "${url}" "${archive}" STATUS download_status SHOW_PROGRESS) + list(GET download_status 0 download_code) + if(NOT download_code EQUAL 0) + list(GET download_status 1 download_message) + file(REMOVE "${archive}") + message(FATAL_ERROR + "Failed to download ONNX Runtime ${version} from ${url}: " + "${download_message}\nDownload it manually and pass " + "-DONNXRUNTIME_ROOT_PATH=/path/to/onnxruntime instead.") + endif() + + file(MAKE_DIRECTORY "${unpacked}") + file(ARCHIVE_EXTRACT INPUT "${archive}" DESTINATION "${unpacked}") + file(REMOVE "${archive}") + + _anytime_ort_find_root("${unpacked}" downloaded_root) + if(NOT downloaded_root) + message(FATAL_ERROR + "Downloaded ONNX Runtime ${version} but found no include/ directory " + "under ${unpacked}.") + endif() + set(${out_root} "${downloaded_root}" PARENT_SCOPE) +endfunction() + +function(anytime_resolve_onnxruntime) + _anytime_ort_wheel_version(wheel_version) + message(STATUS "onnxruntime wheel reports version ${wheel_version}") + + if(NOT ONNXRUNTIME_ROOT_PATH AND DEFINED ENV{ONNXRUNTIME_ROOT_PATH}) + set(ONNXRUNTIME_ROOT_PATH "$ENV{ONNXRUNTIME_ROOT_PATH}") + endif() + + if(ONNXRUNTIME_ROOT_PATH) + _anytime_ort_find_root("${ONNXRUNTIME_ROOT_PATH}" root) + if(NOT root) + message(FATAL_ERROR + "ONNXRUNTIME_ROOT_PATH=${ONNXRUNTIME_ROOT_PATH} contains no " + "include/onnxruntime_c_api.h.") + endif() + + if(NOT EXISTS "${root}/VERSION_NUMBER") + message(FATAL_ERROR + "${root} has no VERSION_NUMBER, so its version cannot be checked " + "against the ${wheel_version} wheel. Point ONNXRUNTIME_ROOT_PATH at " + "an unpacked release archive, or unset it to download one.") + endif() + file(READ "${root}/VERSION_NUMBER" sdk_version) + string(STRIP "${sdk_version}" sdk_version) + + if(NOT sdk_version VERSION_EQUAL wheel_version) + message(FATAL_ERROR + "ONNX Runtime version mismatch. The SDK at ${root} is " + "${sdk_version}; the onnxruntime wheel that will be imported in the " + "same process is ${wheel_version}. These must be equal: the two " + "libraries are loaded together, and Stage 1 measured a 7.6x " + "difference in session->Run() from exactly this mismatch. Unset " + "ONNXRUNTIME_ROOT_PATH to download the matching SDK.") + endif() + message(STATUS "ONNX Runtime ${sdk_version}: using SDK at ${root}") + else() + _anytime_ort_download("${wheel_version}" root) + endif() + + # find_library caches its result, so a changed root would otherwise keep + # linking the previously resolved library against the new headers. That + # mismatch surfaces only at runtime, as "The requested API version [N] is not + # available". + if(DEFINED CACHE{ANYTIME_ORT_LIBRARY} AND + NOT ANYTIME_ORT_LIBRARY MATCHES "^${root}/") + message(STATUS "ONNX Runtime root changed; re-resolving the library") + unset(ANYTIME_ORT_LIBRARY CACHE) + endif() + find_library(ANYTIME_ORT_LIBRARY + NAMES onnxruntime + PATHS "${root}/lib" + NO_DEFAULT_PATH + REQUIRED) + + # Read ORT_API_VERSION out of the headers that were just resolved and assert + # it in the translation units. This catches a stray onnxruntime_c_api.h + # arriving from some other include path, without assuming anything about how + # release versions map onto API versions. + file(STRINGS "${root}/include/onnxruntime_c_api.h" api_version_line + REGEX "^#define ORT_API_VERSION[ \t]+[0-9]+") + if(NOT api_version_line) + message(FATAL_ERROR + "Could not read ORT_API_VERSION from " + "${root}/include/onnxruntime_c_api.h.") + endif() + string(REGEX MATCH "[0-9]+" api_version "${api_version_line}") + + message(STATUS "ONNX Runtime library: ${ANYTIME_ORT_LIBRARY}") + message(STATUS "ONNX Runtime API version: ${api_version}") + + set(ANYTIME_ORT_ROOT "${root}" PARENT_SCOPE) + set(ANYTIME_ORT_VERSION "${wheel_version}" PARENT_SCOPE) + set(ANYTIME_ORT_API_VERSION "${api_version}" PARENT_SCOPE) +endfunction() diff --git a/runtime/include/anytime/engine.hpp b/runtime/include/anytime/engine.hpp new file mode 100644 index 0000000..3258281 --- /dev/null +++ b/runtime/include/anytime/engine.hpp @@ -0,0 +1,88 @@ +// In-process inference engine. +// +// Owns one ONNX Runtime session per named variant and runs them synchronously. +// This replaces the line-delimited JSON worker from Stage 1: the transport is now +// a function call, so there is no framing, no base64, and no copy in either +// direction. +// +// Threading in this phase mirrors what the subprocess pool did. One Engine holds +// its own sessions, and the Python pool holds one Engine per slot, so N workers +// remain N independent single-threaded servers and the M/M/c model the admission +// controller uses stays valid. Sharing one session across the pool would save +// memory and is what the scheduler will do once it lands, but it would change the +// concurrency model in the same commit that introduces the engine. + +#ifndef ANYTIME_ENGINE_HPP +#define ANYTIME_ENGINE_HPP + +#include + +#include +#include +#include +#include +#include + +#include "anytime/tensor.hpp" + +namespace anytime { + +// One loaded graph, with the input and output names it declares. +class Model { +public: + Model(Ort::Env& env, const std::string& path, int intra_op_threads, + int inter_op_threads); + + const std::vector& input_names() const { return input_names_; } + const std::vector& output_names() const { return output_names_; } + bool declares_input(const std::string& name) const; + Ort::Session& session() { return *session_; } + +private: + std::unique_ptr session_; + std::vector input_names_; + std::vector output_names_; +}; + +// Outputs of one run, in the order the graph declares them, plus the time spent +// inside Session::Run. The values own their buffers; the bindings hand those +// buffers to numpy without copying. +struct RunResult { + std::vector outputs; + double latency_ms = 0.0; +}; + +class Engine { +public: + // Each entry maps a variant name to an ONNX graph path. Threads default to + // one of each so a pooled engine behaves as a single server, matching how + // the service times in configs/serving.yaml were measured. + explicit Engine(const std::vector>& models, + int intra_op_threads = 1, int inter_op_threads = 1); + + // Runs `variant` over `feeds`. + // + // Feeds a graph does not declare are dropped rather than rejected: variants + // of one task can declare different inputs (a DistilBERT graph takes + // input_ids and attention_mask, a BERT graph also takes token_type_ids), so + // callers pass the union. A declared input that is missing is an error, since + // running on a partial feed would silently produce wrong logits. + RunResult run(const std::string& variant, + const std::vector>& feeds); + + std::vector variants() const; + const std::vector& input_names(const std::string& variant) const; + const std::vector& output_names(const std::string& variant) const; + +private: + Model& lookup(const std::string& variant); + const Model& lookup(const std::string& variant) const; + + Ort::Env env_; + Ort::MemoryInfo memory_; + std::map> models_; +}; + +} // namespace anytime + +#endif // ANYTIME_ENGINE_HPP diff --git a/runtime/include/anytime/tensor.hpp b/runtime/include/anytime/tensor.hpp new file mode 100644 index 0000000..2f4c774 --- /dev/null +++ b/runtime/include/anytime/tensor.hpp @@ -0,0 +1,58 @@ +// Element types and borrowed tensor views. +// +// The engine never owns input buffers. Callers hand it a pointer, a shape, and a +// dtype; ONNX Runtime reads through that pointer during Run. This is what makes +// the numpy boundary free of copies, and it means the caller has to keep the +// buffer alive for the duration of the call. The bindings do that by holding the +// numpy references on the stack across the whole run. + +#ifndef ANYTIME_TENSOR_HPP +#define ANYTIME_TENSOR_HPP + +#include + +#include +#include +#include +#include + +namespace anytime { + +// Element types accepted on graph inputs. Deliberately narrow: exported graphs +// declare int64 token ids and masks and float32 activations, and an unsupported +// dtype has to fail loudly rather than be reinterpreted. Outputs are mapped back +// from whatever the graph produces, which is a wider set. +enum class DType { + Float32, + Float64, + Int32, + Int64, + Bool, +}; + +std::size_t dtype_size(DType dtype); +const char* dtype_name(DType dtype); +ONNXTensorElementDataType dtype_to_ort(DType dtype); +DType dtype_from_ort(ONNXTensorElementDataType type); + +// Name of an ONNX element type, for error messages about types the engine does +// not accept. +std::string ort_type_name(ONNXTensorElementDataType type); + +// A borrowed, C-contiguous buffer. Non-owning by design; see the file comment. +struct TensorView { + const void* data = nullptr; + std::vector shape; + DType dtype = DType::Float32; + + std::size_t element_count() const; + std::size_t byte_count() const; +}; + +// Wraps a borrowed buffer as an Ort::Value. No copy: the returned value points +// into view.data, which must outlive it. +Ort::Value borrow_as_tensor(const TensorView& view, const OrtMemoryInfo* memory); + +} // namespace anytime + +#endif // ANYTIME_TENSOR_HPP diff --git a/runtime/src/engine.cpp b/runtime/src/engine.cpp new file mode 100644 index 0000000..dfd7f03 --- /dev/null +++ b/runtime/src/engine.cpp @@ -0,0 +1,158 @@ +#include "anytime/engine.hpp" + +#include +#include +#include +#include + +namespace anytime { +namespace { + +std::string join(const std::vector& parts) { + std::ostringstream out; + for (std::size_t i = 0; i < parts.size(); ++i) { + if (i) out << ", "; + out << parts[i]; + } + return out.str(); +} + +} // namespace + +Model::Model(Ort::Env& env, const std::string& path, int intra_op_threads, + int inter_op_threads) { + Ort::SessionOptions options; + options.SetIntraOpNumThreads(intra_op_threads); + options.SetInterOpNumThreads(inter_op_threads); + options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL); + + session_ = std::make_unique(env, path.c_str(), options); + + Ort::AllocatorWithDefaultOptions allocator; + const std::size_t input_count = session_->GetInputCount(); + input_names_.reserve(input_count); + for (std::size_t i = 0; i < input_count; ++i) { + auto name = session_->GetInputNameAllocated(i, allocator); + input_names_.emplace_back(name.get()); + } + const std::size_t output_count = session_->GetOutputCount(); + output_names_.reserve(output_count); + for (std::size_t i = 0; i < output_count; ++i) { + auto name = session_->GetOutputNameAllocated(i, allocator); + output_names_.emplace_back(name.get()); + } +} + +bool Model::declares_input(const std::string& name) const { + return std::find(input_names_.begin(), input_names_.end(), name) != + input_names_.end(); +} + +Engine::Engine(const std::vector>& models, + int intra_op_threads, int inter_op_threads) + : env_(ORT_LOGGING_LEVEL_WARNING, "anytime_runtime"), + memory_(Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeDefault)) { + if (models.empty()) { + throw std::invalid_argument("Engine needs at least one model"); + } + for (const auto& [variant, path] : models) { + if (models_.count(variant)) { + throw std::invalid_argument("duplicate variant: " + variant); + } + models_[variant] = std::make_unique(env_, path, intra_op_threads, + inter_op_threads); + } +} + +Model& Engine::lookup(const std::string& variant) { + const auto it = models_.find(variant); + if (it == models_.end()) { + // runtime_error rather than out_of_range: pybind11 maps it to + // RuntimeError, which is the contract every backend shares for "the + // runtime could not serve this request". Malformed arguments (a dtype the + // engine does not accept) stay invalid_argument and surface as ValueError. + throw std::runtime_error("unknown variant: " + variant + " (loaded: " + + join(variants()) + ")"); + } + return *it->second; +} + +const Model& Engine::lookup(const std::string& variant) const { + const auto it = models_.find(variant); + if (it == models_.end()) { + // runtime_error rather than out_of_range: pybind11 maps it to + // RuntimeError, which is the contract every backend shares for "the + // runtime could not serve this request". Malformed arguments (a dtype the + // engine does not accept) stay invalid_argument and surface as ValueError. + throw std::runtime_error("unknown variant: " + variant + " (loaded: " + + join(variants()) + ")"); + } + return *it->second; +} + +std::vector Engine::variants() const { + std::vector names; + names.reserve(models_.size()); + for (const auto& [variant, model] : models_) { + names.push_back(variant); + } + return names; +} + +const std::vector& Engine::input_names(const std::string& variant) const { + return lookup(variant).input_names(); +} + +const std::vector& Engine::output_names(const std::string& variant) const { + return lookup(variant).output_names(); +} + +RunResult Engine::run(const std::string& variant, + const std::vector>& feeds) { + Model& model = lookup(variant); + + std::vector input_names; + std::vector inputs; + input_names.reserve(feeds.size()); + inputs.reserve(feeds.size()); + + for (const auto& [name, view] : feeds) { + if (!model.declares_input(name)) continue; + input_names.push_back(name.c_str()); + inputs.push_back(borrow_as_tensor(view, memory_)); + } + + if (inputs.size() != model.input_names().size()) { + std::vector missing; + for (const auto& declared : model.input_names()) { + const bool supplied = std::any_of( + feeds.begin(), feeds.end(), + [&declared](const auto& feed) { return feed.first == declared; }); + if (!supplied) missing.push_back(declared); + } + throw std::runtime_error("variant " + variant + " is missing input(s): " + + join(missing) + " (declares: " + + join(model.input_names()) + ")"); + } + + std::vector output_names; + output_names.reserve(model.output_names().size()); + for (const auto& name : model.output_names()) { + output_names.push_back(name.c_str()); + } + + const auto start = std::chrono::steady_clock::now(); + std::vector outputs = model.session().Run( + Ort::RunOptions{nullptr}, + input_names.data(), inputs.data(), inputs.size(), + output_names.data(), output_names.size()); + const auto end = std::chrono::steady_clock::now(); + + RunResult result; + result.outputs = std::move(outputs); + result.latency_ms = + std::chrono::duration(end - start).count(); + return result; +} + +} // namespace anytime diff --git a/runtime/src/tensor.cpp b/runtime/src/tensor.cpp new file mode 100644 index 0000000..e7fad2c --- /dev/null +++ b/runtime/src/tensor.cpp @@ -0,0 +1,115 @@ +#include "anytime/tensor.hpp" + +#include + +// The headers this compiles against must be the ones CMake resolved from the SDK +// that matches the onnxruntime wheel. A stray onnxruntime_c_api.h arriving from +// another include path would compile cleanly and then disagree with the linked +// library at runtime, which is the failure mode this whole build path exists to +// prevent. +#ifndef ANYTIME_EXPECTED_ORT_API_VERSION +#error "ANYTIME_EXPECTED_ORT_API_VERSION is not defined; configure through runtime/CMakeLists.txt" +#endif +static_assert(ORT_API_VERSION == ANYTIME_EXPECTED_ORT_API_VERSION, + "onnxruntime_c_api.h does not match the SDK CMake resolved. The " + "include path is picking up a different ONNX Runtime."); + +namespace anytime { + +std::size_t dtype_size(DType dtype) { + switch (dtype) { + case DType::Float32: return sizeof(float); + case DType::Float64: return sizeof(double); + case DType::Int32: return sizeof(int32_t); + case DType::Int64: return sizeof(int64_t); + case DType::Bool: return sizeof(bool); + } + throw std::runtime_error("unhandled dtype"); +} + +const char* dtype_name(DType dtype) { + switch (dtype) { + case DType::Float32: return "float32"; + case DType::Float64: return "float64"; + case DType::Int32: return "int32"; + case DType::Int64: return "int64"; + case DType::Bool: return "bool"; + } + throw std::runtime_error("unhandled dtype"); +} + +ONNXTensorElementDataType dtype_to_ort(DType dtype) { + switch (dtype) { + case DType::Float32: return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT; + case DType::Float64: return ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE; + case DType::Int32: return ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32; + case DType::Int64: return ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64; + case DType::Bool: return ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL; + } + throw std::runtime_error("unhandled dtype"); +} + +DType dtype_from_ort(ONNXTensorElementDataType type) { + switch (type) { + case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT: return DType::Float32; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE: return DType::Float64; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32: return DType::Int32; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64: return DType::Int64; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL: return DType::Bool; + default: + throw std::runtime_error("unsupported ONNX element type: " + + ort_type_name(type)); + } +} + +std::string ort_type_name(ONNXTensorElementDataType type) { + switch (type) { + case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT: return "float32"; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE: return "float64"; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16: return "float16"; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16: return "bfloat16"; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8: return "int8"; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8: return "uint8"; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16: return "int16"; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16: return "uint16"; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32: return "int32"; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32: return "uint32"; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64: return "int64"; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64: return "uint64"; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL: return "bool"; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING: return "string"; + default: return "unknown"; + } +} + +std::size_t TensorView::element_count() const { + std::size_t count = 1; + for (const int64_t dimension : shape) { + if (dimension < 0) { + throw std::runtime_error("tensor shape has a negative dimension"); + } + count *= static_cast(dimension); + } + return count; +} + +std::size_t TensorView::byte_count() const { + return element_count() * dtype_size(dtype); +} + +Ort::Value borrow_as_tensor(const TensorView& view, const OrtMemoryInfo* memory) { + if (view.data == nullptr) { + throw std::runtime_error("tensor view has no data pointer"); + } + // CreateTensor over caller memory: ONNX Runtime reads through the pointer and + // does not take ownership, so nothing is copied on the way in. + return Ort::Value::CreateTensor( + memory, + const_cast(view.data), + view.byte_count(), + view.shape.data(), + view.shape.size(), + dtype_to_ort(view.dtype)); +} + +} // namespace anytime diff --git a/src/anytime_serving/serving/__init__.py b/src/anytime_serving/serving/__init__.py index 4ea7620..4c326ac 100644 --- a/src/anytime_serving/serving/__init__.py +++ b/src/anytime_serving/serving/__init__.py @@ -3,11 +3,14 @@ from .admission import AdmissionDecision, MMcAdmissionController, erlang_b, erlang_c from .load_monitor import LoadMonitor, LoadSample from .onnx_runtime import ( + BACKENDS, InferenceRequest, InferenceResponse, RuntimeClient, RuntimePool, + extension_available, find_runtime_binary, + load_extension, ) from .selector import AdaptiveSelector, SelectionDecision, VariantProfile from .server import AdaptiveServer, ServedRequest, ServerStats, drive_workload, poisson_arrivals @@ -22,11 +25,14 @@ "AdaptiveSelector", "SelectionDecision", "VariantProfile", + "BACKENDS", "RuntimeClient", "RuntimePool", "InferenceRequest", "InferenceResponse", + "extension_available", "find_runtime_binary", + "load_extension", "AdaptiveServer", "ServedRequest", "ServerStats", diff --git a/src/anytime_serving/serving/onnx_runtime.py b/src/anytime_serving/serving/onnx_runtime.py index 02acb0d..654cf9f 100644 --- a/src/anytime_serving/serving/onnx_runtime.py +++ b/src/anytime_serving/serving/onnx_runtime.py @@ -1,13 +1,23 @@ -"""Client for the C++ ONNX runtime worker. - -The C++ binary (``runtime_cpp/``) accepts line-delimited JSON requests on -stdin and writes line-delimited JSON responses to stdout. This module wraps -that protocol and provides a worker pool for concurrent dispatch. - -A pure-Python fallback worker is also provided. It runs ONNX Runtime in-process -and is used when the C++ binary has not been built (e.g. on CI without a C++ -toolchain). The protocol it implements is identical, so unit tests exercise -the same code path the production server uses. +"""Client for the inference runtime. + +Three backends implement one interface, all taking and returning numpy arrays: + +``extension`` + The ``anytime_runtime`` pybind11 module, which runs ONNX Runtime in this + process. Tensors are borrowed rather than copied and the GIL is released + around inference, so a pool of workers runs concurrently. This is the + production path. +``subprocess`` + The Stage 1 worker, spawned per pool slot and driven over line-delimited + JSON. Retained only so the extension can be checked against it; the encoding + cost it pays is the reason it is being replaced. +``python`` + ONNX Runtime through its own Python wheel. The reference implementation the + tests compare the extension against, and the fallback where the extension + has not been built. + +The backend is chosen automatically unless ``backend=`` names one. Tests pin it +explicitly so a parity failure cannot be hidden by a silent fallback. """ from __future__ import annotations @@ -22,7 +32,7 @@ import uuid from dataclasses import dataclass, field from pathlib import Path -from typing import IO +from typing import IO, Any import numpy as np @@ -30,6 +40,50 @@ LOGGER = get_logger("serving.onnx_runtime") +BACKENDS = ("extension", "subprocess", "python") + +_extension: Any | None = None + + +def load_extension() -> Any: + """Import ``anytime_runtime``, refusing a version mismatch. + + The extension and the ``onnxruntime`` wheel are two independent copies of + ONNX Runtime loaded into one process. Stage 1 built the worker against 1.20.1 + while profiling against the 1.26.0 wheel and measured DistilBERT at 98.9 ms + versus 13.0 ms inside ``session->Run()``; every service time the planner used + was wrong by almost an order of magnitude, and nothing failed. The build + enforces this equality at configure time, and this is the second gate, in + case the extension is carried to an environment with a different wheel. + """ + global _extension + if _extension is not None: + return _extension + + import anytime_runtime + import onnxruntime + + linked = anytime_runtime.onnxruntime_version() + installed = onnxruntime.__version__ + if linked != installed: + raise RuntimeError( + f"anytime_runtime links ONNX Runtime {linked} but the installed wheel is " + f"{installed}. Both are loaded into this process, and a mismatch measured " + f"a 7.6x difference in inference time during Stage 1. Rebuild the " + f"extension against the current wheel: pip install -e . --no-cache-dir" + ) + _extension = anytime_runtime + return _extension + + +def extension_available() -> bool: + """Whether the in-process extension can be imported and matches the wheel.""" + try: + load_extension() + except (ImportError, RuntimeError): + return False + return True + @dataclass class InferenceRequest: @@ -60,13 +114,101 @@ def feed(self, default_input_name: str) -> dict[str, np.ndarray]: @dataclass class InferenceResponse: + """Result of one inference. + + Under the extension backend ``logits`` is a view over the buffer ONNX Runtime + allocated, not a copy, so holding the response holds that buffer. Copy it if + it needs to outlive the request. + """ + request_id: str logits: np.ndarray runtime_latency_ms: float wall_latency_ms: float +class _RuntimeBackend: + """Runs one variant over a name -> tensor mapping. + + Implementations return the first graph output and the time spent inside + inference, excluding anything the client adds around it. + """ + + name = "abstract" + + def infer(self, variant: str, feeds: dict[str, np.ndarray]) -> tuple[np.ndarray, float]: + raise NotImplementedError + + def close(self) -> None: + raise NotImplementedError + + +class _ExtensionBackend(_RuntimeBackend): + """In-process ONNX Runtime through the ``anytime_runtime`` extension.""" + + name = "extension" + + def __init__(self, model_paths: dict[str, Path]) -> None: + extension = load_extension() + self._engine = extension.Engine([(v, str(p)) for v, p in model_paths.items()]) + self._variants = frozenset(self._engine.variants) + + def infer(self, variant: str, feeds: dict[str, np.ndarray]) -> tuple[np.ndarray, float]: + if variant not in self._variants: + raise RuntimeError(f"unknown variant {variant!r}; loaded: {sorted(self._variants)}") + outputs, latency_ms = self._engine.run(variant, feeds) + return outputs[0], float(latency_ms) + + def close(self) -> None: + # Dropping the engine releases the sessions and their arenas. + self._engine = None + + +class _PythonBackend(_RuntimeBackend): + """ONNX Runtime through its Python wheel. The reference implementation.""" + + name = "python" + + def __init__(self, model_paths: dict[str, Path]) -> None: + import onnxruntime as ort # local import so the dep is optional at import time + + options = ort.SessionOptions() + options.intra_op_num_threads = 1 + options.inter_op_num_threads = 1 + options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL + self._sessions = { + variant: ort.InferenceSession( + str(path), sess_options=options, providers=["CPUExecutionProvider"] + ) + for variant, path in model_paths.items() + } + self._declared_inputs = { + variant: {spec.name for spec in session.get_inputs()} + for variant, session in self._sessions.items() + } + + def infer(self, variant: str, feeds: dict[str, np.ndarray]) -> tuple[np.ndarray, float]: + if variant not in self._sessions: + raise RuntimeError(f"unknown variant {variant!r}; loaded: {sorted(self._sessions)}") + # Variants of one task can declare different inputs, so the caller sends + # the union and each graph takes the subset it declares. Mirrors the + # filtering in runtime/src/engine.cpp. + declared = self._declared_inputs[variant] + fed = {name: tensor for name, tensor in feeds.items() if name in declared} + missing = declared - fed.keys() + if missing: + raise RuntimeError(f"variant {variant!r} is missing input(s): {sorted(missing)}") + start = time.perf_counter() + outputs = self._sessions[variant].run(None, fed) + elapsed_ms = (time.perf_counter() - start) * 1000.0 + return outputs[0], elapsed_ms + + def close(self) -> None: + self._sessions.clear() + + def _encode(array: np.ndarray) -> dict: + """Encode a tensor for the subprocess protocol.""" contiguous = np.ascontiguousarray(array) return { "shape": list(contiguous.shape), @@ -76,23 +218,21 @@ def _encode(array: np.ndarray) -> dict: def _decode(payload: dict) -> np.ndarray: + """Decode a tensor from the subprocess protocol.""" raw = base64.b64decode(payload["data"]) dtype = np.dtype(payload["dtype"]) return np.frombuffer(raw, dtype=dtype).reshape(payload["shape"]) -class _RuntimeBackend: - """Abstract backend that takes a request dict and returns a response dict.""" - - def submit(self, request: dict) -> dict: - raise NotImplementedError - - def close(self) -> None: - raise NotImplementedError +class _SubprocessBackend(_RuntimeBackend): + """The Stage 1 worker, over line-delimited JSON on stdin and stdout. + Kept so the extension can be validated against the implementation it + replaces. Every tensor is base64-encoded, parsed, and copied in each + direction, which is exactly what the extension removes. + """ -class _SubprocessBackend(_RuntimeBackend): - """Backend backed by the C++ binary, communicating via stdin/stdout.""" + name = "subprocess" def __init__(self, binary: Path, model_paths: dict[str, Path]) -> None: args = [str(binary)] @@ -116,16 +256,20 @@ def __init__(self, binary: Path, model_paths: dict[str, Path]) -> None: self._stdout: IO[str] = self._process.stdout self._stderr: IO[str] = self._process.stderr - # Drain handshake line (the C++ binary prints "ready" once both models - # have loaded). + # Drain handshake line (the worker prints "ready" once every model has + # loaded). handshake = self._stdout.readline().strip() if handshake != "ready": stderr = self._stderr.read() raise RuntimeError(f"C++ runtime failed to start: {handshake!r} ({stderr})") - def submit(self, request: dict) -> dict: - line = json.dumps(request) + "\n" - self._stdin.write(line) + def infer(self, variant: str, feeds: dict[str, np.ndarray]) -> tuple[np.ndarray, float]: + request = { + "request_id": uuid.uuid4().hex, + "variant": variant, + "inputs": {name: _encode(tensor) for name, tensor in feeds.items()}, + } + self._stdin.write(json.dumps(request) + "\n") self._stdin.flush() response_line = self._stdout.readline() if not response_line: @@ -135,11 +279,8 @@ def submit(self, request: dict) -> dict: # The worker reports a recoverable problem (an unknown variant, say) as an # error field and stays alive for the next request. if "error" in response: - raise RuntimeError( - f"C++ runtime rejected request {response.get('request_id', '?')}: " - f"{response['error']}" - ) - return response + raise RuntimeError(f"C++ runtime rejected the request: {response['error']}") + return _decode(response["logits"]), float(response["latency_ms"]) def close(self) -> None: if self._process.poll() is None: @@ -161,89 +302,71 @@ def close(self) -> None: pass -class _PythonBackend(_RuntimeBackend): - """Pure-Python ONNX Runtime backend. Used when the C++ binary is absent.""" - - def __init__(self, model_paths: dict[str, Path]) -> None: - import onnxruntime as ort # local import so the dep is optional at import time - - options = ort.SessionOptions() - options.intra_op_num_threads = 1 - self._sessions = { - variant: ort.InferenceSession(str(path), sess_options=options) - for variant, path in model_paths.items() - } - self._declared_inputs = { - variant: {spec.name for spec in session.get_inputs()} - for variant, session in self._sessions.items() - } - - def submit(self, request: dict) -> dict: - variant = request["variant"] - session = self._sessions[variant] - # Variants of the same task can declare different inputs, so the caller - # sends the union and each graph takes the subset it declares. Mirrors the - # filtering in runtime_cpp/src/main.cpp. - declared = self._declared_inputs[variant] - feeds = { - name: _decode(payload) - for name, payload in request["inputs"].items() - if name in declared - } - missing = declared - feeds.keys() - if missing: - raise RuntimeError(f"request is missing inputs {sorted(missing)} for {variant!r}") - start = time.perf_counter() - outputs = session.run(None, feeds) - elapsed_ms = (time.perf_counter() - start) * 1000.0 - return { - "request_id": request["request_id"], - "logits": _encode(outputs[0]), - "latency_ms": elapsed_ms, - } - - def close(self) -> None: - self._sessions.clear() +def _make_backend( + model_paths: dict[str, Path], + requested: str | None, + binary: Path | None, +) -> _RuntimeBackend: + """Build the requested backend, or pick one.""" + if requested is not None: + if requested not in BACKENDS: + raise ValueError(f"backend must be one of {BACKENDS}, got {requested!r}") + if requested == "extension": + return _ExtensionBackend(model_paths) + if requested == "subprocess": + if binary is None or not binary.exists(): + raise ValueError("the subprocess backend needs binary= pointing at a built worker") + return _SubprocessBackend(binary, model_paths) + return _PythonBackend(model_paths) + + if extension_available(): + return _ExtensionBackend(model_paths) + if binary is not None and binary.exists(): + LOGGER.warning( + "anytime_runtime is unavailable; falling back to the subprocess worker " + "at %s. Build the extension with: pip install -e .", + binary, + ) + return _SubprocessBackend(binary, model_paths) + LOGGER.warning( + "anytime_runtime is unavailable; falling back to the Python backend. " + "Build the extension with: pip install -e ." + ) + return _PythonBackend(model_paths) class RuntimeClient: - """Single inference worker, backed by either the C++ binary or ONNX Runtime.""" + """Single inference worker.""" def __init__( self, model_paths: dict[str, Path], *, + backend: str | None = None, binary: Path | None = None, input_name: str = "input", ) -> None: if not model_paths: raise ValueError("model_paths must be non-empty") self._input_name = input_name - if binary is not None and binary.exists(): - LOGGER.info("Using C++ runtime binary at %s", binary) - self._backend: _RuntimeBackend = _SubprocessBackend(binary, model_paths) - else: - if binary is not None: - LOGGER.warning("C++ binary %s not found; falling back to Python backend", binary) - self._backend = _PythonBackend(model_paths) + self._backend = _make_backend(model_paths, backend, binary) self._lock = threading.Lock() + @property + def backend_name(self) -> str: + """Which backend is serving. Recorded alongside every measurement.""" + return self._backend.name + def infer(self, request: InferenceRequest) -> InferenceResponse: - payload = { - "request_id": request.request_id, - "variant": request.variant, - "inputs": { - name: _encode(tensor) for name, tensor in request.feed(self._input_name).items() - }, - } + feeds = request.feed(self._input_name) start = time.perf_counter() with self._lock: - response = self._backend.submit(payload) + logits, runtime_latency_ms = self._backend.infer(request.variant, feeds) wall_ms = (time.perf_counter() - start) * 1000.0 return InferenceResponse( - request_id=response["request_id"], - logits=_decode(response["logits"]), - runtime_latency_ms=float(response["latency_ms"]), + request_id=request.request_id, + logits=logits, + runtime_latency_ms=runtime_latency_ms, wall_latency_ms=wall_ms, ) @@ -265,13 +388,15 @@ def __init__( size: int, model_paths: dict[str, Path], *, + backend: str | None = None, binary: Path | None = None, input_name: str = "input", ) -> None: if size <= 0: raise ValueError("size must be positive") self._clients: list[RuntimeClient] = [ - RuntimeClient(model_paths, binary=binary, input_name=input_name) for _ in range(size) + RuntimeClient(model_paths, backend=backend, binary=binary, input_name=input_name) + for _ in range(size) ] self._free: queue.Queue[RuntimeClient] = queue.Queue() for client in self._clients: @@ -285,6 +410,11 @@ def size(self) -> int: """ return len(self._clients) + @property + def backend_name(self) -> str: + """Which backend the workers use.""" + return self._clients[0].backend_name if self._clients else "none" + def infer(self, request: InferenceRequest) -> InferenceResponse: client = self._free.get() try: @@ -313,7 +443,7 @@ def _build_dir_candidates(root: Path) -> tuple[Path, ...]: def find_runtime_binary() -> Path | None: - """Locate the compiled C++ runtime, if it exists. + """Locate the compiled subprocess worker, if it exists. ``ANYTIME_RUNTIME_BIN`` takes precedence and is the only reliable option for a non-editable install, where the package no longer lives inside the source diff --git a/tests/test_runtime_engine.py b/tests/test_runtime_engine.py new file mode 100644 index 0000000..30c2915 --- /dev/null +++ b/tests/test_runtime_engine.py @@ -0,0 +1,394 @@ +"""Tests for the in-process engine, against the backends it replaces. + +The point of most of this file is cross-backend agreement. The extension runs +ONNX Runtime in this process over borrowed buffers; the ``python`` backend runs +the same graph through the onnxruntime wheel; the ``subprocess`` backend runs it +in the Stage 1 worker over base64-encoded JSON. All three must produce bitwise +identical output, because they are the same library doing the same work and any +difference means the new tensor path is corrupting something. + +This comparison is why the subprocess worker is still here. Stage 1's mistake was +that nothing compared the serving path against the path used for profiling, so a +7.6x discrepancy sat undetected. The replacement is checked against what it +replaces before that code is removed. + +Tests needing a compiled runtime are marked ``needs_runtime`` and skipped when it +is absent. Build it with: + + pip install -e . +""" + +import os +import tempfile +from pathlib import Path + +import numpy as np +import pytest + +onnx = pytest.importorskip("onnx", reason="onnx is required to build the fixture graphs") +from onnx import TensorProto, helper, numpy_helper # noqa: E402 + +from anytime_serving.serving.onnx_runtime import ( # noqa: E402 + BACKENDS, + InferenceRequest, + RuntimeClient, + RuntimePool, + extension_available, + find_runtime_binary, + load_extension, +) + +BINARY = find_runtime_binary() + +requires_extension = pytest.mark.skipif( + not extension_available(), reason="anytime_runtime is not built; see module docstring" +) + +# Fixed weights, so every backend is asked to compute exactly the same thing and +# the comparison is over arithmetic rather than over random inputs. +WEIGHT = np.arange(16, dtype=np.float32).reshape(4, 4) / 8.0 - 1.0 +BIAS = np.array([0.25, -0.5, 0.125, 1.0], dtype=np.float32) + + +def _build_graph(path: Path) -> None: + """A graph with real arithmetic in it. + + An Identity graph would round-trip a payload without exercising a kernel, so + it cannot show that two backends compute the same result. MatMul, Add, and + Relu do. + """ + inp = helper.make_tensor_value_info("input", TensorProto.FLOAT, [None, 4]) + out = helper.make_tensor_value_info("logits", TensorProto.FLOAT, [None, 4]) + nodes = [ + helper.make_node("MatMul", ["input", "weight"], ["projected"]), + helper.make_node("Add", ["projected", "bias"], ["biased"]), + helper.make_node("Relu", ["biased"], ["logits"]), + ] + graph = helper.make_graph( + nodes, + "affine_relu", + [inp], + [out], + initializer=[ + numpy_helper.from_array(WEIGHT, "weight"), + numpy_helper.from_array(BIAS, "bias"), + ], + ) + model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 14)], ir_version=8) + onnx.save(model, str(path)) + + +def _build_two_input_graph(path: Path) -> None: + """Declares two inputs, so input filtering can be tested.""" + left = helper.make_tensor_value_info("input", TensorProto.FLOAT, [None, 4]) + right = helper.make_tensor_value_info("scale", TensorProto.FLOAT, [None, 4]) + out = helper.make_tensor_value_info("logits", TensorProto.FLOAT, [None, 4]) + graph = helper.make_graph( + [helper.make_node("Mul", ["input", "scale"], ["logits"])], + "scaled", + [left, right], + [out], + ) + model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 14)], ir_version=8) + onnx.save(model, str(path)) + + +@pytest.fixture(scope="module") +def graphs(): + with tempfile.TemporaryDirectory() as tmp: + affine = Path(tmp) / "affine.onnx" + two_input = Path(tmp) / "two_input.onnx" + _build_graph(affine) + _build_two_input_graph(two_input) + yield {"affine": affine, "two_input": two_input} + + +@pytest.fixture(scope="module") +def model_paths(graphs): + return {"fp32": graphs["affine"], "int8": graphs["affine"]} + + +def _available_backends() -> list[str]: + available = ["python"] + if extension_available(): + available.append("extension") + if BINARY is not None: + available.append("subprocess") + return available + + +def _client(model_paths, backend): + return RuntimeClient(model_paths, backend=backend, binary=BINARY) + + +def _expected(data: np.ndarray) -> np.ndarray: + return np.maximum(data @ WEIGHT + BIAS, 0.0) + + +# --- the premise the comparisons rest on ------------------------------------ + + +def test_required_backends_are_actually_present(): + """Fail rather than skip where a backend is supposed to exist. + + Most tests here skip a backend that is not built, which is right locally but + would let a CI job quietly compare one backend against itself and report + success. ``ANYTIME_REQUIRE_BACKENDS`` names the backends an environment + promises to provide, and CI sets it so the parity comparison cannot decay into + a no-op without anyone noticing. + """ + required = os.environ.get("ANYTIME_REQUIRE_BACKENDS", "").strip() + if not required: + pytest.skip("ANYTIME_REQUIRE_BACKENDS is not set") + + requested = [name.strip() for name in required.split(",") if name.strip()] + unknown = sorted(set(requested) - set(BACKENDS)) + assert not unknown, f"ANYTIME_REQUIRE_BACKENDS names unknown backend(s): {unknown}" + + available = _available_backends() + missing = sorted(set(requested) - set(available)) + assert not missing, ( + f"ANYTIME_REQUIRE_BACKENDS demands {requested} but only {available} are " + f"available. The cross-backend comparison would have skipped instead of " + f"failing." + ) + + +# --- version equality ------------------------------------------------------- + + +@requires_extension +def test_extension_links_the_installed_onnxruntime(): + """The two ONNX Runtimes in this process must be the same version. + + Enforced at CMake configure time as well. This is the gate that still applies + when a built extension is carried into an environment with a different wheel, + which is how the Stage 1 mismatch would have been caught immediately. + """ + import onnxruntime + + extension = load_extension() + assert extension.onnxruntime_version() == onnxruntime.__version__ + + +@requires_extension +def test_extension_reports_its_compiled_api_version(): + extension = load_extension() + assert extension.ort_api_version() > 0 + + +# --- cross-backend agreement ------------------------------------------------ + + +def test_every_backend_computes_the_same_result(model_paths): + """Bitwise agreement across every backend built in this environment.""" + backends = _available_backends() + if len(backends) < 2: + pytest.skip(f"only the {backends[0]!r} backend is available; nothing to compare") + + rng = np.random.default_rng(0) + data = rng.standard_normal((3, 4)).astype(np.float32) + request = InferenceRequest(variant="fp32", data=data) + + results = {} + for backend in backends: + with _client(model_paths, backend) as client: + assert client.backend_name == backend + results[backend] = client.infer(request).logits + + # Against the arithmetic, then against each other, so a shared error in two + # backends cannot pass as agreement. + reference = _expected(data) + for backend, logits in results.items(): + np.testing.assert_allclose(logits, reference, rtol=1e-6, atol=1e-6) + for backend in backends[1:]: + np.testing.assert_array_equal( + results[backend], + results[backends[0]], + err_msg=f"{backend} disagrees with {backends[0]} bitwise", + ) + + +@pytest.mark.parametrize("backend", BACKENDS) +def test_backend_round_trips_a_batch(model_paths, backend): + if backend not in _available_backends(): + pytest.skip(f"the {backend!r} backend is not available here") + rng = np.random.default_rng(1) + data = rng.standard_normal((5, 4)).astype(np.float32) + with _client(model_paths, backend) as client: + response = client.infer(InferenceRequest(variant="fp32", data=data)) + np.testing.assert_allclose(response.logits, _expected(data), rtol=1e-6, atol=1e-6) + assert response.runtime_latency_ms >= 0.0 + assert response.wall_latency_ms >= response.runtime_latency_ms - 1e-6 + + +@pytest.mark.parametrize("backend", BACKENDS) +def test_backend_routes_between_variants(model_paths, backend): + if backend not in _available_backends(): + pytest.skip(f"the {backend!r} backend is not available here") + data = np.full((1, 4), 0.5, dtype=np.float32) + with _client(model_paths, backend) as client: + for variant in ("fp32", "int8"): + response = client.infer(InferenceRequest(variant=variant, data=data)) + np.testing.assert_allclose(response.logits, _expected(data), rtol=1e-6, atol=1e-6) + + +@pytest.mark.parametrize("backend", BACKENDS) +def test_backend_reports_unknown_variant_and_stays_usable(model_paths, backend): + """An unknown variant raises without taking the worker down.""" + if backend not in _available_backends(): + pytest.skip(f"the {backend!r} backend is not available here") + data = np.ones((1, 4), dtype=np.float32) + with _client(model_paths, backend) as client: + with pytest.raises(RuntimeError, match="unknown variant|rejected the request"): + client.infer(InferenceRequest(variant="does_not_exist", data=data)) + response = client.infer(InferenceRequest(variant="fp32", data=data)) + np.testing.assert_allclose(response.logits, _expected(data), rtol=1e-6, atol=1e-6) + + +# --- input handling --------------------------------------------------------- + + +@pytest.mark.parametrize("backend", BACKENDS) +def test_backend_drops_undeclared_inputs(graphs, backend): + """Callers send the union of every variant's inputs; extras are dropped. + + Variants of one task declare different inputs, so a graph must take the subset + it declares rather than failing on the rest. + """ + if backend not in _available_backends(): + pytest.skip(f"the {backend!r} backend is not available here") + paths = {"affine": graphs["affine"]} + data = np.full((1, 4), 2.0, dtype=np.float32) + with _client(paths, backend) as client: + response = client.infer( + InferenceRequest( + variant="affine", + inputs={"input": data, "token_type_ids": np.zeros((1, 4), dtype=np.int64)}, + ) + ) + np.testing.assert_allclose(response.logits, _expected(data), rtol=1e-6, atol=1e-6) + + +@pytest.mark.parametrize("backend", BACKENDS) +def test_backend_rejects_a_missing_declared_input(graphs, backend): + """A partial feed is an error, not a run on whatever was supplied.""" + if backend not in _available_backends(): + pytest.skip(f"the {backend!r} backend is not available here") + paths = {"scaled": graphs["two_input"]} + with _client(paths, backend) as client: + with pytest.raises(RuntimeError, match="missing input|rejected the request"): + client.infer( + InferenceRequest( + variant="scaled", inputs={"input": np.ones((1, 4), dtype=np.float32)} + ) + ) + + +@requires_extension +def test_extension_accepts_a_non_contiguous_input(model_paths): + """A strided array is made contiguous rather than misread. + + ONNX Runtime reads the buffer directly, so handing it a transposed view + without converting would silently transpose the arithmetic. + """ + rng = np.random.default_rng(2) + base = rng.standard_normal((4, 4)).astype(np.float32) + strided = base.T + assert not strided.flags.c_contiguous + + with _client(model_paths, "extension") as client: + from_strided = client.infer(InferenceRequest(variant="fp32", data=strided)).logits + from_copy = client.infer( + InferenceRequest(variant="fp32", data=np.ascontiguousarray(strided)) + ).logits + np.testing.assert_array_equal(from_strided, from_copy) + np.testing.assert_allclose(from_strided, _expected(strided), rtol=1e-6, atol=1e-6) + + +@requires_extension +def test_extension_rejects_an_unsupported_dtype(model_paths): + """An unaccepted dtype fails loudly rather than being reinterpreted.""" + with _client(model_paths, "extension") as client: + with pytest.raises(ValueError, match="float16|does not accept"): + client.infer(InferenceRequest(variant="fp32", data=np.ones((1, 4), dtype=np.float16))) + + +# --- the properties the extension exists for -------------------------------- + + +@requires_extension +def test_extension_output_is_a_view_not_a_copy(model_paths): + """Outputs borrow ONNX Runtime's buffer. + + Copying every output would undo the reason for running in-process, so assert + the array does not own its memory and is kept alive by its base. + """ + data = np.ones((2, 4), dtype=np.float32) + with _client(model_paths, "extension") as client: + logits = client.infer(InferenceRequest(variant="fp32", data=data)).logits + assert not logits.flags.owndata + assert logits.base is not None + # The buffer has to stay valid once the client is closed, since the response + # outlives the call that produced it. + np.testing.assert_allclose(logits, _expected(data), rtol=1e-6, atol=1e-6) + + +@requires_extension +def test_extension_releases_the_gil_during_inference(model_paths): + """Concurrent pool workers must actually overlap. + + Holding the GIL through inference would serialise the pool, and the M/M/c + model the admission controller uses would describe a machine that does not + exist. Correctness under concurrency is asserted here; the throughput claim + itself belongs to the benchmarks, not to a timing-sensitive unit test. + """ + from concurrent.futures import ThreadPoolExecutor + + rng = np.random.default_rng(3) + requests = [ + InferenceRequest( + variant="int8" if i % 2 else "fp32", + data=rng.standard_normal((1, 4)).astype(np.float32), + ) + for i in range(16) + ] + with RuntimePool(size=4, model_paths=model_paths, backend="extension") as pool: + with ThreadPoolExecutor(max_workers=4) as executor: + responses = list(executor.map(pool.infer, requests)) + + for request, response in zip(requests, responses, strict=True): + assert response.request_id == request.request_id + assert request.data is not None + np.testing.assert_allclose(response.logits, _expected(request.data), rtol=1e-6, atol=1e-6) + + +# --- backend selection ------------------------------------------------------ + + +@requires_extension +def test_the_extension_is_preferred_when_available(model_paths): + """Automatic selection picks the in-process path, not a fallback.""" + with RuntimeClient(model_paths, binary=BINARY) as client: + assert client.backend_name == "extension" + + +def test_an_unknown_backend_name_is_rejected(model_paths): + with pytest.raises(ValueError, match="backend must be one of"): + RuntimeClient(model_paths, backend="does_not_exist") + + +def test_the_subprocess_backend_requires_a_binary(model_paths): + with pytest.raises(ValueError, match="needs binary="): + RuntimeClient(model_paths, backend="subprocess", binary=None) + + +def test_find_runtime_binary_honours_env_override(monkeypatch, tmp_path): + """The env override wins, and a missing path resolves to None.""" + monkeypatch.setenv("ANYTIME_RUNTIME_BIN", str(tmp_path / "absent")) + assert find_runtime_binary() is None + + present = tmp_path / "anytime_runtime" + present.write_text("") + monkeypatch.setenv("ANYTIME_RUNTIME_BIN", str(present)) + assert find_runtime_binary() == present From ce2b57753a21bf72d08208a7c666111ed5ff8684 Mon Sep 17 00:00:00 2001 From: QHarshil Date: Thu, 30 Jul 2026 00:21:54 -0700 Subject: [PATCH 2/4] Remove the subprocess transport now that the engine matches it The extension agreed bitwise with the subprocess worker on DistilBERT and their inference times agreed within 0.4%, which is what the previous commit existed to establish. Deleting it now rather than earlier meant the replacement was checked against the thing it replaces. Gone: runtime_cpp/ (the C++ worker, its hand-rolled JSON reader and base64 codecs), _SubprocessBackend and the Python-side codecs, find_runtime_binary and ANYTIME_RUNTIME_BIN, the binary= parameter on RuntimeClient and RuntimePool, and tests/test_runtime_subprocess.py. The two scripts that passed a binary explicitly no longer choose a backend, since the engine is selected automatically. Two backends remain: the extension, which is the serving path, and ONNX Runtime's Python API, which is the reference the tests compare against and the fallback where the extension has not been built. That fallback now warns that measurements taken through it do not describe the serving path. docs/runtime.md was about the JSON protocol end to end, so it is rewritten rather than patched: what survives is the version-matching rationale, which is the part that mattered, plus the measured transport comparison. The CI runtime job that only checked the worker's CLI contract is gone, and the engine job now asserts the extension links the installed wheel. --- .github/workflows/ci.yml | 44 +- docs/architecture.md | 7 +- docs/development.md | 12 +- docs/runtime.md | 187 ++++---- runtime_cpp/CMakeLists.txt | 56 --- runtime_cpp/README.md | 57 --- runtime_cpp/src/main.cpp | 494 -------------------- scripts/demo_serving.py | 4 +- scripts/profile_variants.py | 6 +- scripts/run_load_sweep.py | 4 +- src/anytime_serving/serving/__init__.py | 2 - src/anytime_serving/serving/onnx_runtime.py | 205 +------- tests/test_runtime_engine.py | 53 +-- tests/test_runtime_subprocess.py | 140 ------ 14 files changed, 154 insertions(+), 1117 deletions(-) delete mode 100644 runtime_cpp/CMakeLists.txt delete mode 100644 runtime_cpp/README.md delete mode 100644 runtime_cpp/src/main.cpp delete mode 100644 tests/test_runtime_subprocess.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc5282b..515f255 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -121,11 +121,8 @@ jobs: tests/test_import_boundaries.py engine: - name: Engine parity across all three backends + name: Engine parity against the reference backend runs-on: ubuntu-latest - # The whole point of this job is comparing the extension against the - # subprocess worker it replaces, which means building both and refusing to - # skip either. steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 @@ -140,32 +137,19 @@ jobs: restore-keys: ort-sdk-${{ runner.os }}- - name: Install run: pip install -e . pytest - # The subprocess worker links its own SDK. Reuse the one CMake resolved for - # the extension, so both halves of the comparison are the same build of - # ONNX Runtime and a disagreement cannot be blamed on versions. - - name: Locate the resolved SDK + # Both copies of ONNX Runtime in this process must be the same version. The + # extension reports what it linked; the wheel reports what it will import. + - name: Report the resolved ONNX Runtime versions run: | - root=$(find ~/.cache/anytime-inference-planner -maxdepth 3 -type d \ - -name include -exec dirname {} \; | head -1) - if [ -z "$root" ]; then - echo "no ONNX Runtime SDK found in the cache"; exit 1 - fi - echo "ONNXRUNTIME_ROOT_PATH=$root" >> "$GITHUB_ENV" - echo "resolved $root ($(cat "$root/VERSION_NUMBER"))" - - name: Build the subprocess worker - run: | - cmake -S runtime_cpp -B runtime_cpp/build \ - -DCMAKE_BUILD_TYPE=Release \ - -DONNXRUNTIME_ROOT_PATH="$ONNXRUNTIME_ROOT_PATH" - cmake --build runtime_cpp/build -j"$(nproc)" - - name: Verify the worker starts and reports its usage - run: | - # No --model argument is an error; the binary must exit non-zero with a - # message rather than hang waiting on stdin. - if runtime_cpp/build/anytime_runtime and unpack it. Release tarball -layouts differ between versions: some nest a versioned directory. Point -`ONNXRUNTIME_ROOT_PATH` at whichever directory contains `include/` and `lib/`. - -The binary lands at `runtime_cpp/build/anytime_runtime`. The Python client finds -it via `ANYTIME_RUNTIME_BIN`, or by searching upward from the package and the -working directory. Set the environment variable explicitly for a non-editable -install, where the package no longer sits inside the source tree. +That is the whole thing. `scikit-build-core` runs CMake, and CMake resolves an ONNX +Runtime SDK matching the installed `onnxruntime` wheel, downloading it once into +`~/.cache/anytime-inference-planner/` if it is not already there. ## Match the ONNX Runtime version to the Python wheel -This is the single most important build detail. Building the worker against -1.20.1 while the Python side used the 1.26.0 wheel measured DistilBERT at -**98.9 ms inside the worker against 13.0 ms in the profiler**, a 7.6x gap. The -timing is taken around `session->Run()`, so this was not transport overhead; the -older release simply lacks the optimisations the newer one applies to this graph -on arm64. - -Because the profiler and the serving path disagreed, every service time the -planner used was wrong by almost an order of magnitude and no request met its -deadline. With matched versions the worker measures 14.05 ms, within 8% of the -in-process session, and the JSON transport costs 0.27 ms per request. +This is the single most important build detail, and it is now enforced rather than +documented. -`CMakeLists.txt` guards a related trap: `find_library` caches its result, so -reconfiguring with a different `ONNXRUNTIME_ROOT_PATH` would keep linking the -previously found library while compiling against the new headers. That mismatch -surfaces only at runtime, as `The requested API version [N] is not available`. -The cache entry is now invalidated when the root path changes, and the resolved -library is printed at configure time. +Building the Stage 1 worker against 1.20.1 while the Python side used the 1.26.0 +wheel measured DistilBERT at **98.9 ms inside the worker against 13.0 ms in the +profiler**, a 7.6x gap. The timing was taken around `session->Run()`, so this was +not transport overhead; the older release simply lacks the optimisations the newer +one applies to this graph on arm64. Because the profiler and the serving path +disagreed, every service time the planner used was wrong by almost an order of +magnitude and no request met its deadline. Nothing crashed and no test failed. The +numbers were just false. -## Protocol +With the extension, both copies of ONNX Runtime are loaded into the same process, +so this stopped being a performance question and became a correctness one. The +version is therefore never written down twice. It is read from the wheel the target +interpreter will import, and checked in three places: -Handshake: the worker prints `ready` on stdout once every model has loaded. +1. **Configure time.** The SDK version must equal the wheel version, or CMake + fails. +2. **Compile time.** `ORT_API_VERSION` is read out of the resolved headers and + asserted in `src/tensor.cpp`, so a header from a different include path breaks + the build rather than the run. +3. **Import time.** `load_extension()` compares + `anytime_runtime.onnxruntime_version()` against `onnxruntime.__version__`, + which covers an extension carried into an environment with a different wheel. -Request, one JSON object per line: +A related consequence: CI no longer pins a version anywhere. It had been building +the C++ side against 1.26.0 while `pip` installed 1.28.0, since the dependency +floor is `>=1.16`. That was harmless only because the two never shared a process. -```json -{"request_id": "r-1", - "variant": "distilbert_fp32", - "inputs": {"input_ids": {"shape": [1,128], "dtype": "int64", "data": ""}, - "attention_mask": {"shape": [1,128], "dtype": "int64", "data": ""}}} -``` - -Response: +## Cost of the transport it replaced -```json -{"request_id": "r-1", - "logits": {"shape": [1,2], "dtype": "float32", "data": ""}, - "latency_ms": 14.05} -``` +Measured on DistilBERT at batch size one, 60 requests after warm-up: -Error response, for anything recoverable: +| Backend | Inference p50 | Wall p50 | Transport | +| --- | --- | --- | --- | +| `python` | 13.667 ms | 13.673 ms | 0.006 ms | +| `extension` | 13.609 ms | 13.628 ms | 0.018 ms | +| `subprocess` | 13.629 ms | 13.926 ms | 0.296 ms | -```json -{"request_id": "r-1", "error": "unknown variant"} -``` +All three agreed bitwise on the logits, and their inference times agreed within +0.4%. That agreement is what a matched version looks like, and it is the check that +was missing in Stage 1. -The Python client raises `RuntimeError` on an error response. +Transport fell from 0.296 ms to 0.018 ms. Against 14 ms of inference that saving is +not why the change was made: a subprocess boundary rules out batching across +requests and sharing a KV cache between them, which is what the rest of Stage 2 +needs. The `subprocess` row is from the Stage 1 worker, which was removed once it +had served as the reference the extension was validated against. ## Behaviour -- **One inference at a time.** Run a pool from the Python side for concurrency. - Intra-op threads are set to 1 so N workers behave as N independent servers, - which is what makes the M/M/c queueing model in - [`planner.md`](planner.md) valid. -- **Per-request error isolation.** A malformed request, an unknown variant, or an - ONNX Runtime failure produces an error response and the worker continues. An - earlier version wrapped the whole request loop in one `try`, so a single bad - request terminated the worker and failed every subsequent request routed to it. -- **Input filtering.** Variants can declare different inputs. The worker keeps the - subset its graph declares and drops the rest, and errors if a declared input is - missing rather than running on a partial feed. -- **Supported dtypes.** Inputs `float32` and `int64`; outputs `float32`. -- **No external dependencies.** JSON parsing and base64 are implemented in - `main.cpp` so the worker needs only ONNX Runtime. +- **Tensors are borrowed, not copied.** Inputs point into the numpy buffer; + outputs are numpy views over ONNX Runtime's buffers, kept alive by a capsule + owning the `Ort::Value`. A response therefore holds runtime memory until it is + dropped, so copy `logits` if it needs to outlive the request. +- **The GIL is released during inference.** Without that a pool would serialise on + the interpreter lock, and the M/M/c model in [`planner.md`](planner.md) would + describe a machine that does not exist. +- **One engine per worker.** Intra-op threads are set to 1 so that N workers behave + as N independent servers, which is what makes that queueing model valid, and + matches how the service times in `configs/serving.yaml` were measured. +- **Input filtering.** Variants can declare different inputs, so callers pass the + union and each graph takes the subset it declares. A declared input that is + missing is an error rather than a run on a partial feed. +- **Error contract.** An unknown variant or a missing declared input raises + `RuntimeError`; a dtype the engine does not accept raises `ValueError`. Both + backends behave identically, which is what makes them comparable. +- **Supported dtypes.** Inputs and outputs: float32, float64, int32, int64, bool. + +## Backends + +`RuntimeClient` picks the extension when it imports and matches the wheel, and +otherwise warns and falls back to ONNX Runtime's own Python API. The fallback exists +so the control plane runs where the extension has not been built; it is not the +serving path, and a measurement taken through it does not describe one. + +`backend="extension"` or `backend="python"` pins the choice. Tests pin it so a +parity failure cannot hide behind a silent fallback. ## Tests -`tests/test_runtime_subprocess.py` exercises the real binary: round-trip -fidelity, the base64 codec across all three padding cases, variant routing, -concurrent dispatch through a pool, and error isolation. Marked `needs_runtime` -and skipped when the binary is absent. - ```bash -pytest -q tests/test_runtime_subprocess.py +pytest -q tests/test_runtime_engine.py +ANYTIME_REQUIRE_BACKENDS=extension,python pytest -q tests/test_runtime_engine.py ``` -## Superseded by the in-process engine - -This worker is no longer the serving path. `anytime_runtime`, documented in -[`../runtime/README.md`](../runtime/README.md), runs ONNX Runtime in the caller's -process over borrowed numpy buffers and is selected automatically. - -The subprocess boundary costs a base64 encode, a JSON parse, and a copy in each -direction. Measured on DistilBERT at batch size one, over 60 requests after -warm-up: - -| Backend | Inference p50 | Wall p50 | Transport | -| --- | --- | --- | --- | -| `python` | 13.667 ms | 13.673 ms | 0.006 ms | -| `extension` | 13.609 ms | 13.628 ms | 0.018 ms | -| `subprocess` | 13.629 ms | 13.926 ms | 0.296 ms | - -All three agree bitwise on the logits, and their inference times agree within -0.4%, which is what a matched ONNX Runtime version looks like. The transport cost -falls from 0.296 ms to 0.018 ms. - -Against 14 ms of inference that saving is not the reason for the change. The -reason is that a subprocess boundary rules out batching across requests and -sharing a KV cache between them, which is what the rest of Stage 2 needs. - -The worker is kept for now because it is what the engine is validated against: -`tests/test_runtime_engine.py` asserts all three backends agree, on the principle -that a replacement should be checked against the thing it replaces before that -thing is deleted. +`tests/test_runtime_engine.py` asserts the backends agree bitwise on a graph with +real arithmetic in it, that outputs are views rather than copies, that a strided +input is made contiguous rather than misread, and that an unsupported dtype is +refused. `ANYTIME_REQUIRE_BACKENDS` turns a missing backend from a skip into a +failure, so the comparison cannot decay into one backend checked against itself. diff --git a/runtime_cpp/CMakeLists.txt b/runtime_cpp/CMakeLists.txt deleted file mode 100644 index 8438b24..0000000 --- a/runtime_cpp/CMakeLists.txt +++ /dev/null @@ -1,56 +0,0 @@ -cmake_minimum_required(VERSION 3.14) -project(anytime_runtime CXX) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_POSITION_INDEPENDENT_CODE ON) - -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release) -endif() - -# Locate ONNX Runtime. Either set ONNXRUNTIME_ROOT_PATH to the unpacked release -# tarball (which contains include/ and lib/) or install ONNX Runtime such that -# CMake can find it via find_package. -if(NOT DEFINED ONNXRUNTIME_ROOT_PATH AND DEFINED ENV{ONNXRUNTIME_ROOT_PATH}) - set(ONNXRUNTIME_ROOT_PATH $ENV{ONNXRUNTIME_ROOT_PATH}) -endif() - -if(NOT ONNXRUNTIME_ROOT_PATH) - message(FATAL_ERROR - "ONNXRUNTIME_ROOT_PATH is not set. Download ONNX Runtime from " - "https://github.com/microsoft/onnxruntime/releases and pass " - "-DONNXRUNTIME_ROOT_PATH=/path/to/onnxruntime to cmake.") -endif() - -add_executable(anytime_runtime src/main.cpp) - -target_include_directories(anytime_runtime PRIVATE ${ONNXRUNTIME_ROOT_PATH}/include) - -# find_library caches its result, so reconfiguring with a different -# ONNXRUNTIME_ROOT_PATH would otherwise keep linking the previously found -# library while compiling against the new headers. That mismatch surfaces only at -# runtime, as "The requested API version [N] is not available". -if(DEFINED CACHE{ONNXRUNTIME_LIB} AND NOT ONNXRUNTIME_LIB MATCHES "^${ONNXRUNTIME_ROOT_PATH}/") - message(STATUS "ONNXRUNTIME_ROOT_PATH changed; re-resolving ONNXRUNTIME_LIB") - unset(ONNXRUNTIME_LIB CACHE) -endif() - -find_library(ONNXRUNTIME_LIB - NAMES onnxruntime - PATHS ${ONNXRUNTIME_ROOT_PATH}/lib - NO_DEFAULT_PATH - REQUIRED) - -message(STATUS "Linking ONNX Runtime: ${ONNXRUNTIME_LIB}") - -target_link_libraries(anytime_runtime PRIVATE ${ONNXRUNTIME_LIB}) - -if(APPLE) - set_target_properties(anytime_runtime PROPERTIES - BUILD_RPATH "${ONNXRUNTIME_ROOT_PATH}/lib" - INSTALL_RPATH "${ONNXRUNTIME_ROOT_PATH}/lib") -elseif(UNIX) - target_link_options(anytime_runtime PRIVATE - "-Wl,-rpath,${ONNXRUNTIME_ROOT_PATH}/lib") -endif() diff --git a/runtime_cpp/README.md b/runtime_cpp/README.md deleted file mode 100644 index e51e2f0..0000000 --- a/runtime_cpp/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# anytime_runtime (C++) - -Single-threaded ONNX Runtime worker. Loads one ONNX graph per variant and answers -line-delimited JSON requests on stdin. `RuntimePool` in -`src/anytime_serving/serving/onnx_runtime.py` spawns one process per pool slot and -dispatches across them. - -## Build - -```bash -cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \ - -DONNXRUNTIME_ROOT_PATH=/path/to/onnxruntime -cmake --build build -j -``` - -Download the release matching your platform from -. Point -`ONNXRUNTIME_ROOT_PATH` at the directory containing `include/` and `lib/`. - -**The version must match the `onnxruntime` Python wheel.** A mismatch is a silent -performance cliff, not a link error. See -[`../docs/runtime.md`](../docs/runtime.md). - -The binary lands at `build/anytime_runtime`. The Python client finds it via -`ANYTIME_RUNTIME_BIN` or by searching upward from the package and the working -directory. - -## Protocol - -Handshake: the worker prints `ready` once every model has loaded. - -```json -{"request_id":"r-1","variant":"distilbert_fp32", - "inputs":{"input_ids":{"shape":[1,128],"dtype":"int64","data":""}, - "attention_mask":{"shape":[1,128],"dtype":"int64","data":""}}} -``` - -```json -{"request_id":"r-1", - "logits":{"shape":[1,2],"dtype":"float32","data":""}, - "latency_ms":14.05} -``` - -Recoverable failures return `{"request_id":"r-1","error":"..."}` and the worker -continues serving. - -## Notes - -- One inference per process. Run a pool from the Python side for concurrency. -- Input dtypes `float32` and `int64`; output dtype `float32`. -- Inputs a graph does not declare are dropped; a missing declared input is an - error. -- No dependencies beyond ONNX Runtime. JSON and base64 are implemented in - `src/main.cpp`. - -Full details, including the version-matching rationale and the CMake cache -pitfall: [`../docs/runtime.md`](../docs/runtime.md). diff --git a/runtime_cpp/src/main.cpp b/runtime_cpp/src/main.cpp deleted file mode 100644 index 7b6e34e..0000000 --- a/runtime_cpp/src/main.cpp +++ /dev/null @@ -1,494 +0,0 @@ -// anytime_runtime: a minimal C++ inference worker. -// -// Loads one or more ONNX models (one per "variant" name) and accepts -// line-delimited JSON requests on stdin. Each request specifies the variant -// and the input tensors; the worker runs ONNX Runtime and writes a response -// line containing the output tensor and the measured per-request latency. -// -// Protocol (one JSON object per line): -// request : {"request_id": "...", "variant": "fp32", -// "inputs": {"": {"shape": [...], "dtype": "...", -// "data": ""}}} -// response: {"request_id": "...", "logits": {"shape": [...], -// "dtype": "float32", "data": ""}, "latency_ms": 12.3} -// -// On startup, after every model is loaded, the worker prints the literal -// string "ready" followed by a newline. The Python client uses this as a -// handshake. - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { - -std::string base64_encode(const uint8_t* data, std::size_t length) { - static constexpr char kAlphabet[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - std::string out; - out.reserve(((length + 2) / 3) * 4); - std::size_t i = 0; - for (; i + 3 <= length; i += 3) { - const uint32_t value = (static_cast(data[i]) << 16) | - (static_cast(data[i + 1]) << 8) | - static_cast(data[i + 2]); - out.push_back(kAlphabet[(value >> 18) & 0x3F]); - out.push_back(kAlphabet[(value >> 12) & 0x3F]); - out.push_back(kAlphabet[(value >> 6) & 0x3F]); - out.push_back(kAlphabet[value & 0x3F]); - } - if (i < length) { - const std::size_t remaining = length - i; - uint32_t value = static_cast(data[i]) << 16; - if (remaining == 2) { - value |= static_cast(data[i + 1]) << 8; - } - out.push_back(kAlphabet[(value >> 18) & 0x3F]); - out.push_back(kAlphabet[(value >> 12) & 0x3F]); - out.push_back(remaining == 2 ? kAlphabet[(value >> 6) & 0x3F] : '='); - out.push_back('='); - } - return out; -} - -std::vector base64_decode(const std::string& input) { - static int8_t table[256]; - static bool initialised = false; - if (!initialised) { - std::fill(std::begin(table), std::end(table), int8_t{-1}); - static const char* alphabet = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - for (int i = 0; i < 64; ++i) { - table[static_cast(alphabet[i])] = static_cast(i); - } - initialised = true; - } - std::vector out; - out.reserve((input.size() / 4) * 3); - uint32_t buffer = 0; - int bits = 0; - for (char c : input) { - if (c == '=' || c == '\n' || c == '\r' || c == ' ') continue; - const int8_t value = table[static_cast(c)]; - if (value < 0) throw std::runtime_error("invalid base64 character"); - buffer = (buffer << 6) | static_cast(value); - bits += 6; - if (bits >= 8) { - bits -= 8; - out.push_back(static_cast((buffer >> bits) & 0xFF)); - } - } - return out; -} - -// Tiny JSON reader sufficient for the request envelope produced by the Python -// client. Strings are unescaped only for the characters the client emits -// (\\ and \"). Numbers are parsed as doubles. Arrays of numbers are returned -// as std::vector. Anything more exotic raises std::runtime_error. -class JsonReader { -public: - explicit JsonReader(const std::string& source) : source_(source), pos_(0) {} - - struct Value { - enum class Kind { Null, Bool, Number, String, Array, Object }; - Kind kind = Kind::Null; - bool boolean = false; - double number = 0.0; - std::string string; - std::vector array; - std::vector> object; - - const Value& find(const std::string& key) const { - for (const auto& [k, v] : object) { - if (k == key) return v; - } - throw std::runtime_error("missing JSON key: " + key); - } - std::vector as_int_array() const { - std::vector out; - out.reserve(array.size()); - for (const auto& v : array) { - out.push_back(static_cast(v.number)); - } - return out; - } - }; - - Value parse() { - skip_ws(); - Value v = parse_value(); - skip_ws(); - if (pos_ != source_.size()) { - throw std::runtime_error("trailing characters in JSON"); - } - return v; - } - -private: - void skip_ws() { - while (pos_ < source_.size() && std::isspace(static_cast(source_[pos_]))) { - ++pos_; - } - } - - Value parse_value() { - skip_ws(); - if (pos_ >= source_.size()) throw std::runtime_error("unexpected end of JSON"); - char c = source_[pos_]; - if (c == '{') return parse_object(); - if (c == '[') return parse_array(); - if (c == '"') return parse_string(); - if (c == 't' || c == 'f') return parse_bool(); - if (c == 'n') { expect_literal("null"); Value v; v.kind = Value::Kind::Null; return v; } - return parse_number(); - } - - Value parse_object() { - Value v; - v.kind = Value::Kind::Object; - ++pos_; // consume '{' - skip_ws(); - if (pos_ < source_.size() && source_[pos_] == '}') { ++pos_; return v; } - while (true) { - skip_ws(); - Value key = parse_string(); - skip_ws(); - if (pos_ >= source_.size() || source_[pos_] != ':') { - throw std::runtime_error("expected ':' in JSON object"); - } - ++pos_; - Value value = parse_value(); - v.object.emplace_back(std::move(key.string), std::move(value)); - skip_ws(); - if (pos_ < source_.size() && source_[pos_] == ',') { ++pos_; continue; } - if (pos_ < source_.size() && source_[pos_] == '}') { ++pos_; break; } - throw std::runtime_error("expected ',' or '}' in JSON object"); - } - return v; - } - - Value parse_array() { - Value v; - v.kind = Value::Kind::Array; - ++pos_; // consume '[' - skip_ws(); - if (pos_ < source_.size() && source_[pos_] == ']') { ++pos_; return v; } - while (true) { - v.array.push_back(parse_value()); - skip_ws(); - if (pos_ < source_.size() && source_[pos_] == ',') { ++pos_; continue; } - if (pos_ < source_.size() && source_[pos_] == ']') { ++pos_; break; } - throw std::runtime_error("expected ',' or ']' in JSON array"); - } - return v; - } - - Value parse_string() { - Value v; - v.kind = Value::Kind::String; - if (source_[pos_] != '"') throw std::runtime_error("expected '\"' in JSON string"); - ++pos_; - std::string out; - while (pos_ < source_.size() && source_[pos_] != '"') { - char c = source_[pos_++]; - if (c == '\\' && pos_ < source_.size()) { - char escape = source_[pos_++]; - switch (escape) { - case '"': out.push_back('"'); break; - case '\\': out.push_back('\\'); break; - case '/': out.push_back('/'); break; - case 'n': out.push_back('\n'); break; - case 't': out.push_back('\t'); break; - case 'r': out.push_back('\r'); break; - default: throw std::runtime_error("unsupported JSON escape"); - } - } else { - out.push_back(c); - } - } - if (pos_ >= source_.size()) throw std::runtime_error("unterminated JSON string"); - ++pos_; // closing quote - v.string = std::move(out); - return v; - } - - Value parse_bool() { - Value v; - v.kind = Value::Kind::Bool; - if (source_[pos_] == 't') { - expect_literal("true"); - v.boolean = true; - } else { - expect_literal("false"); - v.boolean = false; - } - return v; - } - - Value parse_number() { - std::size_t start = pos_; - if (source_[pos_] == '-') ++pos_; - while (pos_ < source_.size() && (std::isdigit(static_cast(source_[pos_])) || - source_[pos_] == '.' || source_[pos_] == 'e' || - source_[pos_] == 'E' || source_[pos_] == '+' || - source_[pos_] == '-')) { - ++pos_; - } - Value v; - v.kind = Value::Kind::Number; - v.number = std::stod(source_.substr(start, pos_ - start)); - return v; - } - - void expect_literal(const char* literal) { - const std::size_t n = std::strlen(literal); - if (pos_ + n > source_.size() || source_.compare(pos_, n, literal) != 0) { - throw std::runtime_error(std::string("expected literal ") + literal); - } - pos_ += n; - } - - const std::string& source_; - std::size_t pos_; -}; - -std::string escape_json(const std::string& s) { - std::string out; - out.reserve(s.size()); - for (char c : s) { - switch (c) { - case '"': out += "\\\""; break; - case '\\': out += "\\\\"; break; - case '\n': out += "\\n"; break; - case '\t': out += "\\t"; break; - case '\r': out += "\\r"; break; - default: out.push_back(c); - } - } - return out; -} - -struct LoadedModel { - std::unique_ptr session; - std::vector input_names; - std::vector output_names; -}; - -LoadedModel load_model(Ort::Env& env, const std::string& path) { - Ort::SessionOptions options; - options.SetIntraOpNumThreads(1); - options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL); - - LoadedModel model; - model.session = std::make_unique(env, path.c_str(), options); - - Ort::AllocatorWithDefaultOptions allocator; - const std::size_t num_inputs = model.session->GetInputCount(); - for (std::size_t i = 0; i < num_inputs; ++i) { - auto name = model.session->GetInputNameAllocated(i, allocator); - model.input_names.emplace_back(name.get()); - } - const std::size_t num_outputs = model.session->GetOutputCount(); - for (std::size_t i = 0; i < num_outputs; ++i) { - auto name = model.session->GetOutputNameAllocated(i, allocator); - model.output_names.emplace_back(name.get()); - } - return model; -} - -Ort::Value make_tensor(const JsonReader::Value& payload, - Ort::MemoryInfo& memory, - std::vector& raw_storage, - std::vector& shape_storage, - std::vector& float_storage, - std::vector& int64_storage) { - const std::string dtype = payload.find("dtype").string; - shape_storage = payload.find("shape").as_int_array(); - raw_storage = base64_decode(payload.find("data").string); - - if (dtype == "float32") { - const std::size_t count = raw_storage.size() / sizeof(float); - float_storage.resize(count); - std::memcpy(float_storage.data(), raw_storage.data(), raw_storage.size()); - return Ort::Value::CreateTensor(memory, float_storage.data(), count, - shape_storage.data(), shape_storage.size()); - } - if (dtype == "int64") { - const std::size_t count = raw_storage.size() / sizeof(int64_t); - int64_storage.resize(count); - std::memcpy(int64_storage.data(), raw_storage.data(), raw_storage.size()); - return Ort::Value::CreateTensor(memory, int64_storage.data(), count, - shape_storage.data(), shape_storage.size()); - } - throw std::runtime_error("unsupported dtype: " + dtype); -} - -std::string serialise_output(const Ort::Value& tensor) { - auto info = tensor.GetTensorTypeAndShapeInfo(); - const std::vector shape = info.GetShape(); - const std::size_t element_count = info.GetElementCount(); - const auto element_type = info.GetElementType(); - if (element_type != ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT) { - throw std::runtime_error("only float32 output tensors are supported"); - } - const float* data = tensor.GetTensorData(); - const std::string encoded = base64_encode( - reinterpret_cast(data), element_count * sizeof(float)); - - std::ostringstream shape_json; - shape_json << '['; - for (std::size_t i = 0; i < shape.size(); ++i) { - if (i) shape_json << ','; - shape_json << shape[i]; - } - shape_json << ']'; - - std::ostringstream out; - out << "{\"shape\":" << shape_json.str() - << ",\"dtype\":\"float32\"" - << ",\"data\":\"" << encoded << "\"}"; - return out.str(); -} - -struct ParsedArgs { - std::vector> models; -}; - -ParsedArgs parse_args(int argc, char** argv) { - ParsedArgs out; - for (int i = 1; i < argc; ++i) { - std::string flag = argv[i]; - if (flag == "--model" && i + 1 < argc) { - std::string value = argv[++i]; - const std::size_t eq = value.find('='); - if (eq == std::string::npos) { - throw std::runtime_error("--model expects ="); - } - out.models.emplace_back(value.substr(0, eq), value.substr(eq + 1)); - } else { - throw std::runtime_error("unknown argument: " + flag); - } - } - if (out.models.empty()) { - throw std::runtime_error("at least one --model must be specified"); - } - return out; -} - -} // namespace - - -int main(int argc, char** argv) { - try { - const ParsedArgs args = parse_args(argc, argv); - - Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "anytime_runtime"); - std::unordered_map models; - for (const auto& [variant, path] : args.models) { - models[variant] = load_model(env, path); - } - - std::cout << "ready" << std::endl; - - Ort::MemoryInfo memory = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); - - std::string line; - while (std::getline(std::cin, line)) { - if (line.empty()) continue; - - // Per-request failures must not take the worker down: a pool shares - // one process per worker, so exiting here would fail every in-flight - // and subsequent request on this worker. Anything recoverable is - // reported as an error response and the loop continues. - std::string request_id; - try { - JsonReader reader(line); - JsonReader::Value request = reader.parse(); - - request_id = request.find("request_id").string; - const std::string variant = request.find("variant").string; - const JsonReader::Value& inputs = request.find("inputs"); - - const auto it = models.find(variant); - if (it == models.end()) { - std::cerr << "unknown variant: " << variant << std::endl; - std::cout << "{\"request_id\":\"" << escape_json(request_id) - << "\",\"error\":\"unknown variant\"}" << std::endl; - continue; - } - LoadedModel& model = it->second; - - std::vector> raw_storage(inputs.object.size()); - std::vector> shape_storage(inputs.object.size()); - std::vector> float_storage(inputs.object.size()); - std::vector> int64_storage(inputs.object.size()); - std::vector tensors; - tensors.reserve(inputs.object.size()); - std::vector input_name_ptrs; - input_name_ptrs.reserve(inputs.object.size()); - - // Variants of the same task can declare different inputs: a - // DistilBERT graph takes input_ids and attention_mask, a BERT - // graph additionally takes token_type_ids. The caller sends the - // union, so drop anything this graph does not declare rather than - // failing the request. - for (std::size_t i = 0; i < inputs.object.size(); ++i) { - const auto& [name, payload] = inputs.object[i]; - const bool declared = std::find(model.input_names.begin(), - model.input_names.end(), - name) != model.input_names.end(); - if (!declared) continue; - input_name_ptrs.push_back(name.c_str()); - tensors.push_back(make_tensor(payload, memory, - raw_storage[i], shape_storage[i], - float_storage[i], int64_storage[i])); - } - if (tensors.size() != model.input_names.size()) { - throw std::runtime_error( - "request supplies " + std::to_string(tensors.size()) + - " of the " + std::to_string(model.input_names.size()) + - " inputs this graph declares"); - } - - std::vector output_name_ptrs; - output_name_ptrs.reserve(model.output_names.size()); - for (const auto& n : model.output_names) output_name_ptrs.push_back(n.c_str()); - - const auto start = std::chrono::steady_clock::now(); - auto outputs = model.session->Run( - Ort::RunOptions{nullptr}, - input_name_ptrs.data(), tensors.data(), tensors.size(), - output_name_ptrs.data(), output_name_ptrs.size()); - const auto end = std::chrono::steady_clock::now(); - const double latency_ms = - std::chrono::duration(end - start).count(); - - std::string logits_json = serialise_output(outputs.front()); - std::cout << "{\"request_id\":\"" << escape_json(request_id) - << "\",\"logits\":" << logits_json - << ",\"latency_ms\":" << latency_ms << "}" << std::endl; - } catch (const std::exception& exc) { - std::cerr << "request error: " << exc.what() << std::endl; - std::cout << "{\"request_id\":\"" << escape_json(request_id) - << "\",\"error\":\"" << escape_json(exc.what()) << "\"}" - << std::endl; - } - } - return 0; - } catch (const std::exception& exc) { - std::cerr << "fatal: " << exc.what() << std::endl; - return 1; - } -} diff --git a/scripts/demo_serving.py b/scripts/demo_serving.py index c7e2a06..462930f 100644 --- a/scripts/demo_serving.py +++ b/scripts/demo_serving.py @@ -22,7 +22,7 @@ from onnx import TensorProto, helper from anytime_serving.serving.load_monitor import LoadMonitor -from anytime_serving.serving.onnx_runtime import InferenceRequest, RuntimePool, find_runtime_binary +from anytime_serving.serving.onnx_runtime import InferenceRequest, RuntimePool from anytime_serving.serving.selector import AdaptiveSelector, VariantProfile from anytime_serving.serving.server import AdaptiveServer, drive_workload, poisson_arrivals from anytime_serving.utils.logger import get_logger @@ -71,7 +71,7 @@ def _run_policy( monitor.start() rng = np.random.default_rng(seed) try: - with RuntimePool(workers, model_paths, binary=find_runtime_binary()) as pool: + with RuntimePool(workers, model_paths) as pool: server = AdaptiveServer(pool, selector, monitor) try: diff --git a/scripts/profile_variants.py b/scripts/profile_variants.py index 248aedc..ba0fa49 100644 --- a/scripts/profile_variants.py +++ b/scripts/profile_variants.py @@ -78,9 +78,9 @@ class VariantMeasurement: def _session(graph: Path) -> ort.InferenceSession: """Build a session matching the serving worker's configuration. - runtime_cpp/src/main.cpp sets intra-op threads to one so that N pooled - workers behave as N independent single-threaded servers. Profiling with a - different thread count would measure a machine the planner never runs on. + runtime/src/engine.cpp sets intra-op threads to one so that N pooled workers + behave as N independent single-threaded servers. Profiling with a different + thread count would measure a machine the planner never runs on. """ options = ort.SessionOptions() options.intra_op_num_threads = 1 diff --git a/scripts/run_load_sweep.py b/scripts/run_load_sweep.py index d6886bf..f70262d 100644 --- a/scripts/run_load_sweep.py +++ b/scripts/run_load_sweep.py @@ -34,7 +34,7 @@ import yaml from anytime_serving.serving.load_monitor import LoadMonitor -from anytime_serving.serving.onnx_runtime import InferenceRequest, RuntimePool, find_runtime_binary +from anytime_serving.serving.onnx_runtime import InferenceRequest, RuntimePool from anytime_serving.serving.selector import AdaptiveSelector, VariantProfile from anytime_serving.serving.server import AdaptiveServer, drive_workload, poisson_arrivals from anytime_serving.utils.logger import get_logger @@ -133,7 +133,7 @@ def _run_policy( monitor = LoadMonitor(interval_s=0.1, alpha=0.3) monitor.start() try: - with RuntimePool(workers, model_paths, binary=find_runtime_binary()) as pool: + with RuntimePool(workers, model_paths) as pool: server = AdaptiveServer(pool, selector, monitor) try: diff --git a/src/anytime_serving/serving/__init__.py b/src/anytime_serving/serving/__init__.py index 4c326ac..cf06b89 100644 --- a/src/anytime_serving/serving/__init__.py +++ b/src/anytime_serving/serving/__init__.py @@ -9,7 +9,6 @@ RuntimeClient, RuntimePool, extension_available, - find_runtime_binary, load_extension, ) from .selector import AdaptiveSelector, SelectionDecision, VariantProfile @@ -31,7 +30,6 @@ "InferenceRequest", "InferenceResponse", "extension_available", - "find_runtime_binary", "load_extension", "AdaptiveServer", "ServedRequest", diff --git a/src/anytime_serving/serving/onnx_runtime.py b/src/anytime_serving/serving/onnx_runtime.py index 654cf9f..3ff8d96 100644 --- a/src/anytime_serving/serving/onnx_runtime.py +++ b/src/anytime_serving/serving/onnx_runtime.py @@ -1,20 +1,16 @@ """Client for the inference runtime. -Three backends implement one interface, all taking and returning numpy arrays: +Two backends implement one interface, both taking and returning numpy arrays: ``extension`` The ``anytime_runtime`` pybind11 module, which runs ONNX Runtime in this process. Tensors are borrowed rather than copied and the GIL is released - around inference, so a pool of workers runs concurrently. This is the - production path. -``subprocess`` - The Stage 1 worker, spawned per pool slot and driven over line-delimited - JSON. Retained only so the extension can be checked against it; the encoding - cost it pays is the reason it is being replaced. + around inference, so a pool of workers runs concurrently. This is the serving + path. ``python`` ONNX Runtime through its own Python wheel. The reference implementation the - tests compare the extension against, and the fallback where the extension - has not been built. + tests compare the extension against, and the fallback where the extension has + not been built. The backend is chosen automatically unless ``backend=`` names one. Tests pin it explicitly so a parity failure cannot be hidden by a silent fallback. @@ -22,17 +18,13 @@ from __future__ import annotations -import base64 -import json -import os import queue -import subprocess import threading import time import uuid from dataclasses import dataclass, field from pathlib import Path -from typing import IO, Any +from typing import Any import numpy as np @@ -40,7 +32,7 @@ LOGGER = get_logger("serving.onnx_runtime") -BACKENDS = ("extension", "subprocess", "python") +BACKENDS = ("extension", "python") _extension: Any | None = None @@ -49,12 +41,13 @@ def load_extension() -> Any: """Import ``anytime_runtime``, refusing a version mismatch. The extension and the ``onnxruntime`` wheel are two independent copies of - ONNX Runtime loaded into one process. Stage 1 built the worker against 1.20.1 - while profiling against the 1.26.0 wheel and measured DistilBERT at 98.9 ms - versus 13.0 ms inside ``session->Run()``; every service time the planner used - was wrong by almost an order of magnitude, and nothing failed. The build - enforces this equality at configure time, and this is the second gate, in - case the extension is carried to an environment with a different wheel. + ONNX Runtime loaded into one process. Stage 1 built the C++ worker against + 1.20.1 while profiling against the 1.26.0 wheel and measured DistilBERT at + 98.9 ms versus 13.0 ms inside ``session->Run()``; every service time the + planner used was wrong by almost an order of magnitude, and nothing failed. + The build enforces this equality at configure time, and this is the gate that + still applies when a built extension is carried into an environment with a + different wheel. """ global _extension if _extension is not None: @@ -132,6 +125,10 @@ class _RuntimeBackend: Implementations return the first graph output and the time spent inside inference, excluding anything the client adds around it. + + Anything meaning "the runtime could not serve this request" -- an unknown + variant, a missing declared input -- raises ``RuntimeError``. A malformed + argument, such as a dtype the engine does not accept, raises ``ValueError``. """ name = "abstract" @@ -207,130 +204,21 @@ def close(self) -> None: self._sessions.clear() -def _encode(array: np.ndarray) -> dict: - """Encode a tensor for the subprocess protocol.""" - contiguous = np.ascontiguousarray(array) - return { - "shape": list(contiguous.shape), - "dtype": str(contiguous.dtype), - "data": base64.b64encode(contiguous.tobytes()).decode("ascii"), - } - - -def _decode(payload: dict) -> np.ndarray: - """Decode a tensor from the subprocess protocol.""" - raw = base64.b64decode(payload["data"]) - dtype = np.dtype(payload["dtype"]) - return np.frombuffer(raw, dtype=dtype).reshape(payload["shape"]) - - -class _SubprocessBackend(_RuntimeBackend): - """The Stage 1 worker, over line-delimited JSON on stdin and stdout. - - Kept so the extension can be validated against the implementation it - replaces. Every tensor is base64-encoded, parsed, and copied in each - direction, which is exactly what the extension removes. - """ - - name = "subprocess" - - def __init__(self, binary: Path, model_paths: dict[str, Path]) -> None: - args = [str(binary)] - for variant, path in model_paths.items(): - args.extend(["--model", f"{variant}={path}"]) - self._process = subprocess.Popen( - args, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - bufsize=1, - text=True, - ) - # Popen types the pipes as Optional. All three were requested above, so - # bind them once to non-optional handles rather than narrowing at every - # use site. - assert self._process.stdin is not None - assert self._process.stdout is not None - assert self._process.stderr is not None - self._stdin: IO[str] = self._process.stdin - self._stdout: IO[str] = self._process.stdout - self._stderr: IO[str] = self._process.stderr - - # Drain handshake line (the worker prints "ready" once every model has - # loaded). - handshake = self._stdout.readline().strip() - if handshake != "ready": - stderr = self._stderr.read() - raise RuntimeError(f"C++ runtime failed to start: {handshake!r} ({stderr})") - - def infer(self, variant: str, feeds: dict[str, np.ndarray]) -> tuple[np.ndarray, float]: - request = { - "request_id": uuid.uuid4().hex, - "variant": variant, - "inputs": {name: _encode(tensor) for name, tensor in feeds.items()}, - } - self._stdin.write(json.dumps(request) + "\n") - self._stdin.flush() - response_line = self._stdout.readline() - if not response_line: - stderr = self._stderr.read() - raise RuntimeError(f"C++ runtime closed unexpectedly: {stderr}") - response = json.loads(response_line) - # The worker reports a recoverable problem (an unknown variant, say) as an - # error field and stays alive for the next request. - if "error" in response: - raise RuntimeError(f"C++ runtime rejected the request: {response['error']}") - return _decode(response["logits"]), float(response["latency_ms"]) - - def close(self) -> None: - if self._process.poll() is None: - try: - self._stdin.close() - except OSError: - pass - self._process.terminate() - try: - self._process.wait(timeout=2.0) - except subprocess.TimeoutExpired: - self._process.kill() - # Popen leaves stdout/stderr open after the child exits; close them so a - # long-lived pool does not accumulate file descriptors. - for stream in (self._stdin, self._stdout, self._stderr): - try: - stream.close() - except OSError: - pass - - -def _make_backend( - model_paths: dict[str, Path], - requested: str | None, - binary: Path | None, -) -> _RuntimeBackend: +def _make_backend(model_paths: dict[str, Path], requested: str | None) -> _RuntimeBackend: """Build the requested backend, or pick one.""" if requested is not None: if requested not in BACKENDS: raise ValueError(f"backend must be one of {BACKENDS}, got {requested!r}") if requested == "extension": return _ExtensionBackend(model_paths) - if requested == "subprocess": - if binary is None or not binary.exists(): - raise ValueError("the subprocess backend needs binary= pointing at a built worker") - return _SubprocessBackend(binary, model_paths) return _PythonBackend(model_paths) if extension_available(): return _ExtensionBackend(model_paths) - if binary is not None and binary.exists(): - LOGGER.warning( - "anytime_runtime is unavailable; falling back to the subprocess worker " - "at %s. Build the extension with: pip install -e .", - binary, - ) - return _SubprocessBackend(binary, model_paths) LOGGER.warning( - "anytime_runtime is unavailable; falling back to the Python backend. " - "Build the extension with: pip install -e ." + "anytime_runtime is unavailable; falling back to the Python backend. Measured " + "service times will not reflect the serving path. Build the extension with: " + "pip install -e ." ) return _PythonBackend(model_paths) @@ -343,13 +231,12 @@ def __init__( model_paths: dict[str, Path], *, backend: str | None = None, - binary: Path | None = None, input_name: str = "input", ) -> None: if not model_paths: raise ValueError("model_paths must be non-empty") self._input_name = input_name - self._backend = _make_backend(model_paths, backend, binary) + self._backend = _make_backend(model_paths, backend) self._lock = threading.Lock() @property @@ -389,14 +276,12 @@ def __init__( model_paths: dict[str, Path], *, backend: str | None = None, - binary: Path | None = None, input_name: str = "input", ) -> None: if size <= 0: raise ValueError("size must be positive") self._clients: list[RuntimeClient] = [ - RuntimeClient(model_paths, backend=backend, binary=binary, input_name=input_name) - for _ in range(size) + RuntimeClient(model_paths, backend=backend, input_name=input_name) for _ in range(size) ] self._free: queue.Queue[RuntimeClient] = queue.Queue() for client in self._clients: @@ -432,45 +317,3 @@ def __enter__(self) -> RuntimePool: def __exit__(self, exc_type, exc, tb) -> None: self.close() - - -def _build_dir_candidates(root: Path) -> tuple[Path, ...]: - build = root / "runtime_cpp" / "build" - return ( - build / "anytime_runtime", - build / "Release" / "anytime_runtime.exe", - ) - - -def find_runtime_binary() -> Path | None: - """Locate the compiled subprocess worker, if it exists. - - ``ANYTIME_RUNTIME_BIN`` takes precedence and is the only reliable option for - a non-editable install, where the package no longer lives inside the source - tree. Otherwise search upward from this file (covering an editable install) - and from the working directory (covering a plain checkout). - """ - env_override = os.environ.get("ANYTIME_RUNTIME_BIN") - if env_override: - candidate = Path(env_override) - return candidate if candidate.exists() else None - - roots: list[Path] = [] - # Walk up from this module: src/anytime_serving/serving/ -> repo root. Done by - # search rather than a fixed parent index so moving the package does not - # silently break resolution. - here = Path(__file__).resolve() - roots.extend(here.parents) - cwd = Path.cwd().resolve() - roots.append(cwd) - roots.extend(cwd.parents) - - seen: set[Path] = set() - for root in roots: - if root in seen: - continue - seen.add(root) - for candidate in _build_dir_candidates(root): - if candidate.exists(): - return candidate - return None diff --git a/tests/test_runtime_engine.py b/tests/test_runtime_engine.py index 30c2915..8e14db3 100644 --- a/tests/test_runtime_engine.py +++ b/tests/test_runtime_engine.py @@ -1,19 +1,17 @@ -"""Tests for the in-process engine, against the backends it replaces. +"""Tests for the in-process engine, against the reference implementation. The point of most of this file is cross-backend agreement. The extension runs -ONNX Runtime in this process over borrowed buffers; the ``python`` backend runs -the same graph through the onnxruntime wheel; the ``subprocess`` backend runs it -in the Stage 1 worker over base64-encoded JSON. All three must produce bitwise -identical output, because they are the same library doing the same work and any -difference means the new tensor path is corrupting something. +ONNX Runtime in this process over borrowed buffers; the ``python`` backend runs the +same graph through the onnxruntime wheel. Both must produce bitwise identical +output, because they are the same library doing the same work and any difference +means the tensor path is corrupting something. -This comparison is why the subprocess worker is still here. Stage 1's mistake was -that nothing compared the serving path against the path used for profiling, so a -7.6x discrepancy sat undetected. The replacement is checked against what it -replaces before that code is removed. +The Stage 1 subprocess worker was the third backend here until it was removed. It +agreed bitwise with the extension on DistilBERT, which is what justified deleting +it: a replacement should be checked against the thing it replaces before that +thing goes away. -Tests needing a compiled runtime are marked ``needs_runtime`` and skipped when it -is absent. Build it with: +Tests needing the compiled extension are skipped when it is absent. Build it with: pip install -e . """ @@ -34,12 +32,9 @@ RuntimeClient, RuntimePool, extension_available, - find_runtime_binary, load_extension, ) -BINARY = find_runtime_binary() - requires_extension = pytest.mark.skipif( not extension_available(), reason="anytime_runtime is not built; see module docstring" ) @@ -112,13 +107,11 @@ def _available_backends() -> list[str]: available = ["python"] if extension_available(): available.append("extension") - if BINARY is not None: - available.append("subprocess") return available def _client(model_paths, backend): - return RuntimeClient(model_paths, backend=backend, binary=BINARY) + return RuntimeClient(model_paths, backend=backend) def _expected(data: np.ndarray) -> np.ndarray: @@ -240,7 +233,7 @@ def test_backend_reports_unknown_variant_and_stays_usable(model_paths, backend): pytest.skip(f"the {backend!r} backend is not available here") data = np.ones((1, 4), dtype=np.float32) with _client(model_paths, backend) as client: - with pytest.raises(RuntimeError, match="unknown variant|rejected the request"): + with pytest.raises(RuntimeError, match="unknown variant"): client.infer(InferenceRequest(variant="does_not_exist", data=data)) response = client.infer(InferenceRequest(variant="fp32", data=data)) np.testing.assert_allclose(response.logits, _expected(data), rtol=1e-6, atol=1e-6) @@ -277,7 +270,7 @@ def test_backend_rejects_a_missing_declared_input(graphs, backend): pytest.skip(f"the {backend!r} backend is not available here") paths = {"scaled": graphs["two_input"]} with _client(paths, backend) as client: - with pytest.raises(RuntimeError, match="missing input|rejected the request"): + with pytest.raises(RuntimeError, match="missing input"): client.infer( InferenceRequest( variant="scaled", inputs={"input": np.ones((1, 4), dtype=np.float32)} @@ -368,27 +361,11 @@ def test_extension_releases_the_gil_during_inference(model_paths): @requires_extension def test_the_extension_is_preferred_when_available(model_paths): - """Automatic selection picks the in-process path, not a fallback.""" - with RuntimeClient(model_paths, binary=BINARY) as client: + """Automatic selection picks the in-process path, not the fallback.""" + with RuntimeClient(model_paths) as client: assert client.backend_name == "extension" def test_an_unknown_backend_name_is_rejected(model_paths): with pytest.raises(ValueError, match="backend must be one of"): RuntimeClient(model_paths, backend="does_not_exist") - - -def test_the_subprocess_backend_requires_a_binary(model_paths): - with pytest.raises(ValueError, match="needs binary="): - RuntimeClient(model_paths, backend="subprocess", binary=None) - - -def test_find_runtime_binary_honours_env_override(monkeypatch, tmp_path): - """The env override wins, and a missing path resolves to None.""" - monkeypatch.setenv("ANYTIME_RUNTIME_BIN", str(tmp_path / "absent")) - assert find_runtime_binary() is None - - present = tmp_path / "anytime_runtime" - present.write_text("") - monkeypatch.setenv("ANYTIME_RUNTIME_BIN", str(present)) - assert find_runtime_binary() == present diff --git a/tests/test_runtime_subprocess.py b/tests/test_runtime_subprocess.py deleted file mode 100644 index b20cc24..0000000 --- a/tests/test_runtime_subprocess.py +++ /dev/null @@ -1,140 +0,0 @@ -"""Protocol tests against the compiled C++ runtime. - -The Python fallback backend and the C++ subprocess backend implement the same -request/response protocol, but only the fallback is exercised by the rest of the -suite. These tests run the real binary so the framing, base64 codec, and -handshake are covered too. - -Skipped when the binary has not been built. Build it with: - - cmake -S runtime_cpp -B runtime_cpp/build -DCMAKE_BUILD_TYPE=Release \\ - -DONNXRUNTIME_ROOT_PATH=/path/to/onnxruntime - cmake --build runtime_cpp/build -j -""" - -import tempfile -from pathlib import Path - -import numpy as np -import pytest - -onnx = pytest.importorskip("onnx", reason="onnx is required to build the fixture model") -from onnx import TensorProto, helper # noqa: E402 - -from anytime_serving.serving.onnx_runtime import ( # noqa: E402 - InferenceRequest, - RuntimeClient, - RuntimePool, - find_runtime_binary, -) - -pytestmark = pytest.mark.needs_runtime - -BINARY = find_runtime_binary() -requires_binary = pytest.mark.skipif( - BINARY is None, reason="C++ runtime binary not built; see module docstring" -) - - -def _build_identity_model(path: Path, dim: int = 4) -> None: - inp = helper.make_tensor_value_info("input", TensorProto.FLOAT, [None, dim]) - out = helper.make_tensor_value_info("logits", TensorProto.FLOAT, [None, dim]) - graph = helper.make_graph( - [helper.make_node("Identity", ["input"], ["logits"])], "identity", [inp], [out] - ) - model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 14)], ir_version=8) - onnx.save(model, str(path)) - - -@pytest.fixture(scope="module") -def model_paths(): - with tempfile.TemporaryDirectory() as tmp: - fp32 = Path(tmp) / "fp32.onnx" - int8 = Path(tmp) / "int8.onnx" - _build_identity_model(fp32) - _build_identity_model(int8) - yield {"fp32": fp32, "int8": int8} - - -@requires_binary -def test_subprocess_round_trip_preserves_payload(model_paths): - with RuntimeClient(model_paths, binary=BINARY) as client: - data = np.arange(8, dtype=np.float32).reshape(2, 4) - response = client.infer(InferenceRequest(variant="fp32", data=data)) - np.testing.assert_array_almost_equal(response.logits, data) - assert response.runtime_latency_ms >= 0.0 - assert response.wall_latency_ms >= response.runtime_latency_ms - 1e-6 - - -@requires_binary -def test_subprocess_base64_codec_survives_all_byte_values(model_paths): - """Exercise the hand-rolled base64 codec across padding lengths. - - Payload sizes of 4, 5, and 6 floats give byte counts with remainders 0, 1, - and 2 mod 3, covering every padding branch in the encoder. - """ - try: - for count in (4, 5, 6, 8, 16): - data = np.linspace(-1e6, 1e6, count, dtype=np.float32).reshape(1, count) - # The graph pins its input width, so rebuild it per payload size. - _build_identity_model(model_paths["fp32"], dim=count) - with RuntimeClient({"fp32": model_paths["fp32"]}, binary=BINARY) as sized: - response = sized.infer(InferenceRequest(variant="fp32", data=data)) - np.testing.assert_array_equal(response.logits, data) - finally: - # Restore the shared module-scoped fixture for the other tests. - _build_identity_model(model_paths["fp32"]) - - -@requires_binary -def test_subprocess_routes_between_variants(model_paths): - with RuntimeClient(model_paths, binary=BINARY) as client: - for variant in ("fp32", "int8"): - data = np.full((1, 4), 3.5, dtype=np.float32) - response = client.infer(InferenceRequest(variant=variant, data=data)) - np.testing.assert_array_almost_equal(response.logits, data) - - -@requires_binary -def test_subprocess_pool_serves_concurrent_requests(model_paths): - from concurrent.futures import ThreadPoolExecutor - - with RuntimePool(size=2, model_paths=model_paths, binary=BINARY) as pool: - rng = np.random.default_rng(0) - requests = [ - InferenceRequest( - variant="int8" if i % 2 else "fp32", - data=rng.standard_normal((1, 4)).astype(np.float32), - ) - for i in range(8) - ] - with ThreadPoolExecutor(max_workers=4) as executor: - responses = list(executor.map(pool.infer, requests)) - for request, response in zip(requests, responses, strict=True): - np.testing.assert_array_almost_equal(response.logits, request.data) - assert response.request_id == request.request_id - - -@requires_binary -def test_subprocess_reports_unknown_variant_and_stays_usable(model_paths): - """An unknown variant raises a descriptive error without killing the worker.""" - with RuntimeClient(model_paths, binary=BINARY) as client: - with pytest.raises(RuntimeError, match="unknown variant"): - client.infer( - InferenceRequest(variant="does_not_exist", data=np.zeros((1, 4), np.float32)) - ) - # The worker reports the problem and continues serving. - data = np.ones((1, 4), dtype=np.float32) - response = client.infer(InferenceRequest(variant="fp32", data=data)) - np.testing.assert_array_almost_equal(response.logits, data) - - -def test_find_runtime_binary_honours_env_override(monkeypatch, tmp_path): - """The env override wins, and a missing path resolves to None.""" - monkeypatch.setenv("ANYTIME_RUNTIME_BIN", str(tmp_path / "absent")) - assert find_runtime_binary() is None - - present = tmp_path / "anytime_runtime" - present.write_text("") - monkeypatch.setenv("ANYTIME_RUNTIME_BIN", str(present)) - assert find_runtime_binary() == present From 987f774960b2f268c8bf1ae31c64c73a970d2b80 Mon Sep 17 00:00:00 2001 From: QHarshil Date: Thu, 30 Jul 2026 00:31:22 -0700 Subject: [PATCH 3/4] Profile through the engine, and fail when a cross-check disagrees Service profiles were measured through a separate ONNX Runtime session rather than through the path that serves traffic. That is the gap that let Stage 1's 7.6x version mismatch hide: the worker and the profiler were different processes running different builds, and nothing compared them, so DistilBERT measured 98.9 ms in one and 13.0 ms in the other while every test passed. profile_variants.py now measures through the same RuntimeClient the server dispatches to, and scores accuracy through it as well, so the logits are the served ones. Closing that gap alone would only move the blind spot, so each variant is also run through a separate session and the two are required to agree within --agreement-tolerance, default 15%. A divergence beyond that aborts before anything is written to disk. Measured on this host, engine against separate session: distilbert_fp32 0.991x minilm_fp32 1.014x distilbert_int8 0.994x minilm_int8 0.999x Tightening the bound to 0.001 was used to confirm the check fires and writes nothing. Profiling also refuses to run at all when the extension is unavailable, since the Python fallback does not describe the serving path; --allow-fallback-backend records those numbers deliberately. Both paths were verified in an environment without the extension built. service_time_ms is now wall time per request through the client rather than time inside a bare session, which is what the pool actually spends. The reported profile records both, plus the agreement ratio, the backend used, and the ONNX Runtime version each side linked. configs/serving.yaml is deliberately not regenerated here: re-running moves the service times by roughly 4% under the new definition, which would leave the committed load sweep and its figure describing a different measurement. Noted in docs/benchmarks.md so the three are regenerated together. The INT8 result reproduces: on arm64 both quantised graphs are slower and no more accurate than the FP32 graphs they replace, so both remain dominated. --- docs/benchmarks.md | 22 ++- scripts/profile_variants.py | 326 ++++++++++++++++++++++++++---------- 2 files changed, 253 insertions(+), 95 deletions(-) diff --git a/docs/benchmarks.md b/docs/benchmarks.md index fee478a..767c90b 100644 --- a/docs/benchmarks.md +++ b/docs/benchmarks.md @@ -97,9 +97,19 @@ percentiles over hundreds of samples rather than as single figures. ## Known limitations - Single host, single task. No GPU, no multi-node. -- The C++ worker and the Python fallback are compared on latency but the sweep - runs whichever is present; the figure above used the C++ worker. -- Service profiles are measured through a Python ONNX Runtime session rather - than through the serving path itself. Those agreed to within 8% once ONNX - Runtime versions matched, but profiling through `RuntimePool` directly would - remove the possibility of divergence. +- The figure above was produced with the Stage 1 subprocess worker, which has since + been replaced by the in-process engine. The two agreed bitwise on logits and + within 0.4% on inference time, so the shape of the result stands, but the sweep + has not been re-run through the engine. +- `configs/serving.yaml` still holds the service times measured through a separate + ONNX Runtime session. Re-running `scripts/profile_variants.py` now measures + through the engine and reports wall time per request rather than time inside a + bare session, which moves the numbers by roughly 4%. The config, the sweep, and + this page should be regenerated together so they continue to describe one + measurement. + +Closed since Stage 1: service profiles are no longer measured beside the serving +path. `scripts/profile_variants.py` measures through the same `RuntimeClient` the +server dispatches to, and cross-checks every variant against a separate ONNX +Runtime session, failing the run rather than writing numbers to disk when the two +diverge by more than 15%. Measured agreement on this host is within 1.6%. diff --git a/scripts/profile_variants.py b/scripts/profile_variants.py index ba0fa49..1f24bfa 100644 --- a/scripts/profile_variants.py +++ b/scripts/profile_variants.py @@ -5,11 +5,22 @@ carrying a number over from a different host, thread count, or batch size makes every downstream admission decision wrong. -This script measures every exported candidate under the same ONNX Runtime -configuration the serving worker uses (one intra-op thread per worker, batch size -one), computes the Pareto frontier over (service time, accuracy), and writes: - - results/variant_profiles.json all measurements plus host metadata +Measurement goes **through the serving path**, not beside it. Every latency and +every logit here comes from the same `RuntimeClient` the server dispatches to. +Stage 1 profiled through a separate ONNX Runtime session instead, and that is what +let a 7.6x discrepancy hide: the C++ worker was built against ONNX Runtime 1.20.1 +while the profiler used the 1.26.0 wheel, so DistilBERT measured 98.9 ms in the +worker against 13.0 ms in the profiler. Nothing failed. Every service time the +planner used was simply false. + +To keep that from recurring in a form the engine cannot see, each variant is also +measured through a separate ONNX Runtime session and the two are required to agree. +A divergence beyond --agreement-tolerance fails the run rather than being written +to disk. This is the check whose absence made Stage 1's numbers wrong. + +Writes: + + results/variant_profiles.json all measurements, agreement, host metadata configs/serving.yaml the frontier, as the serving harness reads it Which variants end up on the frontier is a property of the hardware, not an @@ -40,6 +51,12 @@ import numpy as np import onnxruntime as ort +from anytime_serving.serving.onnx_runtime import ( + InferenceRequest, + RuntimeClient, + extension_available, + load_extension, +) from anytime_serving.utils.logger import get_logger LOGGER = get_logger("scripts.profile_variants") @@ -50,11 +67,15 @@ QUICK_WARMUP_ITERATIONS = 5 QUICK_MEASURE_ITERATIONS = 40 QUICK_ACCURACY_SAMPLES = 128 +# Matched versions measured within 0.4% on this host, and Stage 1 saw 8% across a +# process boundary. 15% is loose enough not to fire on scheduler noise and tight +# enough that anything structural, let alone a 7.6x version mismatch, trips it. +DEFAULT_AGREEMENT_TOLERANCE = 0.15 @dataclass class VariantMeasurement: - """Measured cost and quality for one variant.""" + """Measured cost and quality for one variant, as served.""" name: str model: str @@ -70,17 +91,23 @@ class VariantMeasurement: iterations: int accuracy: float accuracy_samples: int + # Time inside inference as the engine reports it, against the same graph run + # through a separate session. Agreement is what says the number is real. + engine_inference_p50_ms: float + direct_session_p50_ms: float + agreement_ratio: float compute_cost_per_request: float = 1.0 on_pareto_frontier: bool = False dominated_by: str | None = None def _session(graph: Path) -> ort.InferenceSession: - """Build a session matching the serving worker's configuration. + """Build a cross-check session matching the engine's configuration. - runtime/src/engine.cpp sets intra-op threads to one so that N pooled workers - behave as N independent single-threaded servers. Profiling with a different - thread count would measure a machine the planner never runs on. + runtime/src/engine.cpp sets intra-op and inter-op threads to one so that N + pooled workers behave as N independent single-threaded servers. This session + exists only to be compared against the engine, so it has to be configured the + same way or the comparison measures the configuration difference instead. """ options = ort.SessionOptions() options.intra_op_num_threads = 1 @@ -101,7 +128,12 @@ def _find_graph(directory: Path) -> Path: return graphs[0] -def _feeds(tokenizer, session: ort.InferenceSession, text: str) -> dict[str, np.ndarray]: +def _tokenize(tokenizer, text: str) -> dict[str, np.ndarray]: + """Encode one string. Not filtered to any graph's declared inputs. + + The engine drops inputs a graph does not declare, so the union is what the + server sends and therefore what should be measured. + """ encoded = tokenizer( text, return_tensors="np", @@ -109,41 +141,75 @@ def _feeds(tokenizer, session: ort.InferenceSession, text: str) -> dict[str, np. truncation=True, max_length=SEQUENCE_LENGTH, ) - expected = {i.name for i in session.get_inputs()} - return {name: value.astype(np.int64) for name, value in encoded.items() if name in expected} + return {name: value.astype(np.int64) for name, value in encoded.items()} + + +def _declared(session: ort.InferenceSession, feeds: dict[str, np.ndarray]) -> dict[str, np.ndarray]: + expected = {spec.name for spec in session.get_inputs()} + return {name: value for name, value in feeds.items() if name in expected} -def _measure_latency( +def _percentiles(samples: list[float], key: str) -> dict[str, float]: + array = np.asarray(samples) + return { + f"{key}_p50_ms": float(np.percentile(array, 50)), + f"{key}_p95_ms": float(np.percentile(array, 95)), + f"{key}_p99_ms": float(np.percentile(array, 99)), + f"{key}_mean_ms": statistics.fmean(samples), + f"{key}_stdev_ms": statistics.stdev(samples) if len(samples) > 1 else 0.0, + } + + +def _measure_through_engine( + client: RuntimeClient, + variant: str, + feeds: dict[str, np.ndarray], + *, + warmup: int, + iterations: int, +) -> dict[str, float]: + """Latency as the server experiences it, through the runtime client.""" + request = InferenceRequest(variant=variant, inputs=feeds) + for _ in range(warmup): + client.infer(request) + + wall: list[float] = [] + inference: list[float] = [] + for _ in range(iterations): + response = client.infer(request) + wall.append(response.wall_latency_ms) + inference.append(response.runtime_latency_ms) + + stats = _percentiles(wall, "wall") + stats.update(_percentiles(inference, "inference")) + stats["iterations"] = float(iterations) + return stats + + +def _measure_direct_session( session: ort.InferenceSession, feeds: dict[str, np.ndarray], *, warmup: int, iterations: int, ) -> dict[str, float]: + """The same graph through a separate session, for the agreement check.""" + fed = _declared(session, feeds) for _ in range(warmup): - session.run(None, feeds) + session.run(None, fed) samples: list[float] = [] for _ in range(iterations): start = time.perf_counter() - session.run(None, feeds) + session.run(None, fed) samples.append((time.perf_counter() - start) * 1000.0) - - array = np.asarray(samples) - return { - "latency_p50_ms": float(np.percentile(array, 50)), - "latency_p95_ms": float(np.percentile(array, 95)), - "latency_p99_ms": float(np.percentile(array, 99)), - "latency_mean_ms": statistics.fmean(samples), - "latency_stdev_ms": statistics.stdev(samples) if len(samples) > 1 else 0.0, - "iterations": float(len(samples)), - } + return _percentiles(samples, "direct") def _measure_accuracy( - session: ort.InferenceSession, tokenizer, samples: int | None + client: RuntimeClient, variant: str, tokenizer, samples: int | None ) -> tuple[float, int]: - """Accuracy on the SST-2 validation split.""" + """Accuracy on the SST-2 validation split, scored through the engine.""" from datasets import load_dataset dataset = load_dataset("glue", "sst2", split="validation") @@ -152,7 +218,8 @@ def _measure_accuracy( correct = 0 for row in dataset: - logits = session.run(None, _feeds(tokenizer, session, row["sentence"]))[0] + feeds = _tokenize(tokenizer, row["sentence"]) + logits = client.infer(InferenceRequest(variant=variant, inputs=feeds)).logits if int(np.argmax(logits, axis=-1)[0]) == int(row["label"]): correct += 1 return correct / len(dataset), len(dataset) @@ -184,68 +251,107 @@ def _mark_pareto_frontier(measurements: list[VariantMeasurement]) -> None: candidate.dominated_by = dominator.name if dominator else None -def profile(model_dir: Path, quick: bool) -> list[VariantMeasurement]: - from transformers import AutoTokenizer - - warmup = QUICK_WARMUP_ITERATIONS if quick else WARMUP_ITERATIONS - iterations = QUICK_MEASURE_ITERATIONS if quick else MEASURE_ITERATIONS - accuracy_samples = QUICK_ACCURACY_SAMPLES if quick else None - +def _discover(model_dir: Path) -> list[tuple[str, str, str, Path]]: + """Find exported variants as (name, model, precision, graph).""" directories = sorted(model_dir.glob("text_*_*")) if not directories: raise SystemExit( f"no exported variants under {model_dir}. Run: " f"python scripts/export_onnx.py --task text --output-dir {model_dir}" ) - - measurements: list[VariantMeasurement] = [] + found = [] for directory in directories: if not directory.is_dir(): continue # Directory names are text__. _, model_name, precision = directory.name.split("_", 2) - graph = _find_graph(directory) - tokenizer = AutoTokenizer.from_pretrained(directory) - session = _session(graph) - - name = f"{model_name}_{precision}" - LOGGER.info("Profiling %s (%s)", name, graph.name) - latency = _measure_latency( - session, - _feeds(tokenizer, session, "a genuinely measured service time"), - warmup=warmup, - iterations=iterations, - ) - accuracy, n_samples = _measure_accuracy(session, tokenizer, accuracy_samples) - - measurements.append( - VariantMeasurement( - name=name, - model=model_name, - precision=precision, - graph=graph.name, - size_mb=round(graph.stat().st_size / 1e6, 1), - # The planner admits on expected service time, so use the median: - # it is not skewed by occasional scheduler noise. - service_time_ms=round(latency["latency_p50_ms"], 3), - latency_p50_ms=round(latency["latency_p50_ms"], 3), - latency_p95_ms=round(latency["latency_p95_ms"], 3), - latency_p99_ms=round(latency["latency_p99_ms"], 3), - latency_mean_ms=round(latency["latency_mean_ms"], 3), - latency_stdev_ms=round(latency["latency_stdev_ms"], 3), - iterations=int(latency["iterations"]), - accuracy=round(accuracy, 4), - accuracy_samples=n_samples, + found.append((f"{model_name}_{precision}", model_name, precision, _find_graph(directory))) + return found + + +def profile(model_dir: Path, quick: bool, tolerance: float) -> tuple[list[VariantMeasurement], str]: + from transformers import AutoTokenizer + + warmup = QUICK_WARMUP_ITERATIONS if quick else WARMUP_ITERATIONS + iterations = QUICK_MEASURE_ITERATIONS if quick else MEASURE_ITERATIONS + accuracy_samples = QUICK_ACCURACY_SAMPLES if quick else None + + variants = _discover(model_dir) + # One client holding every variant, which is how the server loads them. + client = RuntimeClient({name: graph for name, _, _, graph in variants}) + LOGGER.info("Profiling through the %s backend", client.backend_name) + + measurements: list[VariantMeasurement] = [] + disagreements: list[str] = [] + try: + for name, model_name, precision, graph in variants: + tokenizer = AutoTokenizer.from_pretrained(graph.parent) + feeds = _tokenize(tokenizer, "a genuinely measured service time") + + LOGGER.info("Profiling %s (%s)", name, graph.name) + engine = _measure_through_engine( + client, name, feeds, warmup=warmup, iterations=iterations ) - ) - LOGGER.info( - " p50=%.2fms p95=%.2fms p99=%.2fms accuracy=%.4f (n=%d) size=%.1fMB", - latency["latency_p50_ms"], - latency["latency_p95_ms"], - latency["latency_p99_ms"], - accuracy, - n_samples, - graph.stat().st_size / 1e6, + direct = _measure_direct_session( + _session(graph), feeds, warmup=warmup, iterations=iterations + ) + accuracy, n_samples = _measure_accuracy(client, name, tokenizer, accuracy_samples) + + ratio = engine["inference_p50_ms"] / direct["direct_p50_ms"] + if abs(ratio - 1.0) > tolerance: + disagreements.append( + f" {name}: engine {engine['inference_p50_ms']:.3f} ms vs separate " + f"session {direct['direct_p50_ms']:.3f} ms ({ratio:.3f}x)" + ) + + measurements.append( + VariantMeasurement( + name=name, + model=model_name, + precision=precision, + graph=graph.name, + size_mb=round(graph.stat().st_size / 1e6, 1), + # The planner admits on expected service time, so use the + # median of what a request actually costs the pool: the wall + # time through the client, not just time inside inference. + service_time_ms=round(engine["wall_p50_ms"], 3), + latency_p50_ms=round(engine["wall_p50_ms"], 3), + latency_p95_ms=round(engine["wall_p95_ms"], 3), + latency_p99_ms=round(engine["wall_p99_ms"], 3), + latency_mean_ms=round(engine["wall_mean_ms"], 3), + latency_stdev_ms=round(engine["wall_stdev_ms"], 3), + iterations=int(engine["iterations"]), + accuracy=round(accuracy, 4), + accuracy_samples=n_samples, + engine_inference_p50_ms=round(engine["inference_p50_ms"], 3), + direct_session_p50_ms=round(direct["direct_p50_ms"], 3), + agreement_ratio=round(ratio, 4), + ) + ) + LOGGER.info( + " p50=%.2fms p95=%.2fms accuracy=%.4f (n=%d) size=%.1fMB agreement=%.3fx", + engine["wall_p50_ms"], + engine["wall_p95_ms"], + accuracy, + n_samples, + graph.stat().st_size / 1e6, + ratio, + ) + finally: + client.close() + + if disagreements: + raise SystemExit( + "The engine and a separate ONNX Runtime session disagree by more than " + f"the {tolerance} relative bound:\n" + + "\n".join(disagreements) + + "\n\nThis is the check that Stage 1 lacked. A 7.6x version mismatch " + "between the C++ worker and the onnxruntime wheel went unnoticed for " + "exactly this reason, and every service time the planner used was wrong. " + "Do not write these numbers to disk: confirm the extension and the wheel " + "report the same ONNX Runtime version, then re-run. Pass " + "--agreement-tolerance to widen the bound only if the difference is " + "understood." ) _mark_pareto_frontier(measurements) @@ -257,21 +363,25 @@ def profile(model_dir: Path, quick: bool) -> list[VariantMeasurement]: measurement.compute_cost_per_request = round( measurement.service_time_ms / reference.service_time_ms, 4 ) - return measurements + return measurements, client.backend_name -def _host_metadata() -> dict[str, object]: - return { +def _host_metadata(backend: str) -> dict[str, object]: + metadata: dict[str, object] = { "platform": platform.platform(), "processor": platform.processor() or platform.machine(), "machine": platform.machine(), "python": platform.python_version(), "onnxruntime": ort.__version__, "providers": ort.get_available_providers(), + "backend": backend, "intra_op_num_threads": 1, "batch_size": 1, "sequence_length": SEQUENCE_LENGTH, } + if extension_available(): + metadata["extension_onnxruntime"] = load_extension().onnxruntime_version() + return metadata def _write_serving_config(path: Path, frontier: list[VariantMeasurement], workers: int) -> None: @@ -306,9 +416,10 @@ def _write_serving_config(path: Path, frontier: list[VariantMeasurement], worker existing.setdefault("admission", {"safety_factor": 1.0}) path.write_text( - "# Generated by scripts/profile_variants.py. Values are measured on the\n" - "# host recorded in results/variant_profiles.json; re-run after changing\n" - "# hardware, thread count, or model variants.\n" + yaml.safe_dump(existing, sort_keys=False) + "# Generated by scripts/profile_variants.py. Values are measured through the\n" + "# serving path on the host recorded in results/variant_profiles.json;\n" + "# re-run after changing hardware, thread count, or model variants.\n" + + yaml.safe_dump(existing, sort_keys=False) ) @@ -321,18 +432,46 @@ def main() -> int: action="store_true", help="Fewer iterations and a subset of the validation split", ) + parser.add_argument( + "--agreement-tolerance", + type=float, + default=DEFAULT_AGREEMENT_TOLERANCE, + help=( + "Maximum relative difference between inference time through the engine " + "and through a separate session before the run fails, as a fraction " + f"(default {DEFAULT_AGREEMENT_TOLERANCE})" + ), + ) + parser.add_argument( + "--allow-fallback-backend", + action="store_true", + help=( + "Profile even when the anytime_runtime extension is unavailable. The " + "numbers then describe the Python fallback rather than the serving path" + ), + ) parser.add_argument("--output", type=Path, default=Path("results/variant_profiles.json")) parser.add_argument("--serving-config", type=Path, default=Path("configs/serving.yaml")) args = parser.parse_args() - measurements = profile(args.model_dir, args.quick) + if not extension_available() and not args.allow_fallback_backend: + raise SystemExit( + "anytime_runtime is not available, so profiling would measure the Python " + "fallback rather than the path that serves traffic. That divergence is " + "what made Stage 1's service times wrong. Build the extension with:\n" + " pip install -e .\n" + "or pass --allow-fallback-backend to record fallback numbers deliberately." + ) + + measurements, backend = profile(args.model_dir, args.quick, args.agreement_tolerance) frontier = [m for m in measurements if m.on_pareto_frontier] payload = { - "host": _host_metadata(), + "host": _host_metadata(backend), "quick": args.quick, "task": "text", "accuracy_dataset": "glue/sst2 validation", + "agreement_tolerance": args.agreement_tolerance, "variants": [asdict(m) for m in measurements], "pareto_frontier": [m.name for m in frontier], } @@ -344,15 +483,24 @@ def main() -> int: LOGGER.info("Wrote %s", args.serving_config) LOGGER.info("") - LOGGER.info("%-18s %10s %10s %9s %s", "variant", "p50 (ms)", "accuracy", "size(MB)", "verdict") + LOGGER.info( + "%-18s %10s %10s %9s %10s %s", + "variant", + "p50 (ms)", + "accuracy", + "size(MB)", + "agreement", + "verdict", + ) for m in sorted(measurements, key=lambda m: m.service_time_ms): verdict = "frontier" if m.on_pareto_frontier else f"dominated by {m.dominated_by}" LOGGER.info( - "%-18s %10.2f %10.4f %9.1f %s", + "%-18s %10.2f %10.4f %9.1f %9.3fx %s", m.name, m.service_time_ms, m.accuracy, m.size_mb, + m.agreement_ratio, verdict, ) From 5ca041d41e2f30a21b93e7bbe9f887f7528b9b7d Mon Sep 17 00:00:00 2001 From: QHarshil Date: Thu, 30 Jul 2026 00:58:22 -0700 Subject: [PATCH 4/4] Regenerate the config, sweep, and figure through the engine The service profile, configs/serving.yaml, results/load_sweep.csv, and docs/img/load_sweep.png were produced by the Stage 1 subprocess worker. They are now regenerated in one pass through the in-process engine so that all four describe the same measurement, along with the numbers quoted in README.md, benchmarks.md, quantization.md, and planner.md. The result does not move. Service times reproduce Stage 1 within their own spread, 12.89 against 12.79 ms for DistilBERT and 5.19 against 5.21 ms for MiniLM, and all four accuracies reproduce exactly: 91.06, 90.60, 90.14, 90.14. Replacing the transport did not change what is being measured. A single p50 was more precise than the measurement deserved. Measuring the same 200-request p50 eight times gave 13.84 to 14.73 ms for DistilBERT and 5.62 to 5.83 ms for MiniLM, ranges of 6.5% and 3.6%, driven by thermal state rather than by anything in the code, while the within-pass stdev is around 0.45 ms and says nothing about it. profile_variants.py now takes --repeats independent passes, default 3, reports the median of their medians, and records the range across them as service_time_spread_pct. An earlier single-pass run of this same regeneration read 13.93 ms for DistilBERT, which is how the outlier was noticed. Sweep headline at rho = 0.95: 281 rps of goodput against 43, at 49% of the compute cost, previously 287 against 37. The ratio moves from 7.8x to 6.5x because the accurate-only denominator is computed from however few requests admission lets through, which is the noisy end. Repeating the whole sweep twice more with the same seed moved goodput by at most 6% and the rho = 0.95 adaptive figure by 2%. Two things the new data shows that the old tables did not: At rho = 0.60 the attainment curves cross. Adaptive attains 84.5% against 85.1% while admitting 99.8% against 94.4%. Admitting nearly everything puts more work in the queue, so attainment among admitted requests does not improve even though goodput does, 161 against 153 rps. Recorded rather than smoothed over: it is the one point where the adaptive policy is not better on every axis. The sweep was previously run with --duration 2 while the documented reproduction command defaults to 3, so that command never reproduced the committed numbers. Regenerated at the default. Also documents that --quick numbers must not be reported: it scores accuracy on 128 of the 872 validation examples, which moves the figure by half a point. --- README.md | 41 ++++++----- configs/serving.yaml | 14 ++-- docs/benchmarks.md | 137 +++++++++++++++++++++++------------- docs/img/load_sweep.png | Bin 202610 -> 198635 bytes docs/planner.md | 2 +- docs/quantization.md | 13 ++-- scripts/profile_variants.py | 127 ++++++++++++++++++++++++++------- 7 files changed, 231 insertions(+), 103 deletions(-) diff --git a/README.md b/README.md index d2db860..2b36a0d 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Latency-bounded ML serving. A Python control plane watches queue depth and CPU load, then routes each request to one of several profiled model variants so that as much traffic as possible completes inside a deadline. Inference runs in a C++ -ONNX Runtime worker pool. +ONNX Runtime engine loaded into the process as an extension module. Variant selection is a constrained optimisation: maximise expected accuracy subject to an M/M/c sojourn-time bound and the measured backlog. @@ -13,22 +13,27 @@ subject to an M/M/c sojourn-time bound and the measured backlog. ## Results DistilBERT-SST-2 and MiniLM-L6 served from a 4-worker pool on an Apple M4 Pro, -real SST-2 validation traffic, 38 ms deadline. Offered load is a fraction of the -measured pool capacity of 313 rps. Goodput counts only requests that completed -within the deadline. +real SST-2 validation traffic, 39 ms deadline. Offered load is a fraction of the +measured pool capacity of 310 rps. Goodput counts only requests that completed +within the deadline; p95 is the adaptive policy's. | Offered load | Goodput, accurate-only | Goodput, adaptive | Compute cost | p95 | | --- | --- | --- | --- | --- | -| ρ = 0.40 | 126 rps | 127 rps | 1.00 | 28 ms | -| ρ = 0.80 | 99 rps | 214 rps | 0.76 | 44 ms | -| ρ = 0.95 | 37 rps | 287 rps | 0.48 | 38 ms | -| ρ = 1.30 | 3 rps | 403 rps | 0.41 | 18 ms | +| ρ = 0.40 | 122 rps | 124 rps | 1.00 | 31 ms | +| ρ = 0.80 | 144 rps | 217 rps | 0.79 | 53 ms | +| ρ = 0.95 | 43 rps | 281 rps | 0.49 | 38 ms | +| ρ = 1.30 | 2 rps | 394 rps | 0.41 | 19 ms | Below ρ ≈ 0.5 the planner keeps every request on the most accurate variant and matches the baseline exactly. As the queue builds it shifts traffic to the cheaper -variant: at ρ = 0.95 that is **7.8x the goodput at 48% of the compute cost**, for +variant: at ρ = 0.95 that is **6.5x the goodput at 49% of the compute cost**, for at most 0.92 accuracy points (91.06% to 90.14% on SST-2 validation). +Measured through the serving path itself, with every variant cross-checked against +a separate ONNX Runtime session. Repeating the sweep moved goodput by at most 6%, +and service times carry a 1-4% run-to-run spread, so treat the third digit as +noise. + Full tables, methodology, and host details: [`docs/benchmarks.md`](docs/benchmarks.md). ## Install @@ -48,8 +53,7 @@ python scripts/demo_serving.py ``` Self-contained: builds a small synthetic ONNX model, drives Poisson traffic -through both policies, and prints a JSON summary. Needs no model download and no -C++ build. +through both policies, and prints a JSON summary. Needs no model download. Reproduce the measured results end to end: @@ -65,8 +69,8 @@ python scripts/run_load_sweep.py # sweep load, write the figure pytest -q ``` -The serving tests build a tiny ONNX model on the fly, so they run without torch -or the C++ binary. Tests needing either are marked and skip when it is absent. +The serving tests build a tiny ONNX graph on the fly, so they run without torch. +Tests needing the compiled extension are marked and skip when it is absent. ## Documentation @@ -74,21 +78,26 @@ or the C++ binary. Tests needing either are marked and skip when it is absent. | --- | --- | | [Architecture](docs/architecture.md) | control plane and worker split, request lifecycle | | [Planner](docs/planner.md) | admission control, Erlang-C, variant selection | -| [Runtime](docs/runtime.md) | C++ worker, build, wire protocol | +| [Runtime](docs/runtime.md) | C++ engine, build, version matching | | [Quantisation](docs/quantization.md) | why the variant frontier is measured, not assumed | | [Benchmarks](docs/benchmarks.md) | methodology, full results, reproduction | | [Development](docs/development.md) | dependency groups, tests, CI, layout | ## Notes -Two findings shaped the current design and are worth knowing before extending it: +Three findings shaped the current design and are worth knowing before extending it: - **Worker count belongs in the queueing model.** Modelling a c-worker pool as a single server understates capacity by a factor of c. `AdaptiveServer` now refuses a selector that models a different pool size. - **Match the C++ ONNX Runtime version to the Python wheel.** A mismatch measured DistilBERT at 98.9 ms in the worker against 13.0 ms in the profiler, which - silently invalidated every admission decision. + silently invalidated every admission decision. The version is now derived from + the installed wheel at build time and checked again at import, so it cannot + drift. +- **Measure through the serving path, not beside it.** That mismatch survived + because profiling used a separate process. Profiling now runs through the same + client the server dispatches to, and fails if a cross-check disagrees. ## License diff --git a/configs/serving.yaml b/configs/serving.yaml index 84c59c0..d38d8e6 100644 --- a/configs/serving.yaml +++ b/configs/serving.yaml @@ -1,7 +1,7 @@ -# Generated by scripts/profile_variants.py. Values are measured on the -# host recorded in results/variant_profiles.json; re-run after changing -# hardware, thread count, or model variants. -deadline_ms: 38.4 +# Generated by scripts/profile_variants.py. Values are measured through the +# serving path on the host recorded in results/variant_profiles.json; +# re-run after changing hardware, thread count, or model variants. +deadline_ms: 38.7 workers: 4 duration_s: 20.0 arrival_rate_rps: 80.0 @@ -11,10 +11,10 @@ admission: safety_factor: 1.0 variants: distilbert_fp32: - service_time_ms: 12.789 + service_time_ms: 12.893 accuracy: 0.9106 compute_cost_per_request: 1.0 minilm_fp32: - service_time_ms: 5.211 + service_time_ms: 5.189 accuracy: 0.9014 - compute_cost_per_request: 0.4075 + compute_cost_per_request: 0.4025 diff --git a/docs/benchmarks.md b/docs/benchmarks.md index 767c90b..bd168a0 100644 --- a/docs/benchmarks.md +++ b/docs/benchmarks.md @@ -15,70 +15,100 @@ assumed, or carried over from another machine. | Sequence length | 128 tokens | | Task | SST-2 binary sentiment | | Accuracy split | GLUE SST-2 validation, all 872 examples | -| Latency samples | 200 per variant, after 20 warmup iterations | -| Deadline | 38.4 ms (3x the slowest frontier variant) | +| Latency samples | 200 per pass, 3 independent passes per variant, 20 warmup iterations each | +| Deadline | 38.7 ms (3x the slowest frontier variant) | +| Measured through | the `anytime_runtime` extension, the same path the server uses | Recorded in full in `results/variant_profiles.json`. ## Variant frontier -Service time is the median of 200 single-request measurements taken through a -session configured exactly like a serving worker. +Service time is wall time per request through `RuntimeClient`, which is what the +pool actually spends. It is reported as the median of three independent +measurement passes; the spread column is the range across those passes. -| Variant | p50 | p95 | p99 | stdev | Accuracy | Size | Relative cost | Verdict | -| --- | --- | --- | --- | --- | --- | --- | --- | --- | -| `distilbert_fp32` | 12.79 ms | 13.54 ms | 14.73 ms | 0.45 ms | 91.06% | 268 MB | 1.000 | frontier | -| `minilm_fp32` | 5.21 ms | 5.43 ms | 5.54 ms | 0.09 ms | 90.14% | 91 MB | 0.407 | frontier | -| `distilbert_int8` | 16.42 ms | 17.26 ms | 17.57 ms | 0.36 ms | 90.60% | 67 MB | 1.284 | dominated | -| `minilm_int8` | 6.93 ms | 7.07 ms | 7.19 ms | 0.08 ms | 90.14% | 23 MB | 0.542 | dominated | +| Variant | p50 | Spread | p95 | p99 | stdev | Accuracy | Size | Relative cost | Verdict | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| `distilbert_fp32` | 12.89 ms | 4.0% | 14.24 ms | 15.41 ms | 1.02 ms | 91.06% | 268 MB | 1.000 | frontier | +| `minilm_fp32` | 5.19 ms | 2.0% | 5.46 ms | 5.62 ms | 0.13 ms | 90.14% | 91 MB | 0.403 | frontier | +| `distilbert_int8` | 17.17 ms | 1.4% | 18.38 ms | 19.51 ms | 0.85 ms | 90.60% | 67 MB | 1.332 | dominated | +| `minilm_int8` | 7.16 ms | 0.9% | 7.45 ms | 7.75 ms | 0.22 ms | 90.14% | 23 MB | 0.556 | dominated | The measured 91.06% for DistilBERT-SST-2 matches its published SST-2 dev accuracy -of roughly 91.3%, which is the main sanity check on the measurement path. +of roughly 91.3%, which is the main sanity check on the measurement path. All four +accuracies reproduce Stage 1 exactly, which is the check that the engine's logits +are the same logits. Both INT8 variants are strictly dominated: slower with no accuracy gain. See [`quantization.md`](quantization.md). +### Why three passes + +One pass is not enough on this host. Measuring the same 200-request p50 eight +times gave 13.84 to 14.73 ms for DistilBERT and 5.62 to 5.83 ms for MiniLM, a +range of 6.5% and 3.6%, driven by thermal state and scheduler placement rather +than by anything in the code. The within-pass standard deviation is around 0.45 ms +and says nothing about that, so a single p50 quoted with a within-pass spread +overstates its own precision. Reporting the median of three passes, with the range +across them, is why the spread column exists. + +This also sets the cross-check tolerance. Engine and separate session agreed to +within 2% here (0.980x to 1.007x), and the 15% bound is loose enough not to fire +on that drift while still catching anything structural. + ## Load sweep Offered load is expressed as a fraction of measured pool capacity -(4 workers / 12.79 ms = 313 rps) rather than as a bare request rate. Both +(4 workers / 12.89 ms = 310 rps) rather than as a bare request rate. Both policies see the same Poisson arrival stream of real SST-2 sentences, tokenised -before the run so the measurement is inference rather than preprocessing. +before the run so the measurement is inference rather than preprocessing. Three +seconds of arrivals per point, which is the script's default. Goodput counts only requests that completed within the deadline; it is the metric that matters, because admitted-and-late is worth nothing to a caller. | ρ | Rate | Policy | Admitted | Attainment | p50 | p95 | Goodput | Cost | | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| 0.40 | 125 rps | accurate-only | 99.6% | 99.2% | 16.8 ms | 28.7 ms | 126 rps | 1.000 | -| 0.40 | 125 rps | adaptive | 99.6% | 100.0% | 16.5 ms | 28.4 ms | 127 rps | 1.000 | -| 0.60 | 188 rps | accurate-only | 94.5% | 82.1% | 29.6 ms | 46.8 ms | 150 rps | 1.000 | -| 0.60 | 188 rps | adaptive | 100.0% | 87.8% | 27.0 ms | 44.7 ms | 169 rps | 0.941 | -| 0.80 | 250 rps | accurate-only | 74.8% | 51.7% | 38.2 ms | 52.6 ms | 99 rps | 1.000 | -| 0.80 | 250 rps | adaptive | 99.8% | 83.6% | 30.3 ms | 44.0 ms | 214 rps | 0.757 | -| 0.95 | 297 rps | accurate-only | 17.5% | 68.9% | 33.9 ms | 49.1 ms | 37 rps | 1.000 | -| 0.95 | 297 rps | adaptive | 99.8% | 95.0% | 9.4 ms | 38.4 ms | 287 rps | 0.483 | -| 1.10 | 344 rps | accurate-only | 3.6% | 76.0% | 30.5 ms | 47.3 ms | 10 rps | 1.000 | -| 1.10 | 344 rps | adaptive | 99.9% | 99.4% | 7.2 ms | 31.2 ms | 345 rps | 0.426 | -| 1.30 | 407 rps | accurate-only | 0.6% | 100.0% | 24.7 ms | 25.2 ms | 3 rps | 1.000 | -| 1.30 | 407 rps | adaptive | 99.9% | 100.0% | 8.1 ms | 17.9 ms | 403 rps | 0.411 | +| 0.40 | 124 rps | accurate-only | 99.7% | 96.0% | 16.3 ms | 34.4 ms | 122 rps | 1.000 | +| 0.40 | 124 rps | adaptive | 99.7% | 97.9% | 15.6 ms | 31.0 ms | 124 rps | 1.000 | +| 0.60 | 186 rps | accurate-only | 94.4% | 85.1% | 24.1 ms | 53.0 ms | 153 rps | 1.000 | +| 0.60 | 186 rps | adaptive | 99.8% | 84.5% | 25.1 ms | 53.9 ms | 161 rps | 0.942 | +| 0.80 | 248 rps | accurate-only | 77.9% | 73.4% | 34.3 ms | 68.3 ms | 144 rps | 1.000 | +| 0.80 | 248 rps | adaptive | 99.9% | 86.5% | 29.1 ms | 52.8 ms | 217 rps | 0.790 | +| 0.95 | 295 rps | accurate-only | 18.4% | 79.0% | 30.9 ms | 53.3 ms | 43 rps | 1.000 | +| 0.95 | 295 rps | adaptive | 99.9% | 95.3% | 7.3 ms | 37.6 ms | 281 rps | 0.489 | +| 1.10 | 341 rps | accurate-only | 2.5% | 88.0% | 28.8 ms | 50.3 ms | 7 rps | 1.000 | +| 1.10 | 341 rps | adaptive | 99.9% | 99.5% | 6.3 ms | 24.5 ms | 335 rps | 0.415 | +| 1.30 | 403 rps | accurate-only | 0.4% | 100.0% | 17.0 ms | 21.1 ms | 2 rps | 1.000 | +| 1.30 | 403 rps | adaptive | 99.9% | 99.9% | 7.4 ms | 19.0 ms | 394 rps | 0.405 | + +Repeating the whole sweep twice more with the same seed moved goodput by at most +6%, and the ρ = 0.95 adaptive figure by 2% (281, 286, 285 rps). The accurate-only +column is the noisier one, because it is computed from however few requests +admission happens to let through. ![Measured serving behaviour vs offered load](img/load_sweep.png) ### Reading the results -- **Below ρ ≈ 0.5 the policies are identical.** The adaptive planner routes 253 - of 253 requests to DistilBERT and matches the baseline. It does not degrade +- **Below ρ ≈ 0.5 the policies are identical.** The adaptive planner routes 378 + of 378 requests to DistilBERT and matches the baseline. It does not degrade quality it does not need to. -- **The gap opens as the queue builds.** At ρ = 0.95 adaptive delivers 287 rps of - goodput against 37 rps, at 48% of the compute cost, having moved 526 of 603 +- **The gap opens as the queue builds.** At ρ = 0.95 adaptive delivers 281 rps of + goodput against 43 rps, at 49% of the compute cost, having moved 753 of 881 requests to MiniLM. - **The accuracy cost is bounded and small.** MiniLM measures 90.14% against DistilBERT's 91.06%, so the worst case is 0.92 accuracy points, and only for the shifted fraction. +- **At ρ = 0.60 the attainment curves cross.** Adaptive attains 84.5% against + 85.1%, marginally worse, while admitting 99.8% against 94.4%. Admitting nearly + everything puts more work in the queue, so attainment among admitted requests + does not improve; goodput still does, 161 rps against 153. This is worth stating + because it is the one point where the adaptive policy is not uniformly better on + every axis. - **Attainment for `accurate-only` is noisy above ρ = 0.9** because it is conditioned on admitted requests, and very few are admitted there. At ρ = 1.30 - it admits 5 requests and all 5 hit, giving 100% attainment and 3 rps of + it admits 5 requests and all 5 hit, giving 100% attainment and 2 rps of goodput. This is why goodput, not attainment, is the headline. ## Reproducing @@ -89,27 +119,34 @@ python scripts/profile_variants.py # measure frontier, write serving. python scripts/run_load_sweep.py # sweep load, write CSV and figure ``` -Add `--quick` to any of the last two for a reduced run during development. -Outputs land in `results/` and `docs/img/`. Both scripts are deterministic given -a seed except for wall-clock effects, which is why latency is reported as -percentiles over hundreds of samples rather than as single figures. +Add `--quick` to either of the last two for a reduced run during development. Do +not report `--quick` numbers: it drops accuracy to 128 of the 872 validation +examples, which moves the measured accuracy by half a point. + +Outputs land in `results/` and `docs/img/`. Both scripts are deterministic given a +seed except for wall-clock effects, which is why latency is reported as +percentiles over repeated passes rather than as single figures. ## Known limitations - Single host, single task. No GPU, no multi-node. -- The figure above was produced with the Stage 1 subprocess worker, which has since - been replaced by the in-process engine. The two agreed bitwise on logits and - within 0.4% on inference time, so the shape of the result stands, but the sweep - has not been re-run through the engine. -- `configs/serving.yaml` still holds the service times measured through a separate - ONNX Runtime session. Re-running `scripts/profile_variants.py` now measures - through the engine and reports wall time per request rather than time inside a - bare session, which moves the numbers by roughly 4%. The config, the sweep, and - this page should be regenerated together so they continue to describe one - measurement. - -Closed since Stage 1: service profiles are no longer measured beside the serving -path. `scripts/profile_variants.py` measures through the same `RuntimeClient` the -server dispatches to, and cross-checks every variant against a separate ONNX -Runtime session, failing the run rather than writing numbers to disk when the two -diverge by more than 15%. Measured agreement on this host is within 1.6%. +- Absolute service times drift with thermal state by a few percent, which is why + they are reported as a median over passes with the range attached. Ratios between + variants are steadier than absolutes. +- Batch size is fixed at 1. There is no batching across requests yet, so these + numbers describe one request in flight per worker. +- Attainment for `accurate-only` above ρ = 0.9 is conditioned on a small admitted + sample and should not be read as a quality signal. + +Closed since Stage 1: + +- **Profiling no longer happens beside the serving path.** + `scripts/profile_variants.py` measures through the same `RuntimeClient` the + server dispatches to, scores accuracy through it, and cross-checks every variant + against a separate ONNX Runtime session, aborting rather than writing numbers to + disk when the two diverge by more than 15%. +- **The config, the sweep, and this page describe one measurement again.** All + three were regenerated together through the engine. Service times reproduce + Stage 1 within their own spread (12.89 against 12.79 ms for DistilBERT, 5.19 + against 5.21 ms for MiniLM) and accuracies reproduce exactly, so replacing the + subprocess transport did not move the result. diff --git a/docs/img/load_sweep.png b/docs/img/load_sweep.png index 7dd323b212cc6f7571099c0ec619ddc5e4dcb1d0..9e1c7ac1e32ae3c97f2fcc7c464ae690acfaef06 100644 GIT binary patch literal 198635 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 z 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™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 z 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੩++7_PhyBjM1vD=8@9vdRu^h&JN978tF;UAI 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

    kHmzU77x+9* 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 z

    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

    sula5+1ZT@0PMyzhicar!~5 zc4e_5cq3)=p2iZ_5&6F3IVB zl~!C{9{--@WC*Y;rU7BINd{LWwGS4dz{=`;iTF2MdZ1Vomc88|wm)x+_&_!HrhKD_ zZ9ny&m(4aeQoMeTqH?~@sUzsxIfz-O297<@OHB7jL+7g^{L*;(U6R93`v;$x_rwg$ zBDMBHUoOA|n=79cRIpfKGcN(Ls0vr~)OrZIflG7{0hcuEhekd{qDMX1=LQXo_N59= z@;Cner)^DgZq{qd+yO4fuiHZda<74h(D|KHWFRWis%HSiB2y9>wsGEt4=2X<_tp~r zCe)8TxXF7vg7Pst$-hoJ#=6BYf>> zf4?y}1m`}ck}P`5>%MwAxzY5dFePUi!||GL-_+6U69W{1Xgz4QodN;_Bbtf;+|k>b z>jX=p`$){S!<3tHFF{jrZtk6Gcz^H=ZyeiL_7R&uI|)Ri{OljPu>B?wc$e0&>3G0a zj*bjdnYrQ=%|idqbI7%?KAFjs{RobVR|*zI57TAir@b30*z4TR=S+RJr6YaEYZUFc z+3{mwWwkV1%<8Qeh{)JDUMAAHAmH49eIo6WQ(WO|6tcq>~4TTAE zL?H7a3RG|4hSaZ_{#l6s3-THO_lbhf8JTYvw^`;p`Al_O<4ne!zy^YCt5*Lq=8SK` zEJ(R80q5Og(OEC)t8BI*Jh5FkzF?DBvm<(x;*bg~5Z$$3nVPZqB;L!*vHEA~d{(CY zXu0^K`3+Qm4~26KvqSu%wxz?nAo_Zf7YlsOiBvAG6V8N%!)_VP3$wGYpf6a++l>RA zu>cB!=^-R6y{V>OCAuVe;cqV~TvuOxpV@I)L-hdX3ih&Zt%tb~5E;Um@ggq#TLlAf zEVW4~ck>I~$nj(Dn7V4#e&Hc(djj-TtKAh>p4^s)A6sv&T8o(Be`4BhX{*IMoaAD-RrdTdV63#zg$5v-c))}Z@0xik z6kUiTZGy)aAxc4LW_&xa3UmMISzVFSpL_UzLD{##JC%*IpCuTpA-oKW|C5JhW7u>C zdg`-$rvh8A^FxO?1NPq3U9^3vp&?Ssd@Y}tNfU6%3XYDzw!}khc%E)_74xAtFSagNyM>)o}H|F*l5B($?yQUQUl3s z7m1GQeXlnbAlUw+q{N{X#=|w{w~3rMSCmZC4+EY+ho+I8l3nnBRmtxkEVbc8pcd{2 z!2q8n9rMT6<z> zHeY6X84sr~yRx>yAskaYla)}Ah5cF{Qd<8R3g+eGe4Q-09xWUi{;qdX>~RARCpbmj7oGoK z_R_@lpZ;A-^Ng6nv;DoSScOQM|BM*$-r2FIl6cNPtL#Uk2-@eSH@ot4@0p>j)G=&* z#m8H``Y+B83^cHW>N1Xa6HYn!D8{JvlcD$(9uc8&Xo)-y(wi*yQbJ6Fl zPh_B6eRpy?Nr4< z#TvEElSBX9cz7WVPR6mZbv*0&SN5tKGj5k*LkymOVJ4QL-W6g$DZbERoS##F8xDEE zl21?ew7Dlz1%XxjW_u(;aQoeK$RNQR{bLCa-caesd1U)@!?qk7T&eTjF0-%QS+NHT z)e%^`33StP5Kq1O9?F?MjDo5b${CMwG^(tcroFdd{R{Rk|E_!Wk}o^2ey@%~_6r=2 z00m^sN2YAf?cS{@6yJd~jQw3)06C5d=l(5!CGxahKX=Q>oVW^ge?V#cw-^#J@;-^^?x!PPKz zRGWWE=G(D16J0L=^IcNMe6@-^kW>TgioLAS=zasxKxiI>!JUYc&%dhl(bWs*Q#jQa zI#AhO$xEx<+~3gBQ2#()x_5D&!%hNoZEc@G@XSoichWNT+Z!4L!ioHYqyGn+0A{E@ z83NMaE{gNjbBN}efBRE{xjM^AO+leZOnn}uK`1B0m1d*VtXHJp++!a9Q3g@NfUu=L zx%BhC#rNFdbI}whulsua9-GUq8TX4zsHmOR&n~bwefsoxXbTb-A3-SL%F0TRV=;ma z`3DMlf#*w0y&d}ZsUs4Up)=2Yx+WV{Fd(ro*9eErgvZb2*A{b)#9V(_+&dYJ_OmsRAXg#h3NN3n_E}3?8!A6P zKZq6xeHw-#I)~bcH=^va;Xj8ac*+9phK+M-D%lhR$ws za|rc54Gb3j=tpVgvRr(p|46#ZVF@S8mp163yAj?OMto?Cq9tg9f^_Me5e)@(y3mhB zJ!ThIr?~fhz3R2=w;RTsNlhve#l}1XJms<^RC7`YjW3qvkJ38J@Ie~T;W?=on(SPV z9TpT67?`w#^B-P@hAFCh0p>_kjau@qAm}Tz5*f=P%;eEIVG`GOUuinE8b&20m(Jw%F~QqTm?zc3!u=L znfJ?cx3y*M@bpNSnH7*P+^(1bl+G6DdrM20!a8@31lw@GFwZ&}l1qdq0?vrtRw&&F z=8@W|K~Ik!#*^duJv41>&zN{4Xa4I!^y=3ew?#*=geVc!)u%?^Pr|CLQ=Z&6Z zI$cO^0u9=3&`tfHdPZJ@QEI8rxzShanB4{APnK0PbLDqxETcccf(p2EJ=-%^#{ zEuaLK;_uYSB=f#2bc?wTE|~A>lmK(qeF0BKxm}G9Bz<-!n}PO5HCvz8_GbwBaG|<# zy9-22WnL!^>&@k|;2A5P!YHOV(M@-qYzV-p@$OHl4{sqro7vo?X`A(X_!q}V9yMg& z?u!B|u_$5totFV2fk`o>&q7T7ZYw3{XpB4XU+W)Aj$XX-#G}Sxon=`Y)^)7I;{kS} zY9e^?_is^`*v)m|omXUTVy?!q50@Y6-+Set zobt$3FGy>z@YZ$C=h$FbwK=G)jR*$0Cuf*r-C)F3sj^D@{v5bhU%9|S#caG1he7F+ z&LV7?`*NOACKSnD`T_jCe9e2H_UDH1M;0WOBWZnM!JpE7{{nEju5p<}UztJ$;`ixD zG`;^JWv}S?;PsiwJYhdWytpq-mWMC)J=iEfKJ{%JHWQ>5f6haa26a~!h}4}fC|~8W z9T^V}!jiP5B@Q|*9X&v{lcJiepG+Blphb? zkC0X93k%Uy=r_iwC%|m+fy-`z1}lV7Wn&Tc$HvC;Oig)u{u6SIT?lPL#F7QC1fZK% zfG#3lzxGtCFwup@D`_R(x;acJD(?+20E+TQ)+xy*E_-V+UUez%hfnx%&j;=WP14W> zSMQu*)*oX}yAkzBEz?|i3i)^S3edr{)-2LK_PJ@bN9?2d07prKJbGxzYRA}TOY`Vs zb0_NIe;sqtk&&-pIbpoq6aPkll}FlOrALYg86{n}mbq8>lb-1>uB=*xX#S*ApyC9QWmZR$tgmqxT!snH4`D-h?}&Kj!rm5Ki@fi-r516Sj}iW850B$&6Jh3%YmppS z$8Tc7DltXNXaZX^+b%iXH6x+kHO7g2HHV^dFlG5lNr}ti)SC3`!E7$(ncxx@h)QlPpourEq(FW zP*&|%gYtv_Y>*-o5)xKQQxk48ghgW#xNbexOxW50{@Yxgr@!1efnVl@-?y*?mu1;L z?ORKe^|juyL&G~ z&qoj6Uaj-BOhCxb=B^O_3bywx+dOy<$*rLD1HZ=lb6JGk6T@`b)E>qgefB%I2i|Ow zGEGP<9B{9l)M^f$!jw_;m*1AobWwZ#cWzkVM4s`&1a5Fk?t1u5wp)H;0K^4|Kb49G z=HCDoAjqG$D>(*drqqKC8X?N^!oMBs+qWT5kq}%a#^>X3yo?fiy@T{>o!CHsPS9n&0qBI z;!3@HUrg?=oo%rZ5}OAT0^lYDAX*XC(V>EK9#G*Bc+Yh~FI7@e@p+4?2!@>QIM#M( z19dDc!eH003oJ|IvF_y;htJR8jQIDDRpi?z=H7CukNJS@dNQ^CuLH(!d2J@jVQjnl zB$yJAQ-(I|+gQz`aXLT$*}lFLo2!J+pIhas5%hAo8L&xRY6ejomZA12;$S^9m}umF zvZEXV-aj(KFdhQEPDoLa5YU}X@aC9>Grt8w8U5k;H+BR_eno|}6G|1N6aX3(-^q*ilJo<| zq%8oCW^SafPtJ()4s=A|FunBsBLVSGiMlhy;z1rn_sy-8VfvdLpI*q({J_yeE~ny4 zkPvx$;s`uSii}(~2Z3Op#b;uoz5R1bR)*5CA^Y}7 z_E2{7&rfdM%AscGCW`Xl4J`J%FH+01b~uSl%jx)nnG{UJ??@27>CQc%?D_dd1;4eo z?0a@4QA-P0x!wQ7WBX|G`}=&QOQ=+CYrpw>1%vy=h_h19Yy7^-xA&!_q&Upl|0NPV;2+t1{(du1fQYsPNKLRk@iVpXxycZy zrpW3G{4r$8?U>X`A0BoQNNOe#Uh1CIIltDw!N$*P{Xubc907NU{^&FUnbydF4A};Zy=Jr8ks?ZjFj9R!^(Gb6{>m6 zCh{NY>fZD=ex5u(l1-gX-IS`#5>TTl1Plfp-H2WPo6rh`m0>z!05R-+tTJG|=@}Wi zMn=kxDIi0^TlB5E@En95W5(1dOU@7f!#F@(>0-*M{S}N(hPuA4H;}`JSkeEF;oImq z!|!AI+}YXG@=Cw_r!=ZZl2PAEsHB(+4J_H&FPl`5mEyiK_(uw@nI%Q+jSEPfn2i*A7Bvh_$P3^(}-ovBpCI z(1e8nj#D=A>{3HAzgyyRs`5FR)dQHyj(^##grubJhKF-zVf}^}Lbt5L2oRHyPg`Oo zj?=S0MdZ_dtJ`V&zNUzZ2%(mxR<=s=U07&BB*Ikfxt4|&MIG?GSZ|hq6%x?O%~6>I zV|231fodEBPr3KzaTh9Yy)z!Yb!kGS^kpnTKpl|!_!H_QCo`=cGo>m`0UL^)h~gI8 zuNZGQuaRh=ts-Br<}opKK}rUm+~Y}$A(gx3#FJ<9m_q51b9G8b7bD^enqLnYCNv;R zsN73zWffu|cb=olRbm)DlKg!Mi{F;K?}GB{{e9i+RX~NWS|7Y6zgy599o57tM+rrF zrJk|H=l%^yjD}zQmvTVOH}jWrfZc5lYnulwEG*;R*RQ{^ClR(#xUSXkcBt)sErkvw z9k5;UdrzrYw^2u(tZsk}GaF(##LWjn?d%7cLPjedxNU1^yltrZaR)Q*Dr4(&DY#Sq z%{}<*5HM4KqP;SY3`)OksKpJnOBo8fls=x)$vqk+bIeeFny|*EF@Rd@3N5d8tY9%o z8($rr|IyKDWVm#p`Ls&Cy_#i7;ts@>Rbsz~eL#DvGBKzk`rauZZUK5=5QXSII13dT zT%EWZJkH!fco8usOIT~f2lz_*tl;m{q2pDOevxQZQX^Ajfd<=$_9QxE`X-Mt4+4xQ z40TgE#Dqb!1pDxMQm5B_$m+R4J~R0~iQH#k&Ol_c&d;i^e_54EDpSBULOkjkz+B|F z2nfIz!u1)6RHkSF`t>hcZA*_Csk(x6W>lTrnHY>8k02j2d43oU;hrI^hp zgC=0&OzWRIp+3jN>C$e**YpiVH(e(FT~^H6sj}&*$ zOamffZ1c;U3V$x`uX(A$f@!tlQu0fE*O_+Rb<`wUyBF}RcV4Y*?ofjQI^u%z9Kx-) zNzPI?h8u9iM4OIF&Y%=m{~6qTbiOVpfJ==Y+}JUcS%TYA9b2A(hgyj!Khh=F0PZO@ z=)@n$SH=bUp$P2ScGo5t8y!8)`K!pYH+z$dizu8@02Wrgy(_Dt(O8wS&s9$C6{J*c z@!Ky7&DWifP;|CWg}k^Vxn01?2>UTmLduPp)AwEPseJo^yvxB!x>qtNthqm*#E?gX z^m45|UfzC{)c9>5-p5uQS|F-mq-5-2o>nO&eruYI+Ju~Ez8SV&yWs)9{RNAS;8T>N zixM1nb%Ex-T#$7JC@3)(Sn=)>G_mwOl)BXN{7Z5usI~~_jgV%QCpI!NU0N4Ff}Xft zOuF>D&xo`4Eu;wQ8rSY#(Uz$lv0hmss4F{s5F28FVv2Q75_x=sI5o?&kZnZX6G`sN z@A3#mrm7R3k*qACa))6xq!`x@WQzD`^U|Q>T>oP8o+VzP(3#`f^93cm+oRDYMV0y%NmFj*t)WcUc1?kuK0$;8^UsF4tn(^c5|Bd)(>Rj$xH$eA|I~ zW7kFiX`aLGt?(hut0Fn6gnAcnwn0DLEhtM%3x9^w#W`xmW4X zpIq9kW6T*u&0nNxA2RGBdXO4-4bSi6g!)zcnY%z3lvPu2`5*Cl917okxhGBM9|?}? zq6_JY(`AA?I=a~(pEpu*uXojphiEMY!v@_yI0;n%tf8P0!N{t1Qd=)fwDUT(6fAs3 zbGj+)6P&1%E;bUg9Z*B`k6j+a4?h#G^!4wrg{QTRjjw|}__QJo^FOzpy}6$iVr2Om z7VQeh#CuA1H#FDtJxrB((pkdvyIcTa$J!*hWbC$*$|i2_amdO19mc4WKa)gj7+R^PUqJP1)tlREK(ySvngvc) z$T%8=p>H9Xpr+bVp{37#d1*kg^*gQD0Z+rR9yR|oP4!F}V&6^F{>r@dt_ zZHIR+*%mEcJd#i{#4Ub{qO};f!@{h68H{kT4m9zJC_inlB40Pt2paAx+l4Uu!~jf+ z|8)c1v*TVDR3U%t>VOUP)nA!jok9<8Te@EAgNiIELd=nvVk-YFP3@@d$aHE$TsBpb zl`bdJU-GoAMq~GY(m_Fi-_mIO#n9q{osE35*4bp^IAXv%v`^iI_IJ9?RAlI@G*^cs zhbW9aDX+QfJE68^Efb|cpw$0(ZLT=QBVRv6!`f0ZVf8~JU?fBh<* z-mnDKOkWO`iRNl(xY2(Jg6M2cc&Rnhe+eQSBN4xh%!(|+FOVvmCbWKkz7D2`%Z)ZO zs^KNJ0d>|yFvT4>pN_v7>J}6>Hpa-xiXoR0rIHFMEco`h?A14hlXAPUec$=Th0dnt z$i~9XUw=LcqzI+`wR!9;UPwi|N|f>{V(Q@MA~!@)U@~Ievqh>@M+vfZNl?~`@dk5| z)(8ymt8RPGyi(L-UQ?k{q4;*S&N<0S5l}(;rHj))(q&qQ^8kON4ZOVbM_SoYWA)z@ zHT!oQqh!d4)kRyO77FVY?$ucc^86(tnrakflWrcWdiJpWhq@5N66gcsxDWUa9wFf+ zBO@cwKB5A5o*R~gpwfoxqIh{Ewo3~9$FWF02w^xAkyeo9?LXiqyhq^6!F=cTMT5j- zlcCYy5|YDFtEwAPWxTg<%E`3nD~&l}a+V2AY3pbGuMm=h>$!8|l@cU*6egJ}LufCY#C7yvDov-;mpvrv&Tf&+3bzJyCNQ)3O*amtCA0WL+_JTcO zdV>RGS_fbTn7=Ei9x%Ui5!Xq{y!Dpi%Kd8~@5`P25kdXwiyt9grbLG`NR(qEjVH_O zQuv;lr2k@n_IuzRLuPAR$IbPa&ojd+p3U)bQ6l;1t2^n|BL4@`|XN(SqkY>^BX zM80(jIXY~hr3oSD#s}MtZ+jNdD#+c`QD@+cP-D?)!A)?Uo@;F#AOshLjz=Nard6tP za(K9u&?GrfzZ%Fgt@%Duf3<=dd-LP%IMbhouE_&)navZUE0f*~sGxbbxnq`2lJF}c z)-bP~WTF1rqi%Y>%-ob`9Xo4)5uU?edi9dsB+Z~sxCYH5^4!@x`Mp907%`NCfGt*f zdJM#vvmb`|ezZCt$cmi-w$Ud9GeL+3Ks4hWfCu7n2wY@Up4xPc94+8U(+;=GXQnfD zkxAXg^u-{7Z)m5MKZZ zJ!?A-+1(DC>gNrYUEyBC*-l-Ul$&)+zB@4ao@&;APRzdy1#ps@2e2{KIpasiNS3zq z22J3(S^gcm=xzALxx`SJllje|scgQkxX_mrL}LttR;KuqClOpmK8W{Pc6OZy5C9t? z+hVQ?MtfD3;T~LU>^VWO*Ws`+ldR|6pf#Zn9I#2x3BAnwpA&EQh(a$ZBLM-yozI`= z|8ene#?7UreNOqPe^*3uIV+a`SM0r{*ZK?{$5$7UN`J)s;cZDsOSb`~6oTtSqCNgy z63*K|_91szn7h-3Edb>WxzB*I04w{U?D{^Eh))p+EguUZm5R&A3{_?c2?;?=*r$t0 zI5{%Koj2=W#E|tlpYrMF27Pvj{YGAbC#{<6Lj=nt=zr+}Y5Q9shMS|x4h*<+rdDZ&fsT&;y~Yj;h}zxd zu0W%<`Cex9l;SzO7c_umMXb>?GxfbZ<%nLNe45SD6BN%H`-gpvMTib$EVzu(agNd0Mn$qeCtjEszQ7zPtFLoN!**KFzQ=6x>k zOE@fGo3%){F%Qsr9&UXQWSm{!zJW*#rZ~IC^0+4Xk@gpU zob>_T{lb4Fb>+|hMs4~-fvkpI54Fp!0D#(&n}~-8n+Jmje>Jm%chhzPQcBE7u(`}|8}&CMAUXx2Xa?@ytdPW*vBN)Xg| zQ6xj)>zz4#BKuC!ribiy>vmAcg~qbnI{_)uuyL~)8yt+`tIz$4815ra4mdl3UHH&m zkt`6L(`Umx1i(0#6zklR-!g5pTB+5Xe)l&A3LtV@x4wP=w5!Vt`5Wi7@vDp28R_YB z9|!yt;}Q3Y)^*#>he_Dr46XQma~&NtX!>AKLqv4Se3$>Z==WH?r>tESP%}C=VS(f{ z0H2}`{6lSnK}^RE=~Z%@pU!@ODRBr!V;NFK2;7bOg8%I3|6DovGlb$#p%ZS$FGFkL6eFG2ZUz(KR>xt|NsANW7 zd7APGB2T{pWi6Un{n_aRzOXyI_ByaZ-PqcSoKn`~HS8kfbvrDV-FqX^TTR=Wr0sD+ z1mcNk5A@HUKLhycpDhiJbCI-A&RHT)=+fi#)&ClnAUuSRyM&}$PHmNn7&+Pa^zh_P zK=f9{1608N2SCXEE6N;eR%LgZaMT2$kpuOq}$4$NJqzA>I98Gfv@0B@~?fRWQF-oFEmzynp zwGNgC35^ft#Kgq|YQU7$<|v4WvCFm`HqKkt5R5PgS_t2UGsWXCg+NABIdW41p45Tc zV1t`Wg|Dyg+bIZYw=**{i>O1V?gF8jBH_8SE%NME=5)ON!dRIlaSyFt;?8G}W8j+S zLv&!pb|V;|a5n-hb>KV+VHI)~0BoSX`jV8Ye%9tkaAAs~sv!r!O+Q3?hZJJ1^r0*g@=%Dd@Bj01MZ z4V`Lpfbs@AJ3Ge?*6X&z-U^tFln8ydWuRXeLX;)R?D~E@Y;0^T$FM<1v|97Fpr$Un zy7xA~#@n2p0TVoFC;iTZ>i}Yz4<4HO*ZYu$J5XTj2K7We5*Y zSN}FYgqf|*&E0aDCFgZ~4bN_N$(MZCXLs#@-<8rO7fITk?_<@rIT{~q7kX7$)(7+B zG)~(oJqWuRqO3dD!xur?n@5D{JNEs%#woKD>&=^jXzMW&S%;vx@vZt`Accu9`?(jM z5r&lh@$p*Ol(+yJ;E@oaBDDvM25Va3(fZ~TLr|F&Brx=w!3!}r1@#|@EiiVLhrg89 zd7Pcv)WI+3>f^3q$I|&2_$*Xxn^vRS?xZ5VjFhRznq7oa>UB6#_FI zTkGoL4|3YBLeQjkmqKbiE?LACIAi?Wwct-tJH#(W)OVHs8y9l16x`PTS=5r1eN7(6 ztbVV1KJmcI%d6VC0lFWlc(x1hKD3}yy2=K)NYL)o!Rr!4J`V0q(;!Lo@SBGxnH`8D zK46JN)SRsFgy#b}IeE$R&t%wScg2$hs7n|s8$HhWVSC#5-cYhYyO9DQP~T&g+y{&+ zjrk(g2)xJ*1?fKSwf~QgxC{3alyP%lE5*}24~L5l`HdS%`3rBjOk(os^a8LkPXt@&sP!xV*tHmw8;!7G}s z4h&u4_s^Q5%QeI?TIIjGv+Y-lWwT`;{{@MH(|A$ODk^3HDOZN9>}Brp{ZWz8L+un@ zB8^l4(2FlW-1flIU;2dhT*iwFHP;d7Z{(rT{+6t7sdPj(j!?eXr84Z*h>93ZhrGly zuvH@h5n8u@&pjThT;T-@?dNlIb3NWHnw?muXQsc!8EZ}ZRoaPn6&VgQ!t7`wuhbWm zv#5wrKxaZ6(<}7LES+NaB>q`U0>Qr%q@AiDDW#Q?YEAyu>6U6$B`mAL;#0GxO-pv|A|T8^ennkfB&**urk`2&?DB|;?2@QRSb z#!+{=8!ojF;1&clg(9F#$e5v#qd)#TJV`sqx4wXdPtCF3Of0zi8PVZCd%hWEcsPU& z${Lenc4V8o@yuV~pMW7<^yujOrEq?mS!0`ld>z}Z1tD) z&hgbX_W@Mw92~zor5Az*S>AA#$nIHf-?#4vXiN3e*X%Fp*kx$L(met~JAKvs4uYL> z$#OVe6U?4%1L9bx0$>`i7f3O z?m<+P8NLf>Io0^JrzZRx9y$R6i+$>Ul63$EH?v);y8I+k&&Sy!9jxd0<(RZTVvRFN zH0)PVJ1)@(jaLB0LuCV~R$91ddTsEpS2`E6CIqew*V{V={`&NZV#(zU)M$E2hKnZt z9C4_ph%&B~Wp*_8>C-lpgHSRI(b5HzAsAHScAz)PCdXSRD^6TC3c*or7@AS`Lb@%V zs)?Gl6Sn!cdle^kIwohMC?&}J`yf*akOEHte%Dq zHvUP9&z_+|FR+X6m^E)+MC%bu04a|G$jH=rkD|MWv35D!Bw1%6IUAKxN-1Go5wzCi z_oB%Xf*}QCn)Fg3xPX16+GJt3f@QLdnwr|1C(wT=CW!Ge9s&5u*aNshe|q_H6@l_Y zJZP||!Ll`f8*^3Rij&I=SYzMTVXl#3ReOei28SaNoF#vWo5NB8U3r^Q!b*~ZMfA|@{8_y47t1oxVS{BMae!}*eGd1 ztN(!M#onAFO>*VXW!wgzbb^BqgFKOUV{7KMcHl!L3+D{-p*_3B#6%PeYV0Z8O%Rt* z+WS=ep)2=KlC@K~q$#j^VUtDJG7sZ$EfRYZ_L);<6_3}tJ?;qzhcFac%2sq?R-dd7 z8c+o5M)unGwUvDx8R0${!}EDMWI30aaO2*ns;WRo?|e*5%&VlkcgE7_9F3`RTyKel z#3i@~Nu1PnbSdZX)wQ*?UuEpo^mzZ&dRUgc9-@jzfu$=lNM}KhjMBn4la!`FC>0}c zl2K;w%|s{R21Lz0>JdCBdaPlTj+Nz!6Oq2@I|Cx#XX{;>=i>Vrm^G)@cXsx-Jrzk; z*VKf$OMe|2da-fQ769K+&&kEv3U}&vm5ph2uzgz9jqbZ!ziq3`rzZt6}AicWyq)$~qGo8rmbcb_3fCM~GJENIrt~+D)5I zb&gV5HnL?dNPl^*zqYVNVh@HZuFovLE7Qaa-+Z?vU}SF;+p+fif{w71Q}PyPgGX+( za+Qk86^lByA8j?XVSFl^Wb~afBmCt@lXuJ3`hWW^TEol8jD0etLF~KyJF%_9&Gos* zSAvq@a_mhcWAKw0;RRVPxq0*Ev*O~PK&MxIG!a|s^#bB=Y_7^k5U`Q-#GFPHLaJCkIze?0x&LwU(GoBYmFoz^ z%z*{WvPov#&71c!FnigZuq#DKNa%!D4`551avTnZy~dzx~~tK3kU3obRpxX)_3o0#^JX_i+@^2c7x$I z&^~mCqqUNTBHij%R8;Dupkqbv7-$_ss3{(2+P{pqMFA!192n447?AH>C?aDPrD|~W z4J6S-n*g~tT`nOJ=|sl{22rcPAp;>rPNFaMtjNj0@p*ISzIZ#@shbA>bx&{GwntT^ zc|es)=9!Frg(z7CcOzpi6HSNI_sz{b?>Q1GVceKlk!&5LDCCestXXvV%r7hR_a`+t z_MOsP1D8{|@e0-^(DTw!26Z(rII~9V0jrOb?9)}NK-w3gEi;6L4}8;aB^V7lLp?yY5`CNc2&N?YZWKz8 z-9KB7ueMnwtH?lhwz3=;qZghG0A={!kk?>q4^umFCe2B^1N9m28;q^`QDMrZw}5#O zlEsW9Mhxmr*WGemyXG!gJIy#k>1y|5j|PkU9&iAWYHd2&QV@h9+rCvnS^DY|rL;Oq z^@wa&wt=DHZ4?5}*U+f$afrIv%#+FrN74>gEKHQFt!Z!_-xf5)-NDHE0bB6UX0q ze%RKwZhFx$asmD~mtv9QSy~+Ya*3`JI{x2wg>VWAvK{K0nwDMII-t>@9d~d7A&6%u zOvMgtZ6zcg%bxpQ71{1GwDf|2?)|x0p&Wqg%7G^hy_e3N6GEBaH`r;(Fbf)3n^|u7 z9M(XZHR>5wsjrReUT|F_;`WEf)m2n|r=*beLh*IDrH{8}qT{m?gUFTJFP~05{F&ux zuzh=FR!q!$V=fn4P?f9r*gNQ{boK}}J0~Y{|8Wn}Ywr&x4@$pCzLTG26+Mvf(Sq9B z+t1-W{Dn+7+h@BOSzS-v&1QdHq-aI?>dvMsY$M`*U#|36Wzw}v_8S{lZ98SAx6j%6 z+FyN08P32k5-8gyJh9=CmW0^Pi4Z zi}IVFBLnh!2^Jo7_je3$Uf99Kq>0zD4x8y5bVI*oR4D99=?uDI8UG#e!4tg4agTFu zvMFRp5QgTH8LxRU*`L4bmbZ+GXp zah$Vq5qLms5YO9@K~<|NM`grX-Z2($0%$Q2(I6^M~sJvY5M!;d#U{E`_afZ;rPd1MW8Jpj9a5W}a!x>pnG?^*YkKmDSN)P(uHAw=2 za&4Gav6J=B{iU}UI=xSzSg1}wN;y071JM7Zw+&uda2_j!K<+=?A4)`)=TP9guBqj& ztVki0ZyO$_BbG%)xHB_?Pyb2+0@_^YF`Ly#AcrlQdU~s`YjQDkPKHa&uDiZt^2xs9 zvmSK|&s;#XuFU5k$+4ki-cNPBlXp5Zv!k|FFp9y;NuG^q*t=NJuWKr?YqvP+^* z4UBhv`rSMk>U0LR(#?_G#tA%q=1LrszRk{V31q_J4o@HvQ7KQnbj>2Qx~{L{%SOiP z>1xkFk)%I8`kx=w3~}vor`ZYFuGF9~UD)XLGhR+8Y#B^t0LHNl*zM1BH_yY&xMcIz z8?m2eNJvR3`LPa$x9k%B$sjWqBX{0mP(K0#g{SNj%wUXk$-LFIfqkHt5ZkEHoW^+7U1K8?j`zwk8g#Y4j$iXTn}?Zuh(= z{wlfj78nQn!tG8)kvQixB*t$Q6coA&Ui#ZOV>?W&#)b_WN_3b^W~B>g*)=2NbnTbt zM4v~1+`D%#-zTdE)heGngigBj`oS z<-ABEvYWlgaBd!MKy{lEFad{t(AOMIxX6x+K)!34(@ze3G|k(KcQjC74kOcF>S2uJ za5*`6G*5oeZ>*eyrUm70R#KVHp3@F5W-*nftyr<5*MRTS!jQL|pDMGJ`r?B3iwnMD zcHJPaFab~Rg3Y86ZLBd+`9ETzQe8(aRuiR0XYQiZqKjya!NDyz&}tu_J9mzW%^nvP z3@&(==}2|d6JE0Cv0IY#=HKF#!}P#xbd)gdoC+6O_=|I|T&x{W}4ljnCGx_5f%MrV8A*K3b)h9Z~%vUb79 z5AHVaxmz!vl~JELW|wm`rkRDy78MZ`A7__5YdZAp3|SLx)6e-Th469g+5U9XKRmEj zK+rfZqqbM#Bj-y= zrIRT~!D$thes%(`HP~H#RdZS(@xz$S>+!6gP zp&P4v{i*}^Yq7?BhsM8;tiQj8?ub=CnL#5mI=A5bID=}l+c|-CV%-zy$8;4KP1-}? z)@r6amQ1Yl6AwOJi}rKO5o$t#RNR=y^*H>$b#K95IWUb@@XIS9vq9PKJrB9HXpRXc zs{8%Y`~8mch68wmT8V}?zR~A%IAKOf4kR$!7se(>e!?-<3dAHNROy05CiU`<$%z182BTuPnhjAyAe5r&Zqu?t7 zKlPgQ*YHaNVuk4XO92J0Iom%(+W>0s%S#BG{LM z>HFmsi{YQd7D4wYC4S1MJMTWkg()839jv~Q@MW*eN*?rW)!g5GfE{c;-gaKp2wnc1 zEnNG1Rtg1}nvtCvXmtc?cy)asVbdPzWTI_795Y#0YK6>s%Xb2D&<{iFlcGz0N8;b8 zvY&*7h4-P;3@tdlk dict[str, float]: } +def _spread_pct(values: list[float]) -> float: + """Range of a set of measurements as a percentage of the smallest.""" + if len(values) < 2 or min(values) <= 0.0: + return 0.0 + return (max(values) - min(values)) / min(values) * 100.0 + + def _measure_through_engine( client: RuntimeClient, variant: str, @@ -167,22 +184,46 @@ def _measure_through_engine( *, warmup: int, iterations: int, + repeats: int, ) -> dict[str, float]: - """Latency as the server experiences it, through the runtime client.""" + """Latency as the server experiences it, through the runtime client. + + Repeated in independent passes, each with its own warm-up, and reported as the + median of the per-pass medians. One pass is not enough: the same 200-request + p50 measured eight times on this host ranged over 6.5% for DistilBERT, because + thermal state and scheduler placement drift with whatever ran before. The + within-pass standard deviation is around 0.45 ms and says nothing about that, + so quoting a single p50 with a within-pass spread overstates its precision. + """ request = InferenceRequest(variant=variant, inputs=feeds) - for _ in range(warmup): - client.infer(request) - + pass_wall_p50: list[float] = [] + pass_inference_p50: list[float] = [] wall: list[float] = [] inference: list[float] = [] - for _ in range(iterations): - response = client.infer(request) - wall.append(response.wall_latency_ms) - inference.append(response.runtime_latency_ms) + for _ in range(repeats): + for _ in range(warmup): + client.infer(request) + pass_wall: list[float] = [] + pass_inference: list[float] = [] + for _ in range(iterations): + response = client.infer(request) + pass_wall.append(response.wall_latency_ms) + pass_inference.append(response.runtime_latency_ms) + pass_wall_p50.append(float(np.percentile(pass_wall, 50))) + pass_inference_p50.append(float(np.percentile(pass_inference, 50))) + wall.extend(pass_wall) + inference.extend(pass_inference) + + # Tails come from the pooled samples, so they reflect variation across passes + # as well as within them. The headline median does not, by construction. stats = _percentiles(wall, "wall") stats.update(_percentiles(inference, "inference")) + stats["wall_p50_ms"] = statistics.median(pass_wall_p50) + stats["inference_p50_ms"] = statistics.median(pass_inference_p50) + stats["wall_p50_spread_pct"] = _spread_pct(pass_wall_p50) stats["iterations"] = float(iterations) + stats["passes"] = float(repeats) return stats @@ -192,18 +233,32 @@ def _measure_direct_session( *, warmup: int, iterations: int, + repeats: int, ) -> dict[str, float]: - """The same graph through a separate session, for the agreement check.""" - fed = _declared(session, feeds) - for _ in range(warmup): - session.run(None, fed) + """The same graph through a separate session, for the agreement check. + Repeated the same number of times as the engine measurement, so the two are + compared like for like rather than one median against a noisier one. + """ + fed = _declared(session, feeds) + pass_p50: list[float] = [] samples: list[float] = [] - for _ in range(iterations): - start = time.perf_counter() - session.run(None, fed) - samples.append((time.perf_counter() - start) * 1000.0) - return _percentiles(samples, "direct") + + for _ in range(repeats): + for _ in range(warmup): + session.run(None, fed) + pass_samples: list[float] = [] + for _ in range(iterations): + start = time.perf_counter() + session.run(None, fed) + pass_samples.append((time.perf_counter() - start) * 1000.0) + pass_p50.append(float(np.percentile(pass_samples, 50))) + samples.extend(pass_samples) + + stats = _percentiles(samples, "direct") + stats["direct_p50_ms"] = statistics.median(pass_p50) + stats["direct_p50_spread_pct"] = _spread_pct(pass_p50) + return stats def _measure_accuracy( @@ -269,7 +324,9 @@ def _discover(model_dir: Path) -> list[tuple[str, str, str, Path]]: return found -def profile(model_dir: Path, quick: bool, tolerance: float) -> tuple[list[VariantMeasurement], str]: +def profile( + model_dir: Path, quick: bool, tolerance: float, repeats: int +) -> tuple[list[VariantMeasurement], str]: from transformers import AutoTokenizer warmup = QUICK_WARMUP_ITERATIONS if quick else WARMUP_ITERATIONS @@ -290,10 +347,10 @@ def profile(model_dir: Path, quick: bool, tolerance: float) -> tuple[list[Varian LOGGER.info("Profiling %s (%s)", name, graph.name) engine = _measure_through_engine( - client, name, feeds, warmup=warmup, iterations=iterations + client, name, feeds, warmup=warmup, iterations=iterations, repeats=repeats ) direct = _measure_direct_session( - _session(graph), feeds, warmup=warmup, iterations=iterations + _session(graph), feeds, warmup=warmup, iterations=iterations, repeats=repeats ) accuracy, n_samples = _measure_accuracy(client, name, tokenizer, accuracy_samples) @@ -321,6 +378,8 @@ def profile(model_dir: Path, quick: bool, tolerance: float) -> tuple[list[Varian latency_mean_ms=round(engine["wall_mean_ms"], 3), latency_stdev_ms=round(engine["wall_stdev_ms"], 3), iterations=int(engine["iterations"]), + passes=int(engine["passes"]), + service_time_spread_pct=round(engine["wall_p50_spread_pct"], 2), accuracy=round(accuracy, 4), accuracy_samples=n_samples, engine_inference_p50_ms=round(engine["inference_p50_ms"], 3), @@ -329,8 +388,11 @@ def profile(model_dir: Path, quick: bool, tolerance: float) -> tuple[list[Varian ) ) LOGGER.info( - " p50=%.2fms p95=%.2fms accuracy=%.4f (n=%d) size=%.1fMB agreement=%.3fx", + " p50=%.2fms (+/-%.1f%% over %d passes) p95=%.2fms accuracy=%.4f (n=%d) " + "size=%.1fMB agreement=%.3fx", engine["wall_p50_ms"], + engine["wall_p50_spread_pct"], + repeats, engine["wall_p95_ms"], accuracy, n_samples, @@ -432,6 +494,15 @@ def main() -> int: action="store_true", help="Fewer iterations and a subset of the validation split", ) + parser.add_argument( + "--repeats", + type=int, + default=DEFAULT_REPEATS, + help=( + "Independent measurement passes per variant; the reported service time " + f"is the median of their medians (default {DEFAULT_REPEATS})" + ), + ) parser.add_argument( "--agreement-tolerance", type=float, @@ -463,7 +534,12 @@ def main() -> int: "or pass --allow-fallback-backend to record fallback numbers deliberately." ) - measurements, backend = profile(args.model_dir, args.quick, args.agreement_tolerance) + if args.repeats < 1: + raise SystemExit("--repeats must be at least 1") + + measurements, backend = profile( + args.model_dir, args.quick, args.agreement_tolerance, args.repeats + ) frontier = [m for m in measurements if m.on_pareto_frontier] payload = { @@ -472,6 +548,7 @@ def main() -> int: "task": "text", "accuracy_dataset": "glue/sst2 validation", "agreement_tolerance": args.agreement_tolerance, + "measurement_passes": args.repeats, "variants": [asdict(m) for m in measurements], "pareto_frontier": [m.name for m in frontier], } @@ -484,9 +561,10 @@ def main() -> int: LOGGER.info("") LOGGER.info( - "%-18s %10s %10s %9s %10s %s", + "%-18s %10s %8s %10s %9s %10s %s", "variant", "p50 (ms)", + "spread", "accuracy", "size(MB)", "agreement", @@ -495,9 +573,10 @@ def main() -> int: for m in sorted(measurements, key=lambda m: m.service_time_ms): verdict = "frontier" if m.on_pareto_frontier else f"dominated by {m.dominated_by}" LOGGER.info( - "%-18s %10.2f %10.4f %9.1f %9.3fx %s", + "%-18s %10.2f %7.1f%% %10.4f %9.1f %9.3fx %s", m.name, m.service_time_ms, + m.service_time_spread_pct, m.accuracy, m.size_mb, m.agreement_ratio,