Optimize StrictMetricsEvaluator reference binding and add benchmarks - #823
Optimize StrictMetricsEvaluator reference binding and add benchmarks#823SURYAS1306 wants to merge 2 commits into
Conversation
Reuse dynamic_cast results in predicate handlers to avoid redundant shared_ptr refcount bumps, and add an optional Google Benchmark target behind ICEBERG_BUILD_BENCHMARKS for the filtering hot path (issue apache#690). Co-authored-by: Cursor <cursoragent@cursor.com>
Apply clang-format and cmake-format, move benchmarks under src/iceberg/benchmark, and enable ICEBERG_BUILD_BENCHMARKS in the cpp-linter workflow so Google Benchmark headers are available. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Pull request overview
This PR optimizes StrictMetricsEvaluator’s predicate reference binding by reusing the dynamic_cast result (avoiding repeated shared_from_this() refcount bumps), and adds an off-by-default benchmark build option plus an initial Google Benchmark target to measure the filtering hot path.
Changes:
- Replace the
RETURN_IF_NOT_REFERENCEpattern withBIND_REFERENCE_OR_RETURNso each predicate handler reuses the already-castedBoundReference*. - Add
ICEBERG_BUILD_BENCHMARKSCMake option and asrc/iceberg/benchmark/subdirectory that fetches Google Benchmark and buildsstrict_metrics_evaluator_bench. - Enable
ICEBERG_BUILD_BENCHMARKS=ONin thecpp-linterworkflow build step to ensure the benchmark target stays buildable in CI.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/iceberg/expression/strict_metrics_evaluator.cc |
Hot-path optimization: reuse dynamic_cast result instead of calling reference() repeatedly. |
CMakeLists.txt |
Add ICEBERG_BUILD_BENCHMARKS option (default OFF). |
src/iceberg/CMakeLists.txt |
Wire benchmark subdir behind ICEBERG_BUILD_BENCHMARKS. |
src/iceberg/benchmark/CMakeLists.txt |
Fetch Google Benchmark and define the benchmark executable target. |
src/iceberg/benchmark/strict_metrics_evaluator_bench.cc |
Add initial micro-benchmark for StrictMetricsEvaluator::Evaluate. |
.github/workflows/cpp-linter.yml |
Turn on benchmarks during CI build to catch build regressions. |
| BENCHMARK(iceberg::BM_StrictMetricsEvaluate)->Arg(1)->Arg(14)->Arg(20); | ||
| BENCHMARK_MAIN(); |
| std::shared_ptr<Expression> MakeFilter(int predicate_count) { | ||
| std::vector<std::shared_ptr<Expression>> predicates; |
|
This pull request has been marked as stale due to 30 days of inactivity. It will be closed in 1 week if no further activity occurs. If you think that’s incorrect or this pull request requires a review, please simply write any comment. If closed, you can revive the PR at any time and @mention a reviewer or discuss it on the dev@iceberg.apache.org list. Thank you for your contributions. |
Summary
This PR implements the filtering hot-path optimization and benchmark infrastructure proposed in #690.
RETURN_IF_NOT_REFERENCEwithBIND_REFERENCE_OR_RETURNinStrictMetricsEvaluatorso predicate handlers reuse thedynamic_castresult instead of callingexpr->reference()(which bumpsshared_ptrrefcounts viashared_from_this()).ICEBERG_BUILD_BENCHMARKSCMake option that fetches Google Benchmark (v1.9.1) and buildsstrict_metrics_evaluator_bench.Motivation
StrictMetricsEvaluatorruns once per data file during scan planning. The previous macro discarded a successfuldynamic_castand then re-fetched the same reference through a virtual call + atomic refcount operation on every predicate handler (14+ predicate types).Benchmark results (Release, Apple Clang 17, macOS)
Micro-benchmark model of the predicate binding hot path:
End-to-end
StrictMetricsEvaluator::Evaluatebenchmark (with binding + evaluation):Test plan
expression_test --gtest_filter='StrictMetrics*'(42 tests pass)-DICEBERG_BUILD_BENCHMARKS=ON./benchmark/strict_metrics_evaluator_benchCloses #690