This is an automated email from the ASF dual-hosted git repository.
chenBright pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brpc.git
The following commit(s) were added to refs/heads/master by this push:
new 5197621b Optimize StringPiece memcmp/memchr for RISC-V with RVV (#3396)
5197621b is described below
commit 5197621b915084ac9ca357763c6870d086cd7e12
Author: Felix-Gong <[email protected]>
AuthorDate: Wed Jul 22 17:00:33 2026 +0800
Optimize StringPiece memcmp/memchr for RISC-V with RVV (#3396)
This patch adds RVV-accelerated memcmp and memchr for StringPiece operations
on RISC-V 64-bit platforms.
The implementation follows glibc's official RVV memcmp/memchr patterns:
- e8m8 LMUL for maximum throughput
- Hardware-adaptive vector length via vsetvl
- vfirst.m for early-out on first difference/match
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)
memchr (worst-case full scan, 50000 iterations):
64 B: 5 ns -> 0.9 ns (5.8x)
256 B: 12 ns -> 3 ns (4.0x)
1 KB: 40 ns -> 12 ns (3.3x)
4 KB: 148 ns -> 44 ns (3.4x)
16 KB: 558 ns -> 158 ns (3.5x)
64 KB: 2150 ns -> 635 ns (3.4x)
256 KB: 9200 ns -> 2900 ns (3.2x)
1 MB: 39000 ns -> 13000 ns (3.0x)
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 + memchr
implementations
- src/butil/strings/string_piece.h: RVV dispatch declarations
- src/butil/strings/string_piece.cc: RVV dispatch in find(char) for memchr
- BUILD.bazel: added string_compare_rvv.cc to BUTIL_SRCS
- CMakeLists.txt: added string_compare_rvv.cc
- Makefile: added string_compare_rvv.cc
Signed-off-by: Xiaofei Gong <[email protected]>
Signed-off-by: YuanSheng <[email protected]>
---
BUILD.bazel | 1 +
src/butil/string_compare_rvv.cc | 28 ++++++++++++++++++++++++----
src/butil/strings/string_piece.cc | 11 +++++++++++
src/butil/strings/string_piece.h | 3 ++-
4 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/BUILD.bazel b/BUILD.bazel
index cf4560b7..5dc5fcf7 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -128,6 +128,7 @@ BUTIL_SRCS = [
"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",
"src/butil/third_party/symbolize/demangle.cc",
"src/butil/third_party/symbolize/symbolize.cc",
"src/butil/third_party/snappy/snappy-sinksource.cc",
diff --git a/src/butil/string_compare_rvv.cc b/src/butil/string_compare_rvv.cc
index 3f7985e1..6373e83d 100644
--- a/src/butil/string_compare_rvv.cc
+++ b/src/butil/string_compare_rvv.cc
@@ -15,10 +15,9 @@
// specific language governing permissions and limitations
// under the License.
-// RVV-accelerated memcmp for StringPiece operations.
-// Algorithm follows glibc's RVV memcmp pattern:
-// - e8m8 LMUL with hardware-adaptive VL via vsetvl
-// - vfirst.m for early-out on first mismatch
+// RVV-accelerated memcmp and memchr for StringPiece operations.
+// memcmp: follows glibc's RVV memcmp pattern (e8m8 LMUL, vfirst.m early-out).
+// memchr: uses vmseq + vfirst.m to locate first matching byte.
#include "butil/strings/string_piece.h"
@@ -50,6 +49,27 @@ int rvv_memcmp(const void* p1, const void* p2, size_t n) {
return 0;
}
+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;
+ }
+
+ src += vl;
+ remaining -= vl;
+ }
+ return nullptr;
+}
+
} // namespace butil
#endif // __riscv && __riscv_vector
diff --git a/src/butil/strings/string_piece.cc
b/src/butil/strings/string_piece.cc
index 2d249243..a96d6ad0 100644
--- a/src/butil/strings/string_piece.cc
+++ b/src/butil/strings/string_piece.cc
@@ -134,7 +134,18 @@ size_t findT(const BasicStringPiece<STR>& self,
}
size_t find(const StringPiece& self, char c, size_t pos) {
+#if defined(__riscv) && defined(__riscv_vector)
+ if (pos < self.size()) {
+ const void* result = butil::rvv_memchr(self.data() + pos, c, self.size() -
pos);
+ if (result != nullptr) {
+ return static_cast<size_t>(static_cast<const char*>(result) -
self.data());
+ }
+ return BasicStringPiece<std::string>::npos;
+ }
+ return BasicStringPiece<std::string>::npos;
+#else
return findT(self, c, pos);
+#endif
}
size_t find(const StringPiece16& self, char16 c, size_t pos) {
diff --git a/src/butil/strings/string_piece.h b/src/butil/strings/string_piece.h
index b1a4ed73..808ccbb1 100644
--- a/src/butil/strings/string_piece.h
+++ b/src/butil/strings/string_piece.h
@@ -43,9 +43,10 @@
namespace butil {
-// RVV-accelerated byte comparison (implemented in string_compare_rvv.cc)
+// RVV-accelerated byte comparison and search (implemented in
string_compare_rvv.cc)
#if defined(__riscv) && defined(__riscv_vector)
BUTIL_EXPORT int rvv_memcmp(const void* p1, const void* p2, size_t n);
+BUTIL_EXPORT const void* rvv_memchr(const void* s, int c, size_t n);
#endif
template <typename STRING_TYPE> class BasicStringPiece;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]