From 3c8d82aa8613ae68ae98c352230900ff0f553a50 Mon Sep 17 00:00:00 2001
From: E Sequeira <5458743+geseq@users.noreply.github.com>
Date: Mon, 22 Jun 2026 13:14:04 +0000
Subject: [PATCH 1/3] perf: erase price-level rbtree node in O(1) via
iterator_to
remove() erased by key (price()), re-searching for a node already in
hand. Erase via iterator_to(*q) instead (O(1) amortized), avoiding a
redundant tree search on the cancel/fill path.
append() is left on its original find()+insert_equal() body: a
single-walk lower_bound()+hinted insert added a per-append Decimal
equality compare on the common append-to-existing-level path,
regressing the static workload.
---
src/pricelevel.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pricelevel.cpp b/src/pricelevel.cpp
index 60e9701..0babbfe 100644
--- a/src/pricelevel.cpp
+++ b/src/pricelevel.cpp
@@ -52,7 +52,7 @@ void PriceLevel
::remove(Order* order) {
}
if (q->len() == 0) {
- price_tree_.erase(q->price());
+ price_tree_.erase(price_tree_.iterator_to(*q));
--depth_;
queue_pool_.release(&*q);
}
From 1bd64b691d1df9f0717693588a9a96ca45370036 Mon Sep 17 00:00:00 2001
From: E Sequeira <5458743+geseq@users.noreply.github.com>
Date: Sat, 27 Jun 2026 08:17:11 +0000
Subject: [PATCH 2/3] perf: Lever A via function_ref (keeps callback bodies in
.cpp)
Alternative to the template approach: replace std::function callbacks with
a non-owning function_ref (void* + static thunk, two pointers,
no alloc). Methods stay non-template and their bodies remain in the .cpp;
explicit instantiations unchanged. Removes per-order std::function
construction but keeps an indirect call on dispatch (no inlining).
Experiment branch for A/B vs the template variant.
Co-Authored-By: Claude Opus 4.8
Claude-Session: https://claude.ai/code/session_0196EKKWudtsg3gButufhDxz
---
include/function_ref.hpp | 31 +++++++++++++++++++++++++++++++
include/orderqueue.hpp | 6 +++---
test/orderqueue_test.cpp | 16 ++++++++--------
3 files changed, 42 insertions(+), 11 deletions(-)
create mode 100644 include/function_ref.hpp
diff --git a/include/function_ref.hpp b/include/function_ref.hpp
new file mode 100644
index 0000000..1977661
--- /dev/null
+++ b/include/function_ref.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include
+#include
+
+namespace orderbook {
+
+// Non-owning view over any callable, modeled after std::function_ref (P0792).
+// Stores a type-erased object pointer plus a thunk; trivially copyable, two
+// pointers wide, performs no allocation. The referenced callable must outlive
+// every invocation through the function_ref.
+template
+class function_ref;
+
+template
+class function_ref {
+ void* obj_ = nullptr;
+ R (*thunk_)(void*, Args...) = nullptr;
+
+ public:
+ template , function_ref>>>
+ function_ref(F&& f) noexcept
+ : obj_(const_cast(static_cast(std::addressof(f)))),
+ thunk_([](void* obj, Args... args) -> R {
+ return (*static_cast*>(obj))(std::forward(args)...);
+ }) {}
+
+ R operator()(Args... args) const { return thunk_(obj_, std::forward(args)...); }
+};
+
+} // namespace orderbook
diff --git a/include/orderqueue.hpp b/include/orderqueue.hpp
index 20cf7a0..780fc02 100644
--- a/include/orderqueue.hpp
+++ b/include/orderqueue.hpp
@@ -1,17 +1,17 @@
#pragma once
#include
-#include
#include "boost/intrusive/list.hpp"
#include "boost/intrusive/set_hook.hpp"
+#include "function_ref.hpp"
#include "order.hpp"
namespace orderbook {
using TradeNotification =
- std::function;
-using PostOrderFill = std::function;
+ function_ref;
+using PostOrderFill = function_ref;
using OrderList = boost::intrusive::list;
diff --git a/test/orderqueue_test.cpp b/test/orderqueue_test.cpp
index eb822c1..1f8336c 100644
--- a/test/orderqueue_test.cpp
+++ b/test/orderqueue_test.cpp
@@ -54,9 +54,9 @@ TEST_F(OrderQueueTest, TestOrderQueue_ProcessUpdatesTotalQtyOnFullFill) {
oq->append(&o1);
oq->append(&o2);
- const TradeNotification tn = [](OrderID makerOrderID, OrderID takerOrderID, OrderStatus makerOrderStatus, OrderStatus takerOrderStatus, Decimal matchedQty,
+ const auto tn = [](OrderID makerOrderID, OrderID takerOrderID, OrderStatus makerOrderStatus, OrderStatus takerOrderStatus, Decimal matchedQty,
Decimal matchedPrice) {};
- const PostOrderFill pf = [&oq, &o1, &o2](OrderID id) {
+ const auto pf = [&oq, &o1, &o2](OrderID id) {
if (id == 1) {
oq->remove(&o1);
} else if (id == 2) {
@@ -84,9 +84,9 @@ TEST_F(OrderQueueTest, TestOrderQueue_ProcessUpdatesTotalQtyOnExactFill) {
oq->append(&o1);
oq->append(&o2);
- const TradeNotification tn = [](OrderID makerOrderID, OrderID takerOrderID, OrderStatus makerOrderStatus, OrderStatus takerOrderStatus, Decimal matchedQty,
+ const auto tn = [](OrderID makerOrderID, OrderID takerOrderID, OrderStatus makerOrderStatus, OrderStatus takerOrderStatus, Decimal matchedQty,
Decimal matchedPrice) {};
- const PostOrderFill pf = [&oq, &o1, &o2](OrderID id) {
+ const auto pf = [&oq, &o1, &o2](OrderID id) {
if (id == 1) {
oq->remove(&o1);
} else if (id == 2) {
@@ -112,9 +112,9 @@ TEST_F(OrderQueueTest, TestOrderQueue_ProcessZeroesFilledOrderBeforePostFill) {
oq->append(&o2);
bool sawZeroQtyOnPostFill = false;
- const TradeNotification tn = [](OrderID makerOrderID, OrderID takerOrderID, OrderStatus makerOrderStatus, OrderStatus takerOrderStatus, Decimal matchedQty,
+ const auto tn = [](OrderID makerOrderID, OrderID takerOrderID, OrderStatus makerOrderStatus, OrderStatus takerOrderStatus, Decimal matchedQty,
Decimal matchedPrice) {};
- const PostOrderFill pf = [&oq, &o1, &o2, &sawZeroQtyOnPostFill](OrderID id) {
+ const auto pf = [&oq, &o1, &o2, &sawZeroQtyOnPostFill](OrderID id) {
if (id == 1) {
sawZeroQtyOnPostFill = (o1.qty == Decimal(0, 0));
oq->remove(&o1);
@@ -146,12 +146,12 @@ TEST_F(OrderQueueTest, TestOrderQueue_ProcessUsesSnapshotForTradeNotificationAft
OrderID makerOrderID = 0;
Decimal matchedPrice(0, 0);
- const TradeNotification tn = [&makerOrderID, &matchedPrice](OrderID makerID, OrderID takerOrderID, OrderStatus makerOrderStatus,
+ const auto tn = [&makerOrderID, &matchedPrice](OrderID makerID, OrderID takerOrderID, OrderStatus makerOrderStatus,
OrderStatus takerOrderStatus, Decimal matchedQty, Decimal priceValue) {
makerOrderID = makerID;
matchedPrice = priceValue;
};
- const PostOrderFill pf = [&oq, &o1](OrderID id) {
+ const auto pf = [&oq, &o1](OrderID id) {
if (id == 1) {
oq->remove(&o1);
o1.id = 999;
From 9e9ad2dc3cd9b6ef88d24d0257f7528366cce1fe Mon Sep 17 00:00:00 2001
From: E Sequeira <5458743+geseq@users.noreply.github.com>
Date: Sat, 27 Jun 2026 12:08:32 +0000
Subject: [PATCH 3/3] build: enable LTO for Release builds and the benchmark
adapter
Turn on interprocedural optimization (-flto) for optimized builds of the
orderbook library/main and the matching-engine benchmark adapter .so.
Gated to Release-type builds via check_ipo_supported; sanitizer and Debug
builds are unaffected. Enables cross-TU inlining of the matching chain.
Measured (12-round interleaved A/B, cores 2/4): add/cancel throughput
+42-44%; matching scenarios flat-to-positive; correctness unchanged
(all harness scenarios PASS).
Co-Authored-By: Claude Opus 4.8
Claude-Session: https://claude.ai/code/session_0196EKKWudtsg3gButufhDxz
---
CMakeLists.txt | 15 +++++++++++++++
bench/build.sh | 12 +++++++++++-
2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 665cff8..36b9047 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -62,3 +62,18 @@ if (ENABLE_TESTING)
endif()
target_link_libraries(main PRIVATE ${CPP_ORDERBOOK} Boost::intrusive decimal pool)
+
+# --- Link-time optimization (LTO/IPO) for optimized builds only. ------------
+# Enabled only for Release-type configs and only when the toolchain supports
+# it. Debug builds and the sanitizer builds (ASan/UBSan/TSan) are left
+# untouched on purpose: LTO is slow under sanitizers and can misbehave. Note
+# the sanitizer CI builds the engine via bench/build.sh, not this CMake, so it
+# never reaches here; the gate below additionally keeps a Debug configure clean.
+include(CheckIPOSupported)
+check_ipo_supported(RESULT _ipo_ok OUTPUT _ipo_msg LANGUAGES CXX)
+if (_ipo_ok AND CMAKE_BUILD_TYPE MATCHES "^(Release|RelWithDebInfo|MinSizeRel)$")
+ set_property(TARGET ${CPP_ORDERBOOK} main PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
+ message(STATUS "LTO/IPO enabled for ${CMAKE_BUILD_TYPE} build")
+elseif (NOT _ipo_ok)
+ message(STATUS "LTO/IPO not supported by toolchain, continuing without it: ${_ipo_msg}")
+endif()
diff --git a/bench/build.sh b/bench/build.sh
index 607a6b8..7cca1be 100755
--- a/bench/build.sh
+++ b/bench/build.sh
@@ -98,9 +98,19 @@ for p in "$DECIMAL_INC" "$POOL_INC"; do
fi
done
+# --- Link-time optimization. This adapter is a perf/Release artifact, so it
+# gets -flto for cross-TU inlining of the matching chain. The single g++ call
+# below both compiles and links, so one -flto covers both phases. We DROP -flto
+# when ME_EXTRA_CXXFLAGS asks for a sanitizer build (ASan/UBSan/TSan), where LTO
+# is slow and can misbehave with the instrumentation.
+LTO_FLAG="-flto"
+case "${ME_EXTRA_CXXFLAGS:-}" in
+ *sanitize*) LTO_FLAG="" ;;
+esac
+
# --- Compile the adapter + engine TUs into the .so. -------------------------
OUT="$DIR/cpp_orderbook_adapter.so"
-g++ -std=c++20 -O3 -march=native -fPIC -shared \
+g++ -std=c++20 -O3 -march=native $LTO_FLAG -fPIC -shared \
-I"$BENCH/api" \
-I"$ENGINE/include" \
-I"$ENGINE/src" \