Repository navigation
CRC32C dispatch: prefer scalar Zbc over Zvbc (fix PR3332 small-buffer regression) - #3601
Felix-Gong wants to merge 1 commit into
Conversation
aaaec4c to
1b3eb93
Compare
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
2 open findings
What changed in this PR
Adjusts the RISC-V CRC32C implementation dispatch to avoid a small-buffer performance regression by preferring the faster scalar Zbc path over the Zvbc vector path when both are available.
Changes:
- Reordered
Choose_Extend()dispatch checks to preferZbc(scalar) beforeZvbc(vector). - Kept
Zvbcas a fallback whenZbcisn’t available.
| File | Description |
|---|---|
src/butil/crc32c.cc |
Reorders RISC-V extension detection to select scalar Zbc before vector Zvbc to avoid perf regressions. |
🧠 Review effort: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
1b3eb93 to
6d8ce6e
Compare
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
3 open findings
🧠 Review effort: Lite
6d8ce6e to
d099479
Compare
d099479 to
7e618c1
Compare
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
7 open findings
The256threshold is a newly introduced magic number. Please extract it into a named constant… · New With this ordering, CPUs that have both Zbc and Zvbc will never userv_crc32c_vclmul, even for… This changes runtime behavior (which implementation is selected) when both Zbc and Zvbc are…RiscvExtendalready matches theFunctiontypedef signature, so the C-style cast is redundant… · New This#elsebranch implicitly means 'only__riscv_zbcis defined' due to the outer condition,… · New This#elsebranch implicitly means 'only__riscv_zbcis defined' due to the outer condition,… · New The dispatch ordering is performance-sensitive and was changed to address a regression when both…
🧠 Review effort: Lite
| static uint32_t RiscvExtend(uint32_t crc, const char* buf, size_t size) { | ||
| return (size >= 256 ? rv_crc32c_vclmul : rv_crc32c_clmul)(crc, buf, size); |
There was a problem hiding this comment.
Extracted it to kRiscvVclmulThresholdBytes, next to RiscvExtend. It only exists in the Zbc+Zvbc build, and the comment above still explains why the crossover is around there.
| static const bool has_zbc = is_zbc(); | ||
| static const bool has_zvbc = is_zvbc(); | ||
| if (has_zbc && has_zvbc) { | ||
| return (Function)RiscvExtend; |
There was a problem hiding this comment.
RiscvExtend has the same signature as Function, so the cast isn't needed for correctness. I kept it because every other return in this function casts explicitly ((Function)rv_crc32c_clmul, (Function)ExtendImpl<...>), and matching that reads better than one uncast return in the middle.
| return (Function)rv_crc32c_clmul; | ||
| } | ||
| } | ||
| #elif defined(__riscv_zvbc) |
There was a problem hiding this comment.
Changed to #elif defined(__riscv_zbc). The outer condition already requires zbc or zvbc, so behavior is unchanged, but writing it out makes the intent clear if that condition is ever edited.
| } | ||
| #endif | ||
| #if defined(__riscv_zbc) | ||
| #else |
There was a problem hiding this comment.
Same as above — made the branch explicit.
PR3332 sent every Zbc+Zvbc CPU to the vclmul path. After apache#3571 rewrote it, vclmul beats clmul from ~256 B up (1.5x-7.5x) but costs more below that, where vector setup dominates. A fixed order to either path is wrong for these CPUs. Select by size in the dispatcher: clmul under 256 B, vclmul from 256 B on. CPUs with only Zbc or only Zvbc keep their current path, and Extend() is untouched. k3 (X100, VLEN=256, 20-round median): 256 B clmul 1534 vclmul 2155 1 MiB clmul 1555 vclmul 11702 (MB/s) Signed-off-by: Xiaofei Gong <gongxiaofei24@iscas.ac.cn> Signed-off-by: YuanSheng <yuansheng@isrc.iscas.ac.cn>
7e618c1 to
0bee1b6
Compare


Follow-up to #3571.
PR3332 sent every Zbc+Zvbc CPU to the vclmul path. Now that #3571
rewrote it, vclmul wins above ~256 B (1.5x-7.5x) but loses below it,
so a fixed order either way is wrong.
Pick by size: clmul under 256 B, vclmul from 256 B on. CPUs with only
Zbc or only Zvbc keep their previous path; Extend() is unchanged.
Tested on k3 (X100): CRC.* 5/5 PASSED, 180 size/boundary combos match
the table reference.