From a8a9767e49e75f4d7494a6f649a96ac362678610 Mon Sep 17 00:00:00 2001 From: nasr <156965421+div0rce@users.noreply.github.com> Date: Wed, 24 Jun 2026 21:55:00 -0400 Subject: [PATCH] perf(order_book): cap the order-index hash load factor for shorter probe chains MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The order index_ (OrderId -> Locator unordered_map) is the busiest data structure on the engine hot path: every new_limit does a duplicate-id find + a resting insert, every cancel/modify does a find + erase, and every maker fill does an erase — 1-4 point lookups per engine op. At the default max_load_factor of 1.0 a busy book runs the index near fully loaded, so probe chains (and thus every lookup) are long. Capping max_load_factor at 0.25 keeps the table sparse and probe chains short. Measured A/B (Release -O3, baseline storage, qsl-bench profile 3s, same host, 5 runs each, non-overlapping ranges): ~8.50M -> ~10.08M ops/sec, ~+18.6%. A load-factor sweep showed the win plateaus below ~0.25 (0.5:+10%, 0.25:+18%, 0.125:+20%), so 0.25 captures most of it for a modest memory tradeoff (more empty buckets) rather than benchmark-tuning a fixed bucket count. Determinism preserved: index_ is used only for find/insert/erase/size — never iterated for output — so changing its bucket count cannot affect emitted events or snapshots (those iterate the ordered bids_/asks_ maps). Verified: fixtures byte-identical across g++/clang++ and vs the committed copies; OCaml differential passes. make check/asan 270/270 (asan now under the strict UBSan gate). Co-Authored-By: Claude Opus 4.8 --- src/engine/order_book.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/engine/order_book.cpp b/src/engine/order_book.cpp index 53f44c0..0bb866d 100644 --- a/src/engine/order_book.cpp +++ b/src/engine/order_book.cpp @@ -553,7 +553,16 @@ OrderBook::OrderBook(Storage storage) bids_(resource_), asks_(resource_), index_(resource_), intrusive_(storage == Storage::IntrusivePooled ? std::make_unique() : nullptr), - contiguous_(storage == Storage::Contiguous ? std::make_unique() : nullptr) {} + contiguous_(storage == Storage::Contiguous ? std::make_unique() : nullptr) { + // The order index is on the hot path: every new/cancel/modify/fill does 1-4 point lookups on + // it. Capping the load factor at 0.25 (vs the default 1.0) keeps probe chains short, which + // measurably speeds the whole engine on a busy book — a measured ~+18% on the steady-state + // profile workload, trading a modest amount of memory (more empty buckets) for fewer + // collisions. This only changes bucket count, never iteration-for-output: index_ is used solely + // for find/insert/erase/size, while snapshots and resting_orders() iterate the ordered + // bids_/asks_ maps, so determinism is unaffected. + index_.max_load_factor(0.25F); +} OrderBook::~OrderBook() = default;