Skip to content

Commit 5fb665e

Browse files
committed
optimize StringPiece memcmp for RISC-V with RVV
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>
1 parent a0d91f0 commit 5fb665e

3 files changed

Lines changed: 24 additions & 76 deletions

File tree

BUILD.bazel

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ BUTIL_SRCS = [
128128
"src/butil/third_party/icu/icu_utf.cc",
129129
"src/butil/third_party/superfasthash/superfasthash.c",
130130
"src/butil/third_party/modp_b64/modp_b64.cc",
131-
"src/butil/third_party/modp_b64/modp_b64_rvv.cc",
132131
"src/butil/third_party/symbolize/demangle.cc",
133132
"src/butil/third_party/symbolize/symbolize.cc",
134133
"src/butil/third_party/snappy/snappy-sinksource.cc",

src/butil/string_compare_rvv.cc

Lines changed: 22 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,32 @@
1-
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2-
/* vi: set expandtab shiftwidth=4 tabstop=4: */
3-
/**
4-
* \file
5-
* RISC-V Vector (RVV) accelerated memcmp/memchr for StringPiece operations.
6-
*
7-
* Algorithm follows glibc's RVV memcmp/memchr patterns:
8-
* - Use vsetvli with e8/m8 for maximum throughput (hardware-adaptive VL)
9-
* - Use vfirst.m to find first differing/matching byte (no vcpop needed)
10-
* - Simple loop: load → compare → find first → branch
11-
*
12-
* Licensed to the Apache Software Foundation (ASF) under one
13-
* or more contributor license agreements. See the NOTICE file
14-
* distributed with this work for additional information
15-
* regarding copyright ownership. The ASF licenses this file
16-
* to you under the Apache License, Version 2.0 (the
17-
* License); you may not use this file except in compliance
18-
* with the License. You may obtain a copy of the License at
19-
*
20-
* http://www.apache.org/licenses/LICENSE-2.0
21-
*
22-
* Unless required by applicable law or agreed to in writing,
23-
* software distributed under the License is distributed on an
24-
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
25-
* KIND, either express or implied. See the License for the
26-
* specific language governing permissions and limitations
27-
* under the License.
28-
*/
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
// RVV-accelerated memcmp for StringPiece operations.
19+
// Algorithm follows glibc's RVV memcmp pattern:
20+
// - e8m8 LMUL with hardware-adaptive VL via vsetvl
21+
// - vfirst.m for early-out on first mismatch
2922

3023
#include "butil/strings/string_piece.h"
3124

3225
#if defined(__riscv) && defined(__riscv_vector)
3326
#include <riscv_vector.h>
34-
#include <stdint.h>
35-
#include <string.h>
3627

3728
namespace butil {
3829

39-
/**
40-
* rvv_memcmp - RVV-accelerated byte comparison following glibc pattern.
41-
*
42-
* Compares two byte arrays and returns:
43-
* < 0 if p1 < p2
44-
* 0 if p1 == p2
45-
* > 0 if p1 > p2
46-
*
47-
* Uses RVV m8 with hardware-adaptive VL for maximum throughput.
48-
*/
4930
int rvv_memcmp(const void* p1, const void* p2, size_t n) {
5031
const uint8_t* src1 = static_cast<const uint8_t*>(p1);
5132
const uint8_t* src2 = static_cast<const uint8_t*>(p2);
@@ -59,9 +40,7 @@ int rvv_memcmp(const void* p1, const void* p2, size_t n) {
5940
long first = __riscv_vfirst_m_b1(neq, vl);
6041

6142
if (first >= 0) {
62-
uint8_t b1 = src1[first];
63-
uint8_t b2 = src2[first];
64-
return (b1 < b2) ? -1 : 1;
43+
return static_cast<int>(src1[first]) - static_cast<int>(src2[first]);
6544
}
6645

6746
src1 += vl;
@@ -71,35 +50,6 @@ int rvv_memcmp(const void* p1, const void* p2, size_t n) {
7150
return 0;
7251
}
7352

74-
/**
75-
* rvv_memchr - RVV-accelerated byte search following glibc pattern.
76-
*
77-
* Searches for the first occurrence of byte 'c' in buffer 's' of length 'n'.
78-
* Returns pointer to first match, or NULL if not found.
79-
*
80-
* Uses RVV m8 with hardware-adaptive VL for maximum throughput.
81-
*/
82-
const void* rvv_memchr(const void* s, int c, size_t n) {
83-
const uint8_t* src = static_cast<const uint8_t*>(s);
84-
uint8_t ch = static_cast<uint8_t>(c);
85-
size_t remaining = n;
86-
87-
while (remaining > 0) {
88-
size_t vl = __riscv_vsetvl_e8m8(remaining);
89-
vuint8m8_t v = __riscv_vle8_v_u8m8(src, vl);
90-
vbool1_t eq = __riscv_vmseq_vx_u8m8_b1(v, ch, vl);
91-
long first = __riscv_vfirst_m_b1(eq, vl);
92-
93-
if (first >= 0) {
94-
return src + first;
95-
}
96-
97-
src += vl;
98-
remaining -= vl;
99-
}
100-
return nullptr;
101-
}
102-
10353
} // namespace butil
10454

10555
#endif // __riscv && __riscv_vector

src/butil/strings/string_piece.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,9 @@
4343

4444
namespace butil {
4545

46-
// RVV-accelerated byte comparison and search (implemented in string_compare_rvv.cc)
46+
// RVV-accelerated byte comparison (implemented in string_compare_rvv.cc)
4747
#if defined(__riscv) && defined(__riscv_vector)
48-
int rvv_memcmp(const void* p1, const void* p2, size_t n);
49-
const void* rvv_memchr(const void* s, int c, size_t n);
48+
BUTIL_EXPORT int rvv_memcmp(const void* p1, const void* p2, size_t n);
5049
#endif
5150

5251
template <typename STRING_TYPE> class BasicStringPiece;

0 commit comments

Comments
 (0)