From a17f6ead70eb79af0fee0c9fbc78e62536d217f1 Mon Sep 17 00:00:00 2001 From: Stephan Dollberg Date: Mon, 22 Jun 2026 15:40:11 +0100 Subject: [PATCH 1/2] delta_for: cache end iterator in search loops Avoid rebuilding the default end iterator on every scanned element. end() didn't get optimized out and it's not entirely free in this iterator's case. Hoise it out manually. Possibly this addresses some noise we are seeing. --- src/v/utils/delta_for.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/v/utils/delta_for.h b/src/v/utils/delta_for.h index ca77499ce2dfa..8382a74da8ba5 100644 --- a/src/v/utils/delta_for.h +++ b/src/v/utils/delta_for.h @@ -1006,12 +1006,13 @@ class deltafor_frame template const_iterator pred_search(value_t value) const { PredT pred; - for (auto it = begin(); it != end(); ++it) { + auto end_it = end(); + for (auto it = begin(); it != end_it; ++it) { if (pred(*it, value)) { return it; } } - return end(); + return end_it; } std::array _head{}; @@ -1509,12 +1510,13 @@ class deltafor_column /// Find first value that matches the predicate const_iterator pred_search( value_t value, std::regular_invocable auto pred) const { - for (auto it = this->begin(); it != this->end(); ++it) { + auto end_it = this->end(); + for (auto it = this->begin(); it != end_it; ++it) { if (pred(*it, value)) { return it; } } - return this->end(); + return end_it; } }; @@ -1556,14 +1558,15 @@ class deltafor_column, max_frame_size> } index += it->size(); } + auto end_it = this->end(); if (it != this->_frames.end()) { auto start = const_iterator(it, this->_frames.end(), 0, index); - for (; start != this->end(); ++start) { + for (; start != end_it; ++start) { if (pred(*start, value)) { return start; } } } - return this->end(); + return end_it; } }; From 4bac9f76af5a5a896778fb068bbfff84919193a6 Mon Sep 17 00:00:00 2001 From: Stephan Dollberg Date: Mon, 22 Jun 2026 15:40:12 +0100 Subject: [PATCH 2/2] delta_for: batch find microbench iterations Amortize start/stop timer overhead for fast find benchmarks. --- src/v/utils/tests/delta_for_bench.cc | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/v/utils/tests/delta_for_bench.cc b/src/v/utils/tests/delta_for_bench.cc index 3672fc94afdf0..7d724a63ef7d5 100644 --- a/src/v/utils/tests/delta_for_bench.cc +++ b/src/v/utils/tests/delta_for_bench.cc @@ -132,11 +132,16 @@ void append_tx_test(StoreT& store, int test_scale) { } template -void find_test(StoreT& store) { +size_t find_test(StoreT& store) { + constexpr size_t batch = 10; + auto target = *store.last_value(); perf_tests::start_measuring_time(); - auto it = store.find(*store.last_value()); - perf_tests::do_not_optimize(it); + for (size_t i = 0; i < batch; i++) { + auto it = store.find(target); + perf_tests::do_not_optimize(it); + } perf_tests::stop_measuring_time(); + return batch; } template @@ -173,9 +178,11 @@ PERF_TEST(deltafor_bench, xor_column_append_tx2) { append_tx_test(column, 4097); } -PERF_TEST(deltafor_bench, xor_frame_find_4K) { find_test(xor_frame_4K); } +PERF_TEST(deltafor_bench, xor_frame_find_4K) { return find_test(xor_frame_4K); } -PERF_TEST(deltafor_bench, xor_column_find_4K) { find_test(xor_column_4K); } +PERF_TEST(deltafor_bench, xor_column_find_4K) { + return find_test(xor_column_4K); +} PERF_TEST(deltafor_bench, xor_frame_at_4K) { at_test(xor_frame_4K); } @@ -209,9 +216,13 @@ PERF_TEST(deltafor_bench, delta_column_append_tx2) { append_tx_test(column, 4097); } -PERF_TEST(deltafor_bench, delta_frame_find_4K) { find_test(delta_frame_4K); } +PERF_TEST(deltafor_bench, delta_frame_find_4K) { + return find_test(delta_frame_4K); +} -PERF_TEST(deltafor_bench, delta_column_find_4K) { find_test(delta_column_4K); } +PERF_TEST(deltafor_bench, delta_column_find_4K) { + return find_test(delta_column_4K); +} PERF_TEST(deltafor_bench, delta_column_find_4M) { at_test(delta_column_4M); }