perf(encoding): add row-based match finder backend#84
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds a Row-based match finder backend (RowMatchGenerator), wires it into level parameter resolution and MatchGeneratorDriver (selected for level 4), introduces RowConfig and dynamic row-hash sizing, updates matching control flow for Row, and adds tests and benchmark/CI support for the Row backend. Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Compression Pipeline
participant MG as MatchGeneratorDriver
participant Row as RowMatchGenerator
participant Tables as Row Hash Tables
participant Collector as Match Collector
Client->>MG: start_matching(level=4, pos)
MG->>MG: select MatcherBackend::Row
MG->>Row: initialize(RowConfig)
Client->>MG: request_matches(pos)
MG->>Row: find_candidates(pos)
Row->>Tables: row+tag lookup (heads/positions/tags)
Tables-->>Row: candidate positions
Row->>Row: filter candidates & backward-extend (lazy)
Row-->>Collector: emit matches or literals
Row->>Tables: insert/update current position (backfill/tail)
Tables-->>Row: ack
MG-->>Client: return matches
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Pull request overview
Adds a new row-based match-finder backend to the encoder and routes numeric compression level 4 to use it, with updated parameter resolution and targeted tests to validate backend selection and basic multi-block correctness.
Changes:
- Introduce
RowMatchGenerator(row/tag table probing + lazy lookahead) and integrate it intoMatchGeneratorDriver. - Extend level parameter resolution to include Row-specific config and enable the Row backend for
CompressionLevel::Level(4). - Update/add tests to pin backend selection and validate Row multi-block roundtrip reconstruction.
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@zstd/src/encoding/match_generator.rs`:
- Around line 1750-1754: hash_and_row() currently hashes 8 bytes when available
but falls back to 4 bytes near block tails, causing probes and inserts to use
different keys and leaving the last 7 positions underindexed; to fix, make the
Row table key stable across inserts and probes by choosing a single fixed key
width (e.g. always hash 8 bytes with safe padding) or implement dual short/long
row tables and ensure both are consulted on probes, update insert_positions(),
skip_matching(), and start_matching() to backfill the final <4 starts using the
HC-style boundary backfill so that tails inserted with the shorter key remain
visible to later 8-byte probes, and add a regression test exercising a
cross-boundary match across a 7-byte tail to prevent regressions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 2888c842-27bf-477a-8110-a6374d9ff224
📒 Files selected for processing (1)
zstd/src/encoding/match_generator.rs
|
@coderabbitai Fixed: row hash key is now stable (4-byte key), previous-block tail positions are backfilled before matching/skip, and a regression test covers cross-boundary tail reuse. |
|
Tip For best results, initiate chat on the files or code changes.
✏️ Learnings added
🧠 Learnings used |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@zstd/src/encoding/match_generator.rs`:
- Around line 122-126: Add the planned perf benchmark that exercises the
Level(4) routing (the LevelParams entry with backend: MatcherBackend::Row and
ROW_CONFIG) to measure throughput and match-quality on a representative corpus;
the benchmark should run a small/mid-block workload using the same setup as unit
tests but collecting throughput and match ratio metrics, and assert they stay
within acceptable bounds for ROW_SEARCH_DEPTH and ROW_TARGET_LEN so changes to
the Level(4) routing are guarded by automated performance checks. Ensure the
benchmark references the LevelParams entry for Level(4), uses
ROW_CONFIG/ROW_SEARCH_DEPTH/ROW_TARGET_LEN constants, and is integrated into the
CI perf job (or run via cargo bench) so regressions are flagged automatically.
- Around line 450-458: When switching away from MatcherBackend::Row ensure you
not only call row.reset(...) but also release the row tables (row_heads,
row_positions, row_tags) to free their heap allocation; after obtaining row via
self.row_match_generator.as_mut() and before/after calling row.reset(...), drop
or replace those fields (e.g. mem::take or Vec::clear + shrink_to_fit) the same
way the HC backend does so the row table footprint is returned to the allocator
and doesn't remain resident for the driver's lifetime.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 46b74064-8cdc-4f2b-9187-a5bd813bc510
📒 Files selected for processing (1)
zstd/src/encoding/match_generator.rs
There was a problem hiding this comment.
⚠️ Performance Alert ⚠️
Possible performance regression was detected for benchmark 'structured-zstd vs C FFI (x86_64-gnu)'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.30.
| Benchmark suite | Current: af3da92 | Previous: c9ab3d3 | Ratio |
|---|---|---|---|
compress/default/small-4k-log-lines/matrix/pure_rust |
7.573 ms |
4.994 ms |
1.52 |
compress/better/small-4k-log-lines/matrix/pure_rust |
0.254 ms |
0.153 ms |
1.66 |
compress/better/small-4k-log-lines/matrix/c_ffi |
0.182 ms |
0.077 ms |
2.36 |
This comment was automatically generated by workflow using github-action-benchmark.
CC: @polaz
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@zstd/src/encoding/match_generator.rs`:
- Around line 2854-2866: The test never sets saw_triple because the
matcher.start_matching closure only matches Sequence::Literals; update the
closure passed to matcher.start_matching to also match the triple variant (e.g.,
Sequence::Triple or Sequence::Match as defined in the Sequence enum) and set
saw_triple = true when that branch is hit, while keeping the existing logic that
extends reconstructed for Sequence::Literals; this ensures the
assert!(!saw_triple, ...) correctly fails if any triples are emitted.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 7da786ef-bb08-4cec-babd-3626972cfe7d
📒 Files selected for processing (1)
zstd/src/encoding/match_generator.rs
|
@coderabbitai full review |
|
@coderabbitai re-review |
|
🧠 Learnings used✅ Actions performedFull review triggered. |
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@zstd/src/encoding/match_generator.rs`:
- Around line 1875-1952: The Row backend duplicates the Dfast
lazy-match/repcode/backward-extension logic across best_match, pick_lazy_match,
repcode_candidate, extend_backwards, and better_candidate; factor that shared
logic into one reusable helper (e.g., a MatchHeuristics or shared functions like
repcode_candidate_shared, pick_lazy_match_shared, extend_backwards_shared,
better_candidate_shared) that takes the backend-specific inputs (abs_pos,
lit_len, offset history, history bounds, lazy_depth, target_len, live_history
accessor) and returns the same MatchCandidate/Option semantics, then replace the
duplicated implementations in this file and the corresponding Dfast locations
(also around the other block at 1996-2037) to call the shared helpers so
behavior and tests remain unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: a5169d8d-559b-4dfb-b9ed-c1b8de68f256
📒 Files selected for processing (3)
.github/scripts/run-benchmarks.shzstd/benches/support/mod.rszstd/src/encoding/match_generator.rs
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/scripts/run-benchmarks.sh:
- Line 108: REGRESSION_LEVELS duplicates the canonical list in
supported_levels(), causing silent mismatches; remove the hardcoded
REGRESSION_LEVELS and instead derive/validate benchmark level names against the
canonical source from the Rust side (supported_levels()) by either calling a
small Rust helper that prints supported levels or by loading a single shared
policy map that both sides use, then use that output to populate or validate the
set used in run-benchmarks.sh so the shell script and supported_levels() cannot
drift.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 05a4cff2-5f82-442e-a543-551855e1c2fe
📒 Files selected for processing (4)
.github/scripts/run-benchmarks.sh.github/workflows/ci.ymlzstd/benches/support/mod.rszstd/src/encoding/match_generator.rs
Summary
MatcherBackend::Rowwith dedicatedRowMatchGenerator(row/tag table probing + lazy lookahead)CompressionLevel::Defaulton dfast and moving dfast-specific tests toCompressionLevel::Level(2)Validation
Closes #67
Summary by CodeRabbit
New Features
Improvements
Tests
Chores