Skip to content

Benchmarks refactoring#48

Merged
Malkovsky merged 9 commits into
mainfrom
feature/benchmarks_in_docs
May 21, 2026
Merged

Benchmarks refactoring#48
Malkovsky merged 9 commits into
mainfrom
feature/benchmarks_in_docs

Conversation

@Malkovsky

Copy link
Copy Markdown
Owner
  • Added optional benchmark page in docs
  • Refactored Rmm, added sdsl backend

@Malkovsky Malkovsky requested a review from Sanya239 May 18, 2026 22:32
@codecov

codecov Bot commented May 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.97826% with 35 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.19%. Comparing base (d60a5cb) to head (57b50ff).

Files with missing lines Patch % Lines
src/tests/test_rmm.cpp 69.82% 35 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #48      +/-   ##
==========================================
- Coverage   87.98%   87.19%   -0.79%     
==========================================
  Files          13       14       +1     
  Lines        3378     3257     -121     
  Branches      603      607       +4     
==========================================
- Hits         2972     2840     -132     
- Misses        264      285      +21     
+ Partials      142      132      -10     
Flag Coverage Δ
gcov 87.19% <80.97%> (-0.79%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3426c627f4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread include/pixie/rmm_tree.h Outdated
Comment on lines +130 to +137
explicit RmMTree(const std::vector<std::uint64_t>& words,
size_t bit_count,
const size_t& leaf_block_bits /*0=auto*/ = 0,
const float& max_overhead /*<0=off*/ = -1.0) {
build_from_words(words, bit_count, leaf_block_bits, max_overhead);
const float& max_overhead /*<0=off*/ = -1.0)
: RmMTree(std::span<const std::uint64_t>(words),
bit_count,
leaf_block_bits,
max_overhead) {}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject vector temporaries before storing a span

When callers construct from a temporary vector, e.g. RmMTree(std::vector<uint64_t>{...}, n) or RmMTree(pack_words(bits), bits.size()), this overload binds the temporary to const& and then stores only a std::span into it. The vector is destroyed at the end of the full expression, so the first query reads freed memory; I reproduced this with ASan as a heap-use-after-free in rank1_in_block. This is a regression from the previous owning vector constructor and is easy to hit with helper functions that return packed words, so the rvalue overload should be deleted or this overload should keep ownership.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d82c54d044

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (end_position >= size_) {
return zeros_;
}
return tree_.preceding_closing_parentheses(end_position);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Count prefix zeros instead of the last zero run

When the SDSL backend is used for rank0 on prefixes that are not the full vector, this calls bp_support_sada::preceding_closing_parentheses(end_position), which in SDSL v3.0.3 is documented for zeros preceding a position and implements i - select(rank(i)) - 1, i.e. only the consecutive closing parentheses since the previous opening. For a prefix like 101 (end_position == 3), the expected rank0 is 1 but this returns 0, so bench_rmm_sdsl --ops=rank0 reports timings for incorrect queries/results; use end_position - rank1_impl(end_position) (or a real zero-rank support) instead.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 65ba810ed0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread include/pixie/rmm_tree_sdsl.h Outdated
Comment on lines +31 to +36
for (std::size_t i = 0; i < words.size(); ++i) {
std::uint64_t word = words[i];
if (i + 1 == words.size() && (bit_count & 63) != 0) {
word &= (std::uint64_t{1} << (bit_count & 63)) - 1;
}
ones_ += std::popcount(word);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Ignore words beyond bit_count

When SdslRmMTree is constructed with a span larger than ceil(bit_count/64) (for example a reused word buffer with extra capacity or padding words), this loop counts all words in the span and only masks the final span word. The actual bits_ vector is built from only size_ bits, so ones_ can exceed size_, zeros_ = size_ - ones_ underflows, and calls such as rank0(size_) or out-of-range select1 return corrupt results. Limit the count to the valid word count and mask the word containing bit_count.

Useful? React with 👍 / 👎.

Comment thread include/pixie/rmm_base.h
public:
static constexpr std::size_t npos = std::numeric_limits<std::size_t>::max();

std::size_t size() const { return impl().size_impl(); }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we call some "size_impl()" instead of size() itself?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't calling size() result in infinite recursion and immediate stack overflow on call?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored, implementation classes now have impelmentations inside _impl methods

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't calling size() result in infinite recursion and immediate stack overflow on call?

That does not happen for some reason. I tested it and everything worked well. However, both the old solution and the one of mine had to do something with vTables and it is great that you have eliminated this kind of behaviour. Current code does not use any vTables as I see

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think vtables are not the issue here, no method was marked virtual and derived didn't override these method. But if at some point we have a virtual method in base and override it in derived, this double recursion base::method -> derived::method_impl -> derived::method would lead to infinite recursion

Comment thread include/pixie/rmm_base.h
std::size_t size() const { return impl().size_impl(); }

std::size_t rank1(std::size_t end_position) const {
return impl().rank1_impl(end_position);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question about _impl here

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c8cb3e1c07

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread include/pixie/rmm_tree_sdsl.h Outdated
}
const std::size_t close_position_zero_based =
close_position_one_based > 0 ? close_position_one_based - 1 : 0;
return tree_.find_open(close_position_zero_based);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Convert SDSL open/enclose results back to one-based

open_impl converts the incoming close position from one-based to zero-based, but then returns find_open's zero-based answer directly; enclose_impl does the same with tree_.enclose. The rest of this interface (and RmMTree) uses one-based results for these operations, so every successful open/enclose result is shifted by -1 (e.g., open(2) on "10" yields 0 instead of 1), which corrupts BP navigation when swapping to this backend.

Useful? React with 👍 / 👎.


std::size_t close_impl(std::size_t open_position) const {
if (size_ == 0) {
return 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Return npos instead of 0 for empty close/open/enclose

These query methods return 0 when size_ == 0, but this type defines npos as the not-found sentinel and 0 is also a valid position in non-empty trees. Returning 0 on failure makes callers misinterpret empty/invalid queries as successful matches at the first bit, which breaks correctness checks that rely on npos.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3824a8dfa9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +32 to +33
for (std::size_t i = 0; i < valid_words; ++i) {
std::uint64_t word = words[i];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Validate span length before reading SDSL input words

This constructor indexes words[i] up to ceil(bit_count/64) without checking that the span is that long, so callers that pass a shorter buffer (e.g., reused metadata with stale bit_count) trigger out-of-bounds reads during construction and can crash or compute corrupted counts. RmMTree now explicitly rejects this case, so this backend should add the same guard before the loop.

Useful? React with 👍 / 👎.

Comment on lines +734 to +737
const std::size_t close_position =
pool.close_positions_zero_based
[sample_index % pool.close_positions_zero_based.size()];
return dataset.tree.open(close_position);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use correct index convention for open/enclose benchmarks

The benchmark now feeds zero-based close positions into tree.open(...), but RmMTree::open_impl/enclose_impl still use the older one-based convention (they reject 0 and add +1 on return), so these measurements exercise shifted/invalid queries rather than the intended operation. That skews benchmark results and makes comparisons against previous runs or other backends unreliable.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 57b50ff44d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/tests/test_rmm.cpp
TEST(RmMSdslEdgeCases, IgnoresWordsBeyondBitCount) {
std::vector<std::uint64_t> words = {
0b101ull, std::numeric_limits<std::uint64_t>::max()};
pixie::SdslRmMTree rm(std::span<const std::uint64_t>(words),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Include SDSL tree header before SdslRmMTree tests

When PIXIE_THIRD_PARTY_BACKENDS is enabled, SDSL_SUPPORT turns on this test block, but test_rmm.cpp never includes <pixie/rmm_tree_sdsl.h>. pixie/rmm_tree.h does not declare pixie::SdslRmMTree, so this line causes test_rmm to fail to compile in third-party-backend builds with an unknown type error.

Useful? React with 👍 / 👎.

if (size_ == 0) {
return 0;
}
return tree_.rmq(range_begin, range_end);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate RMQ bounds before calling SDSL support

This implementation calls tree_.rmq(range_begin, range_end) without checking range_begin <= range_end and range_end < size_. The main RmMTree backend guards these cases and returns sentinels, but here invalid ranges are forwarded directly into SDSL preconditioned APIs, which can return corrupt results or assert/crash instead of returning npos for out-of-domain queries.

Useful? React with 👍 / 👎.

@Malkovsky Malkovsky merged commit 55e4219 into main May 21, 2026
4 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants