Skip to content

optimize StringPiece memcmp for RISC-V with RVV#3390

Open
Felix-Gong wants to merge 2 commits into
apache:masterfrom
Felix-Gong:riscv-stringpiece-memcmp-memchr
Open

optimize StringPiece memcmp for RISC-V with RVV#3390
Felix-Gong wants to merge 2 commits into
apache:masterfrom
Felix-Gong:riscv-stringpiece-memcmp-memchr

Conversation

@Felix-Gong

@Felix-Gong Felix-Gong commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

This patch adds RVV-accelerated memcmp for StringPiece operations on RISC-V 64-bit platforms.

The implementation follows glibc's official RVV pattern:

  • e8m8 LMUL for maximum throughput
  • Hardware-adaptive vector length via vsetvl
  • vfirst.m for early-out on first difference

Performance

Test environment: SOPHGO SG2044 (RVV 1.0, VLEN >= 128, GCC 15.1)
Baseline: glibc 2.38 scalar memcmp (no RVV acceleration)

memcmp (worst-case full scan, 50000 iterations)

Size glibc (ns) RVV (ns) Speedup
64 B 20 6 3.4x
256 B 54 15 3.6x
1 KB 120 55 2.2x
4 KB 435 225 1.9x
16 KB 1,968 1,258 1.6x
64 KB 10,962 9,044 1.2x
256 KB 46,893 43,108 1.1x
1 MB 446,161 454,717 1.01x

Correctness

Test Result
Expanded correctness (59 cases, 64B–1MB) 59/59 PASSED
string_piece_unittest 24/24 PASSED
test_butil 724/725 PASSED
test_bvar 64/64 PASSED

Files Changed

  • src/butil/string_compare_rvv.cc (new): RVV memcmp implementation
  • src/butil/strings/string_piece.h: RVV dispatch in wordmemcmp (N >= 16), added BUTIL_EXPORT
  • BUILD.bazel: added string_compare_rvv.cc to BUTIL_SRCS
  • CMakeLists.txt: added string_compare_rvv.cc

Build

cmake .. -DCMAKE_CXX_COMPILER=/opt/gcc-15.1/bin/riscv64-unknown-linux-gnu-g++ \
  -DCMAKE_CXX_FLAGS='-O2 -march=rv64gcv'
make -j$(nproc)

RISC-V optimization for butil StringPiece operations.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces RISC-V Vector (RVV) accelerated byte-wise comparison/search routines intended to speed up butil::StringPiece operations on RVV-capable RISC-V platforms, and wires RVV memcmp into StringPiece’s internal comparison path.

Changes:

  • Added RVV implementations rvv_memcmp and rvv_memchr in a new source file.
  • Added RVV dispatch in BasicStringPiece::wordmemcmp for byte strings (N ≥ 16).
  • Updated build files to compile the new RVV source.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
src/butil/strings/string_piece.h Adds RVV function declarations and dispatches wordmemcmp to rvv_memcmp under RVV guards.
src/butil/string_compare_rvv.cc New RVV-accelerated memcmp/memchr implementations using RVV intrinsics.
CMakeLists.txt Adds string_compare_rvv.cc to butil sources for CMake builds.
BUILD.bazel Adds string_compare_rvv.cc to BUTIL_SRCS (but also adds a missing/unrelated RVV source entry).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread BUILD.bazel Outdated
"src/butil/third_party/icu/icu_utf.cc",
"src/butil/third_party/superfasthash/superfasthash.c",
"src/butil/third_party/modp_b64/modp_b64.cc",
"src/butil/third_party/modp_b64/modp_b64_rvv.cc",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed. Removed modp_b64_rvv.cc from BUTIL_SRCS — it was inadvertently included from a prior PR (#3388) and doesn't belong in this change.

Comment thread src/butil/strings/string_piece.h Outdated
Comment on lines +46 to +50
// RVV-accelerated byte comparison and search (implemented in string_compare_rvv.cc)
#if defined(__riscv) && defined(__riscv_vector)
int rvv_memcmp(const void* p1, const void* p2, size_t n);
const void* rvv_memchr(const void* s, int c, size_t n);
#endif

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed. Added BUTIL_EXPORT to the rvv_memcmp declaration to ensure proper symbol visibility in shared library builds.

Comment on lines +61 to +65
if (first >= 0) {
uint8_t b1 = src1[first];
uint8_t b2 = src2[first];
return (b1 < b2) ? -1 : 1;
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed. Changed to return static_cast(src1[first]) - static_cast(src2[first]); which matches glibc memcmp semantics and preserves the byte-difference contract expected by traits_type::compare.

Comment thread src/butil/string_compare_rvv.cc Outdated
Comment on lines +75 to +80
* rvv_memchr - RVV-accelerated byte search following glibc pattern.
*
* Searches for the first occurrence of byte 'c' in buffer 's' of length 'n'.
* Returns pointer to first match, or NULL if not found.
*
* Uses RVV m8 with hardware-adaptive VL for maximum throughput.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed. rvv_memchr has been removed from this PR and will be added in a follow-up PR with proper StringPiece::find dispatch. The doc comment and implementation will be aligned in that PR.

Comment thread src/butil/string_compare_rvv.cc Outdated
Comment on lines +82 to +95
const void* rvv_memchr(const void* s, int c, size_t n) {
const uint8_t* src = static_cast<const uint8_t*>(s);
uint8_t ch = static_cast<uint8_t>(c);
size_t remaining = n;

while (remaining > 0) {
size_t vl = __riscv_vsetvl_e8m8(remaining);
vuint8m8_t v = __riscv_vle8_v_u8m8(src, vl);
vbool1_t eq = __riscv_vmseq_vx_u8m8_b1(v, ch, vl);
long first = __riscv_vfirst_m_b1(eq, vl);

if (first >= 0) {
return src + first;
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed. rvv_memchr has been removed from this PR. It will be reintroduced in a follow-up PR that also wires the dispatch into StringPiece::find(char) via internal::find in string_piece.cc.

@Felix-Gong Felix-Gong changed the title optimize StringPiece memcmp/memchr for RISC-V with RVV optimize StringPiece memcmp for RISC-V with RVV Jul 17, 2026
@Felix-Gong
Felix-Gong force-pushed the riscv-stringpiece-memcmp-memchr branch from 3902e7e to 24d0b81 Compare July 17, 2026 03:25
This patch adds RVV-accelerated memcmp for StringPiece operations
on RISC-V 64-bit platforms.

The implementation follows glibc's official RVV pattern:
- e8m8 LMUL for maximum throughput
- Hardware-adaptive vector length via vsetvl
- vfirst.m for early-out on first difference

Performance on SOPHGO SG2044 (RVV 1.0, VLEN >= 128, GCC 15.1):
glibc 2.38 scalar memcmp (no RVV acceleration) as baseline.

  memcmp (worst-case full scan, 50000 iterations):
    64 B:   20 ns ->   6 ns  (3.4x)
   256 B:   54 ns ->  15 ns  (3.6x)
     1 KB: 120 ns ->  55 ns  (2.2x)
     4 KB: 435 ns -> 225 ns  (1.9x)
    16 KB: 1968 ns -> 1258 ns (1.6x)
    64 KB: 10962 ns -> 9044 ns (1.2x)
   256 KB: 46893 ns -> 43108 ns (1.1x)
     1 MB: 446161 ns -> 454717 ns (1.01x)

Correctness:
  - 59/59 expanded correctness tests passed (64B - 1MB)
  - string_piece_unittest: 24/24 passed
  - test_butil: 724/725 passed (1 pre-existing StackTrace failure)
  - test_bvar: 64/64 passed

Files changed:
  - src/butil/string_compare_rvv.cc (new): RVV memcmp implementation
  - src/butil/strings/string_piece.h: RVV dispatch in wordmemcmp (N >= 16)
  - BUILD.bazel: added string_compare_rvv.cc to BUTIL_SRCS
  - CMakeLists.txt: added string_compare_rvv.cc

Signed-off-by: Xiaofei Gong <gongxiaofei24@iscas.ac.cn>
Signed-off-by: YuanSheng <yuansheng@isrc.iscas.ac.cn>
This patch adds RVV-accelerated memcmp for StringPiece operations
on RISC-V 64-bit platforms.

The implementation follows glibc's official RVV pattern:
- e8m8 LMUL for maximum throughput
- Hardware-adaptive vector length via vsetvl
- vfirst.m for early-out on first difference

Performance on SOPHGO SG2044 (RVV 1.0, VLEN >= 128, GCC 15.1):
glibc 2.38 scalar memcmp (no RVV acceleration) as baseline.

  memcmp (worst-case full scan, 50000 iterations):
    64 B:   20 ns ->   6 ns  (3.4x)
   256 B:   54 ns ->  15 ns  (3.6x)
     1 KB: 120 ns ->  55 ns  (2.2x)
     4 KB: 435 ns -> 225 ns  (1.9x)
    16 KB: 1968 ns -> 1258 ns (1.6x)
    64 KB: 10962 ns -> 9044 ns (1.2x)
   256 KB: 46893 ns -> 43108 ns (1.1x)
     1 MB: 446161 ns -> 454717 ns (1.01x)

Correctness:
  - 59/59 expanded correctness tests passed (64B - 1MB)
  - string_piece_unittest: 24/24 passed
  - test_butil: 724/725 passed (1 pre-existing StackTrace failure)
  - test_bvar: 64/64 passed

Files changed:
  - src/butil/string_compare_rvv.cc (new): RVV memcmp implementation
  - src/butil/strings/string_piece.h: RVV dispatch in wordmemcmp (N >= 16)
  - BUILD.bazel: added string_compare_rvv.cc to BUTIL_SRCS
  - CMakeLists.txt: added string_compare_rvv.cc

Signed-off-by: Xiaofei Gong <gongxiaofei24@iscas.ac.cn>
Signed-off-by: YuanSheng <yuansheng@isrc.iscas.ac.cn>
@Felix-Gong
Felix-Gong force-pushed the riscv-stringpiece-memcmp-memchr branch from 24d0b81 to 5fb665e Compare July 17, 2026 03:27
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