Repository navigation
fix(embedding): disable the onnx memory arena on cpu sessions - #11
Conversation
ONNX Runtime's default CPU arena keeps the high-water mark of every input shape for the life of the session, so a loaded nomic session holds its peak after each batch of long texts. CPU sessions now register the CPU provider with the arena disabled. GPU providers are unchanged. ort is pinned to the version fastembed uses so the provider type matches.
Builds the PR's base and head, runs the same long-text workload against each, and posts peak and retained RSS as a single updated PR comment.
The benchmark is now examples/bench_memory.rs, using sysinfo for RSS and ureq (dev-only, already in the tree via hf-hub) for HTTP, so CI needs no Python and the server binary gains no dependencies.
|
@hansi-codes review |
Memory benchmarkBase Model
|
|
@hansi-codes review |
🟢 Tier S · Ready to merge
CPU embedding sessions now disable ONNX Runtime's memory arena by default, while explicitly configured execution providers remain unchanged. The PR adds a memory benchmark example and a GitHub Actions workflow that compares base and head RSS measurements and publishes the results. It also pins Latest changes: The latest commit strengthens the CPU-provider test by downcasting to the concrete provider and checking that its debug output reports
📂 Walkthrough · 5
✅ Fixed since the last review · 1
Reviewed the commits since |
The previous assertion only checked the provider name, which the dispatch Debug output exposes, so it passed even with the arena enabled. Downcast to ort::ep::CPU and check use_arena instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What
CPU embedding sessions ran with ONNX Runtime's default memory arena, which keeps the high-water mark of every input shape for the life of the session. A loaded nomic session therefore held its peak memory after every batch of long texts until idle unload kicked in.
CPU sessions now register
ort::ep::CPUwith the arena disabled. GPU providers are unchanged.ortis added as a direct dependency pinned to the version fastembed uses (=2.0.0-rc.13), so the lockfile still has a singleort.This is the same fix that landed in claudear (appwrite/claudear#185), where it took a code indexing run from a 14.4 GB peak down to 3.8 GB. The pool already defaults to 1 here since #8, so only the arena part was missing.
Measured locally
Release builds of
masterand this branch, nomic,EMBEDDING_POOL_SIZE=1, 12 requests of 16 texts (100 to 1,800 words), idle unload off, macOS with jemalloc, 2 runs each:That is about 39% less peak and about 74% less retained memory, with no change in throughput. With 4 sessions and 4 concurrent requests, peak is unchanged (all sessions need their buffers at once) and retained memory was too noisy to call.
CI memory benchmark
Adds
.github/workflows/memory-bench.ymlandexamples/bench_memory.rs(RSS viasysinfo, HTTP viaureqas a dev-dependency, so the server binary gains no dependencies). On every PR it builds the base and head binaries, runs the workload above against each (1 and 4 concurrent requests), and posts the table as a single PR comment that is updated on each push. Fork PRs only get the job summary since their token is read-only. The nomic model is cached between runs.The benchmark only reports numbers; it does not fail the build.
🤖 Generated with Claude Code