Repository navigation
[Backport 0.18] perf(hgraph): reduce visited list memory - #2451
Conversation
|
/label status/waiting-for-review |
There was a problem hiding this comment.
Code Review
This pull request refactors the VisitedList class to use a bitwise representation with WordType and TagType, which significantly optimizes memory usage. It also introduces comprehensive unit tests covering word boundaries, memory usage, tag overflow, and randomized differential testing. The reviewer's feedback suggests replacing the alternative operator and with the standard logical operator && in visited_list.h to align with standard C++ coding practices.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
|
/retest |
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## 0.18 #2451 +/- ##
==========================================
- Coverage 91.40% 91.38% -0.03%
==========================================
Files 335 335
Lines 20112 20127 +15
==========================================
+ Hits 18384 18393 +9
- Misses 1728 1734 +6
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
LHT129
left a comment
There was a problem hiding this comment.
Code review summary for PR #2451 (backport of #2449 to 0.18 branch):
Overview: This PR replaces the per-node uint16_t visitation array with a generation-stamped bitmap approach using uint64_t words + uint16_t tags per word. This significantly reduces memory usage for the visited list (from 2 * max_size bytes to 10 * word_count bytes, where word_count = ceil(max_size / 64)).
Files changed: visited_list.h, visited_list.cpp, visited_list_test.cpp (+148 / -18)
Review findings:
-
Correctness: The generation-stamped bitmap logic in
Set()andGet()is correct. The tag-overflow path inReset()properly clears tags and resetstag_to 1. The zero-capacity early-return path in the constructor correctly avoids allocation and the destructor guards against nullwords_. -
Memory safety: The single-buffer allocation (
words_bytes + tags_bytes) and the split intowords_/tags_pointers is sound. Thetags_offset (word_count_ * 8) is naturally 8-byte aligned, souint16_taccesses have no alignment issues. -
Test coverage: Comprehensive tests cover word boundaries (0, 1, 63, 64, 65, size-1), repeated sets, tag overflow (full
uint16_trange), zero-size edge case (verifies no allocation), memory usage calculation, and a randomized differential test against avector<bool>reference across multiple sizes and 20k operations per size. -
Performance: The
Prefetch()method correctly prefetchestags_(the first memory access inGet()). The bitmap approach reduces memory footprint and improves cache locality for large visited lists.
Conclusion: No blocking issues found. The backport is clean and the test coverage is thorough. The existing inline comment about and vs && is a minor style preference that does not affect correctness.
|
/retest |
LHT129
left a comment
There was a problem hiding this comment.
Thanks for this backport to the 0.18 branch. The change from per-element uint16_t to generation-stamped bitmap words is a clean memory optimization.
I have reviewed the three changed files (visited_list.h, visited_list.cpp, visited_list_test.cpp) and the implementation looks correct:
- Bitmap logic: The
Set/Getmethods correctly handle word boundaries, bit masking, and the lazy tag-reset semantics. - Zero-capacity handling: The constructor correctly short-circuits when
word_count_ == 0, and the destructor/Resetguard against null pointers. - Tag overflow: The
Resetmethod properly wraps around and clears all tags when the generation counter overflows. - Test coverage: The new tests cover word boundaries, repeated sets, memory usage calculation, tag overflow, zero-size construction, and randomized differential testing against a
vector<bool>reference — thorough coverage.
Two existing inline comments have been raised by other reviewers that are worth addressing:
- The use of
andinstead of&&inGet()(style consistency) - The
words_array not being explicitly zero-initialized in the constructor (defensive coding)
Otherwise, this backport looks clean and faithful to the original #2449. No additional issues found.
LHT129
left a comment
There was a problem hiding this comment.
Thank you for this backport. The changes look good overall — the bitmap-based visited list is a clean optimization that significantly reduces scratch memory while preserving the lazy reset semantics.
I have reviewed the three changed files and the existing inline comments from other reviewers already cover the points worth addressing:
words_initialization in the constructor (by @LHT129)Get()should be markedconst(by @LHT129)Prefetch()should also prefetchwords_(by @LHT129)- Use
&&instead ofand(by gemini-code-assist)
The test coverage is thorough — the randomized differential test against a std::vector<bool> reference is a strong validation approach. The zero-size and tag-overflow edge cases are also well covered.
No additional blocking issues from my side. Please address the existing suggestions at your discretion.
LHT129
left a comment
There was a problem hiding this comment.
Overall this backport looks clean and well-tested. The existing inline comments from other reviewers have already covered the actionable items (uninitialized words_ array, and vs &&, Get const-correctness, and Prefetch coverage). No additional issues found from my review.
LHT129
left a comment
There was a problem hiding this comment.
This is a clean backport of #2449 to the 0.18 branch. The changes are well-contained and the test coverage is thorough (word boundaries, tag overflow, zero-size, randomized differential testing).
The existing inline comments from LHT129 cover the remaining suggestions (words_ initialization, Get() const-correctness, Prefetch coverage for words_). No additional issues found.
LGTM once the existing suggestions are addressed.
LHT129
left a comment
There was a problem hiding this comment.
This backport of #2449 to the 0.18 branch is clean and well-tested. The generation-stamped bitmap approach correctly reduces visited-list scratch memory while preserving lazy reset semantics.
I have reviewed all three changed files (visited_list.h, visited_list.cpp, visited_list_test.cpp) and the implementation is sound:
- Bitmap logic:
Set/Getcorrectly handle word boundaries, bit masking, and lazy tag-reset. - Zero-capacity handling: Constructor short-circuits when
word_count_ == 0, and the destructor/Resetguard against null pointers. - Tag overflow:
Resetproperly wraps around and clears all tags when the generation counter overflows. - Test coverage: Thorough — word boundaries, repeated sets, memory usage, tag overflow, zero-size construction, and a randomized differential test against
std::vector<bool>.
The existing inline comments from LHT129 already cover the remaining suggestions worth addressing:
words_initialization in the constructor (defensive coding)Get()should be markedconstPrefetch()should also prefetchwords_Allocate()return value null checkword_count_ == 0guard inSet/Get
No additional issues found. LGTM once the existing suggestions are addressed.
LHT129
left a comment
There was a problem hiding this comment.
Review Summary
This is a clean backport of #2449 to the 0.18 branch. The core change replaces the per-node uint16_t visitation array with a generation-stamped bitmap approach using uint64_t words, which significantly reduces memory usage for large graphs.
What was checked
- Correctness: The bitmap logic (word_id, mask, tag-stamped lazy reset) is correct. The tag overflow handling properly resets to 1 (not 0) to avoid false matches against zero-initialized tags.
- Backport fidelity: Correctly retains the
0.18branch differences —int64_treturn type forGetMemoryUsage()and the Catch2 test framework include. - Test coverage: Comprehensive — covers word boundaries, repeated sets, tag overflow, zero-size edge case, and randomized differential testing against a
std::vector<bool>reference. - Memory safety: The destructor correctly guards against null
words_before deallocation.
Existing inline comments
Several issues have already been flagged by other reviewers that should be addressed before merging:
words_array is not zero-initialized after allocation (technically safe due to tag-stamped access pattern, but UB if access pattern changes)- Missing null check on
allocator_->Allocate()return value Get()should be markedconstPrefetch()should also prefetchwords_alongsidetags_Set()/Get()on zero-capacity lists would dereference null pointers- Use
&&instead ofandkeyword
No additional blocking issues found beyond those already raised.
LHT129
left a comment
There was a problem hiding this comment.
Review Summary
I have reviewed this backport of #2449 to the 0.18 branch. The three changed files (visited_list.h, visited_list.cpp, visited_list_test.cpp) have been thoroughly examined.
What was checked
- Correctness: The generation-stamped bitmap logic in
Set()/Get()is correct. Word boundaries, bit masking, and lazy tag-reset semantics are properly implemented. - Backport fidelity: Correctly retains
0.18branch specifics —int64_treturn type forGetMemoryUsage(), Catch2 test framework, and existing include structure. - Test coverage: Comprehensive — word boundaries (0, 1, 63, 64, 65, size-1), repeated sets, memory usage calculation, tag overflow (full
uint16_trange), zero-size edge case, and randomized differential testing againststd::vector<bool>across multiple sizes with 20k operations each. - Memory safety: Destructor guards against null
words_before deallocation. Zero-capacity constructor short-circuits correctly.
Existing inline comments
All actionable issues have already been raised by other reviewers:
- Use
&&instead ofandkeyword inGet()(gemini-code-assist) words_array not zero-initialized in constructor (LHT129)Get()should be markedconst(LHT129)Prefetch()should also prefetchwords_(LHT129)- Missing null check on
Allocate()return value (LHT129) word_count_ == 0guard inSet()/Get()(LHT129)
Conclusion
No additional issues found beyond those already raised. The backport is clean and faithful to the original #2449. Please address the existing suggestions at your discretion.
LHT129
left a comment
There was a problem hiding this comment.
I have completed a review of this backport PR. The core change — replacing the per-node visitation generation array with generation-stamped bitmap words — is correctly implemented and well-tested.
What this PR does well:
- The bitmap word approach significantly reduces memory usage (from
2 * max_sizebytes toceil(max_size/64) * 10bytes). - The lazy reset semantics are correctly preserved via the tag-stamped word design.
- The test coverage is thorough: word boundaries (0, 1, 63, 64, 65), repeated sets, tag overflow/wraparound, zero-capacity edge case, memory usage verification, and a randomized differential test against a
std::vector<bool>reference. - The
CountingAllocatorin the zero-size test correctly verifies that no allocation occurs whenmax_size == 0.
Existing inline comments from other reviewers have already covered the notable findings:
andvs&&operator style inGet()(visited_list.h:54)words_array left uninitialized in the constructor (visited_list.cpp:24)Get()should be markedconst(visited_list.h:53)Prefetch()should also prefetchwords_(visited_list.h:60)- Missing null check on
Allocate()return value (visited_list.cpp:26) - Zero-capacity edge case with potential null dereference in
Set/Get(visited_list.h:40)
I did not find additional substantive issues beyond those already flagged. The backport is clean and the implementation matches the intent described in the PR summary.
LHT129
left a comment
There was a problem hiding this comment.
This is a clean backport of #2449 to the 0.18 branch. The changes are well-contained to visited_list.{h,cpp} and the test file.
The existing inline reviews from LHT129 and gemini-code-assist have already covered the key points:
and→&&operator style (gemini-code-assist)words_array left uninitialized in constructor (LHT129)Get()should be markedconst(LHT129)Prefetchshould also prefetchwords_for cache efficiency (LHT129)- Null check on
Allocate()return value (LHT129) Set/Getnull dereference whenword_count_ == 0(LHT129)
The test coverage is comprehensive — word boundaries, tag overflow, zero-capacity, memory usage, and randomized differential testing against a reference implementation. No additional issues found.
The visited list kept its full span allocated and mishandled a zero-capacity pool, which either wasted memory or produced an invalid view. Shrink the backing span and make the zero-capacity case explicit, with differential coverage against the previous behaviour. Signed-off-by: jc543239 <jc543239@antgroup.com> Signed-off-by: jac0626 <jac0626@users.noreply.github.com> Signed-off-by: LHT129 <lht129@users.noreply.github.com> Assisted-by: Codex:GPT-5
4aa5268 to
26b88d0
Compare
Summary
Backports #2449 to the
0.18branch.0.18branch's existing Catch2 include andGetMemoryUsage()return typeValidation
make fmtwith clang-format 15git diff --checksrc/utils/visited_list.cppandsrc/utils/visited_list_test.cppwith the CMake-generated compilation commandsmake test CASE='[ut][VisitedList]'was blocked before project compilation by external dependency initialization/download failures; CI will run the targeted and repository checks with its dependency cacheBackport of #2449.
Follow-up validation (2026-10-13)
The backport remains unchanged. Compared with landed #2449 (
2d587f4e), the only differences in the three affected files are the intended 0.18 Catch2 include andGetMemoryUsage()return type. All six review suggestions have been answered and resolved with source and contract reasoning.VisitedListandVisitedListPooltests pass in a focused GCC 11.4 / Catch2 3.7.1 harness with ASan/UBSan: four test cases, 118,681 assertions, zero failures.git diff --checkpasses. This is focused validation, not a full local regression or coverage run.HGraph RangeSearch filters reranked distanceswith0 == 1, seed496730723; all four visited-list cases pass in that job.26b88d0cand its exact parent7e64ea07. Both pass with normal CPU affinity and both fail the same assertion with one-CPU affinity. The controls use GCC 11.4, Catch2 3.7.1,Sanitize(-O2), ASan/MKL off, and the same OpenBLAS 0.3.34 dependency. All objects affected by the visited-list header were recompiled for the parent comparison.These controls establish an inherited scheduling-sensitive regression-test failure, consistent with the fixture problem tracked in #3045. The original CircleCI insertion schedule was not preserved, so this does not claim inspection of that job's graph. No unrelated HGraph implementation or fixture change is included in this backport.
One failed-job-only rerun was requested for the existing CircleCI workflow; CircleCI returned HTTP 403 (
Permission denied), so no new run was started. Eight of nine required check contexts pass; the CircleCI context remains failed. Two human approvals are still required. This PR is not merge-ready.