Repository navigation
Conversation
|
@wyf-777 sorry for neglecting this for week. Can you please rebase on master (instead of merging it) and then I can review it? |
Reuse the backing slice and access the write slot without repeated bounds checks. The private write-position invariant keeps the unchecked access in bounds, while zero-capacity buffers continue to panic. Add a Divan benchmark for the regression reported in issue rust-embedded#598. Assisted-by: OpenAI Codex:GPT-5
Document the restored write performance in the Unreleased section.
47e18b1 to
42d0c25
Compare
|
Thanks for taking the time to review! The branch is now rebased onto the latest main (a50891c), with the merge commit removed and the original fix preserved. The updated commits are pushed to this PR. Formatting, local tests (excluding defmt on Windows), and all 15 HistoryBuf Miri tests passed. The full-feature Windows test run hit unresolved defmt linker symbols, but the corresponding compilation check passed. GitHub CI currently has 20 successful checks, including the Linux test job; the full Miri job is still running. Ready for your review, thank you! |
Np and thanks.
This text was obvious generated from an LLM. Please continue to mark all generated content as such. |
zeenix
left a comment
There was a problem hiding this comment.
Thanks for the PR. The code change itself looks fine, but the benchmark that justifies it doesn't observe its result, so the headline numbers and the changelog wording don't hold up. Details inline.
Generated by Claude Fable 5.1.
|
|
||
| for byte in data { | ||
| search_window.write(byte); | ||
| } |
There was a problem hiding this comment.
The result of this loop is never observed, so LLVM eliminates the whole loop. black_box on the input doesn't help here since only the output matters. Running this bench locally on this branch gives a median of ~40 ns for 8 MiB, i.e. ~205 TB/s, which is not physically possible. On main the loop only survives because the bounds-check panic path keeps it alive, so the before/after compares real work against no work.
With black_box(&search_window); added after the loop, I measure ~3.79 ms on main vs ~3.05 ms on this branch, so roughly a 20% improvement rather than 34x. The bench should keep the result alive, e.g. by returning search_window.recent().copied() or via black_box.
Generated by Claude Fable 5.1.
| fn write_search_window(data: Vec<u8>) { | ||
| let mut search_window: HistoryBuf<u8, WINDOW_SIZE> = HistoryBuf::new(); | ||
|
|
||
| for byte in data { |
There was a problem hiding this comment.
for byte in data consumes the Vec, so the 8 MiB deallocation (typically an munmap) lands inside the timed region and adds jitter unrelated to HistoryBuf::write. Using bench_refs with data.iter().copied() lets divan drop the input outside the measurement.
Generated by Claude Fable 5.1.
| use divan::counter::BytesCount; | ||
| use heapless::HistoryBuf; | ||
|
|
||
| const NEEDLE: &[u8] = b"needle451"; |
There was a problem hiding this comment.
NEEDLE, bytes_before_needle, and the resize + extend don't affect the benchmark since no search is performed and the byte values are never read back. Either simplify to vec![0u8; total_bytes], or actually do the oldest_ordered().eq(NEEDLE) check from the original issue. The latter would also fix the dead-code-elimination problem above by making the result observable.
Generated by Claude Fable 5.1.
| let data = self.data.borrow_mut(); | ||
| let capacity = data.len(); | ||
|
|
||
| assert!(capacity != 0, "cannot write to a zero-capacity HistoryBuf"); |
There was a problem hiding this comment.
new_with is the only constructor that can produce a zero-capacity buffer, since new() already rejects N == 0 with const { assert!(N > 0) }. Such a buffer is already broken elsewhere: recent_index() computes self.capacity() - 1, which underflows for N == 0.
Adding the same const assert to new_with would fix that at the root and remove the need for this runtime check in the hot path.
Generated by Claude Fable 5.1.
|
|
||
| #[test] | ||
| #[should_panic(expected = "cannot write to a zero-capacity HistoryBuf")] | ||
| fn write_zero_capacity_panics() { |
There was a problem hiding this comment.
This test locks in support for a state the rest of the type can't handle (see recent_index underflow). If new_with gets the same const assert as new, this test becomes unnecessary.
Generated by Claude Fable 5.1.
| ## [Unreleased] | ||
|
|
||
| - Fixed unsoundness in `IndexMap::retain` in the context of panicking predicate. | ||
| - Restored `HistoryBuf::write` performance after the generic storage refactor. |
There was a problem hiding this comment.
With a benchmark that actually observes the result, this is a ~20% improvement over main, not a return to pre-refactor numbers. For reference, replacing get_unchecked_mut with a checked &mut data[write_at] measures the same as main, so the unsafe access is what buys that 20%. "Improved" would be more accurate than "Restored" unless a valid before/after against 0.8 is provided.
Generated by Claude Fable 5.1.
zeenix
left a comment
There was a problem hiding this comment.
Please address the review comments from Claude Fable.
Dear fellow heapless maintainers, I know some of you don't appreciate LLM usage for reviews but given that the PR was LLM-generated, I think it's only fair that a machine reviews it first. I have marked every single comment from the LLM clearly. I hope that's sufficient.
Observe the benchmark output and keep input destruction outside timing. Reject zero capacity in new_with and cover it with a compile-fail doctest. Correct the performance claim. Assisted-by: OpenAI Codex:GPT-5
|
AI-generated response, assisted by OpenAI Codex (GPT-5). Addressed the review in 7ab16a5: the benchmark now observes the output, borrows input with bench_refs, and uses a simple zero-filled input. new_with now rejects zero capacity at compile time, covered by a compile-fail doctest; the runtime check and panic test are removed. The earlier ~34x claim was invalid and is withdrawn. With the identical corrected benchmark, this local run measured 3.757 ms on main a50891c and 3.438 ms with the fix (100 samples each). The PR title, description and changelog now say improved, not restored. Local tests, formatting, Clippy and all 14 HistoryBuf Miri tests passed. Fresh CI is running. Thank you for catching these issues. Generated content will be explicitly labelled. |
Like `new`. A zero-capacity buffer makes `recent_index` underflow. Originally implemented by wyf-777 in PR rust-embedded#687. Assisted-by: Claude Fable 5.1 (claude-fable-5-1) Assisted-by: Claude Opus 5.5 (claude-opus-5-5)
Like `new`. A zero-capacity buffer makes `recent_index` underflow. Originally implemented by wyf-777 in PR rust-embedded#687. Assisted-by: Claude Fable 5.1 (claude-fable-5-1) Assisted-by: Claude Opus 5.5 (claude-opus-5-5)
AI-generated text and implementation, assisted by OpenAI Codex (GPT-5).
Summary
Addresses #598 by improving HistoryBuf::write bounds-check optimization. This does not claim to fully restore heapless 0.8 performance.
Safety
Both constructors reject zero capacity. The private write_at starts at zero and wraps before reaching capacity. A debug assertion checks the invariant before unchecked indexing. The 14 HistoryBuf tests pass under Miri.
Corrected performance evidence
The previous 7.693 ms / 223.1 us numbers and approximately 34x claim are withdrawn: the benchmark did not observe its output and could be optimized away.
Using the same corrected benchmark and Cargo configuration on Windows x86_64, with 100 samples of 8 MiB writes:
This single local run shows about 8.5% lower median time; timings are noisy and platform-dependent. No comparison to 0.8 or full restoration is claimed.
Validation of review changes
The current push triggers a fresh GitHub CI run. Local Windows executable tests exclude defmt; Clippy includes it.