Compare commits

55 Commits

Author SHA1 Message Date
Danila Kutenin
27ab5f7f51 Fix benchmark C++11 code
Some checks failed
ci / CI ubuntu-latest avx clang debug (push) Failing after 12s
ci / CI ubuntu-latest avx clang release (push) Failing after 8s
ci / CI ubuntu-latest avx2 clang debug (push) Failing after 8s
ci / CI ubuntu-latest avx2 clang release (push) Failing after 9s
ci / CI ubuntu-latest baseline clang debug (push) Failing after 9s
ci / CI ubuntu-latest baseline clang release (push) Failing after 8s
ci / CI ubuntu-latest avx gcc debug (push) Failing after 9s
ci / CI ubuntu-latest avx gcc release (push) Failing after 8s
ci / CI ubuntu-latest avx2 gcc debug (push) Failing after 8s
ci / CI ubuntu-latest avx2 gcc release (push) Failing after 8s
ci / CI ubuntu-latest baseline gcc debug (push) Failing after 8s
ci / CI ubuntu-latest baseline gcc release (push) Failing after 8s
riscv64-qemu-test / test (push) Successful in 4m39s
ci / CI windows-latest avx msvc debug (push) Has been cancelled
ci / CI windows-latest avx msvc release (push) Has been cancelled
ci / CI windows-latest avx2 msvc debug (push) Has been cancelled
ci / CI windows-latest avx2 msvc release (push) Has been cancelled
ci / CI windows-latest baseline msvc debug (push) Has been cancelled
ci / CI windows-latest baseline msvc release (push) Has been cancelled
ci / CI macos-latest avx clang debug (push) Has been cancelled
ci / CI macos-latest avx clang release (push) Has been cancelled
ci / CI macos-latest baseline clang debug (push) Has been cancelled
ci / CI macos-latest baseline clang release (push) Has been cancelled
2026-05-09 18:58:29 +00:00
Danila Kutenin
f6f696553b Fix minor changes 2026-05-09 18:56:30 +00:00
Danila Kutenin
f50b387b42 Import changes
PiperOrigin-RevId: 913030038
2026-05-09 18:53:48 +00:00
Snappy Team
8fe84c01c0 Replace usage of ARCH_ARM with standard compiler macros.
PiperOrigin-RevId: 885453472
2026-05-09 18:53:37 +00:00
Yicheng Luo
a1962a8d1c Export LICENSE in bazel
PiperOrigin-RevId: 874490620
2026-05-09 18:53:28 +00:00
Danila Kutenin
368c77c96c Internal changes
PiperOrigin-RevId: 822002697
2026-05-09 18:53:17 +00:00
Danila Kutenin
ec20182d26 zippy: Fix data corruption when compressed output is more than 4GB
PiperOrigin-RevId: 741053848
2026-05-09 18:53:07 +00:00
Danila Kutenin
dca57a700f Internal changes
PiperOrigin-RevId: 631425350
2026-05-09 18:52:56 +00:00
Danila Kutenin
aa5f5f8650 Internal change
PiperOrigin-RevId: 626960053
2026-05-09 18:52:47 +00:00
Connal de Souza
2ac1356d4d Optimize ExtractOffset() by avoiding storing the mask.
Currently, the constant mask is stored to memory and then immediately read back. Since the read address is often not aligned to the store address, this can cause an expensive Read-after-Write hazard. Although the load is contained entirely within the store, meaning that store forwarding can occur and there are no throughput penalties, there is still a latency penalty. The increased latency matters because of the pointer-chasing pattern in decompression here.

https://godbolt.org/z/e71jhE3bj

PiperOrigin-RevId: 626440765
2026-05-09 18:52:39 +00:00
Danila Kutenin
c6d8c585dd Internal change
PiperOrigin-RevId: 623073126
2026-05-09 18:52:31 +00:00
Danila Kutenin
da1ea96391 Internal change
PiperOrigin-RevId: 622802698
2026-05-09 18:52:23 +00:00
Richard O'Grady
e1e7329dc7 Internal changes
PiperOrigin-RevId: 621907514
2026-05-09 18:52:12 +00:00
danilak-G
0212163f6e Merge pull request #234 from anthony-zy/rv_extractoffset
RISC-V: Optimize decompression with branchless AdvanceToNextTagRVOptimized +13.7%
2026-05-09 12:22:41 +01:00
danilak-G
0daaac5b07 Merge pull request #232 from anthony-zy/main
refactor: Align RISC-V implementation with AArch64 branchless mask extraction
2026-05-09 12:17:15 +01:00
danilak-G
70a0e1cbda Merge pull request #220 from yunfeizhou2025/upload
limit RISC-V FindMatchLength optimizations to 64-bit
2026-05-09 12:12:15 +01:00
anthony-zy
28590427a6 RISC-V: Optimize Snappy decompression tag advance (AdvanceToNextTagRVOptimized) for +4% throughput 2026-04-17 09:59:32 +08:00
郑紫阳10295048
77534271b3 refactor: Align RISC-V implementation with AArch64 branchless mask extraction 2026-04-15 10:33:35 +08:00
danilak-G
6281a07b7e Merge pull request #229 from UebelAndre/config
Move `//:config` to `implementation_deps` to prevent header collision
2026-03-06 22:30:42 +00:00
UebelAndre
4cb90917ee Move //:config to implementation_deps to prevent header collision 2026-03-06 11:47:10 -08:00
danilak-G
051dc4dc43 Merge pull request #228 from UebelAndre/bazel
Add Bazel 9 support
2026-03-03 16:49:56 +00:00
UebelAndre
07614b8308 Add Bazel 9 support 2026-02-28 12:38:26 -08:00
danilak-G
da459b5263 Create COPYING.notestdata
This file is created for those who do not distribute testdata as it has different licenses, useful for some of our customers
2026-01-21 10:12:49 +00:00
Zhou Yunfei
6484508ffb limit RISC-V FindMatchLength optimizations to 64-bit
Add `__riscv_xlen == 64` check to ensure the optimized FindMatchLength
routine is only enabled on 64-bit RISC-V platforms.

Signed-off-by: Zhou Yunfei <xdzyf2012@gmail.com>
2025-12-12 14:01:42 +08:00
danilak-G
25e52c58fb Merge pull request #214 from anthony-zy/add_zbb_check_macro
RISC-V: gate __builtin_ctzll behind Zbb to avoid 10 % slowdown
2025-11-20 12:13:53 +00:00
anthony-zy
a862a744b5 fix confic 2025-11-10 18:40:59 +08:00
anthony-zy
992fb9fcb0 Resolve merge conflicts 2025-11-10 18:39:54 +08:00
anthony-zy
c633c6bcb7 Resolve merge conflicts 2025-11-10 18:37:35 +08:00
anthony-zy
30dbdc2728 add zbb check macro 2025-11-10 18:31:13 +08:00
anthony-zy
727f5b3fc6 add zbb check macro 2025-11-10 10:37:19 +08:00
Danila Kutenin
cbea40d40c Fix an unused var warning for RISC-V 2025-10-20 13:34:53 +00:00
danilak-G
633cb9cbcb Merge pull request #213 from anthony-zy/add_rvv_optmized_memcopy64
feat(RISC-V): Add RVV-optimized implementation for memcopy64
2025-10-20 08:50:42 +01:00
anthony-zy
e92cb6ae8a Merge branch 'add_rvv_optmized_memcopy64' of https://github.com/anthony-zy/snappy into add_rvv_optmized_memcopy64 2025-10-20 10:20:21 +08:00
anthony-zy
2d6c8f17de Merge branch 'add_rvv_optmized_memcopy64' of https://github.com/anthony-zy/snappy into add_rvv_optmized_memcopy64 2025-10-20 10:19:39 +08:00
anthony-zy
b63569f403 Merge branch 'add_rvv_optmized_memcopy64' of https://github.com/anthony-zy/snappy into add_rvv_optmized_memcopy64 2025-10-20 09:53:37 +08:00
anthony-zy
9cc1596bf6 Merge branch 'add_rvv_optmized_memcopy64' of https://github.com/anthony-zy/snappy into add_rvv_optmized_memcopy64 2025-10-20 09:53:27 +08:00
anthony-zy
c098f689b8 Merge branch 'add_rvv_optmized_memcopy64' of https://github.com/anthony-zy/snappy into add_rvv_optmized_memcopy64 2025-10-17 17:53:04 +08:00
anthony-zy
6ab5882822 Merge branch 'add_rvv_optmized_memcopy64' of https://github.com/anthony-zy/snappy into add_rvv_optmized_memcopy64 2025-10-17 17:52:35 +08:00
anthony-zy
d457ac7380 Merge branch 'add_rvv_optmized_memcopy64' of https://github.com/anthony-zy/snappy into add_rvv_optmized_memcopy64 2025-10-17 10:29:45 +08:00
anthony-zy
9fd2b72c77 fix by some comments 2025-10-17 10:28:17 +08:00
anthony-zy
77a61a4927 Merge branch 'add_rvv_optmized_memcopy64' of https://github.com/anthony-zy/snappy into add_rvv_optmized_memcopy64 2025-10-17 10:21:26 +08:00
anthony-zy
c19d705ee1 Merge branch 'add_rvv_support' of https://github.com/anthony-zy/snappy into add_rvv_support 2025-10-17 10:20:57 +08:00
anthony-zy
2b8136579d Merge branch 'add_rvv_support' of https://github.com/anthony-zy/snappy into add_rvv_support 2025-09-12 11:07:09 +08:00
anthony-zy
c860cabbc5 Merge branch 'google:main' into add_rvv_support 2025-09-12 10:59:56 +08:00
anthony-zy
441032643f Merge branch 'google:main' into add_rvv_support 2025-09-05 16:02:38 +08:00
anthony-zy
27d8915d34 Merge branch 'add_rvv_support' of https://github.com/anthony-zy/snappy into add_rvv_support 2025-09-05 16:00:09 +08:00
anthony-zy
eb8d19fc1e Merge branch 'add_rvv_support' of https://github.com/anthony-zy/snappy into add_rvv_support 2025-09-05 15:59:29 +08:00
anthony-zy
0f989a2a97 Merge branch 'add_rvv_support' of https://github.com/anthony-zy/snappy into add_rvv_support 2025-08-28 20:42:49 +08:00
anthony-zy
802ef73aed add RVV support and optmized uncompress speed 2025-08-28 20:42:13 +08:00
anthony-zy
1f6ba69d67 add RVV support and optimized uncompress speed 2025-08-28 20:11:39 +08:00
anthony-zy
758804a4bc Use high-performance FindMatchLength to Optimize Snappy compression speed For RISC-V[skip ci] 2025-08-26 20:51:45 +08:00
danilak-G
6f99459b5b Merge pull request #208 from wanghan-sanechips/riscv-benchmark-fix
build: Update benchmark submodule for RISC-V
2025-07-29 09:45:06 +01:00
danilak-G
4793b4d004 Merge pull request #210 from anthony-zy/rv_findmatchlenght
Use high-performance FindMatchLength to Optimize Snappy compression s…
2025-07-29 09:44:35 +01:00
anthony-zy
1d88de7de8 Use high-performance FindMatchLength to Optimize Snappy compression speed For RISC-V[skip ci] 2025-07-29 14:08:43 +08:00
wanghan
b68435f083 build: Update benchmark submodule for RISC-V
- Pins to b20cea67 to fix illegal instruction
- Verified on openEuler RISC-V
2025-07-28 18:23:35 +08:00
13 changed files with 258 additions and 53 deletions

View File

@@ -0,0 +1,43 @@
name: riscv64-qemu-test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
env:
RISCV_CROSSCOMPILE: "ON"
riscv_gnu_toolchain_download_path: https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2025.07.03/riscv64-glibc-ubuntu-24.04-gcc-nightly-2025.07.03-nightly.tar.xz
RISCV_PATH: /opt/riscv
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt update
sudo apt install -y --no-install-recommends \
qemu-user qemu-user-static \
build-essential \
cmake \
git
sudo mkdir -p $RISCV_PATH
wget ${riscv_gnu_toolchain_download_path} -O riscv-toolchain.tar.xz
sudo tar -xvf riscv-toolchain.tar.xz -C $RISCV_PATH --strip-components=1
sudo sed -i "s|libdir='/mnt/riscv/riscv64-unknown-linux-gnu/lib'|libdir='$RISCV_PATH/riscv64-unknown-linux-gnu/lib'|g" $RISCV_PATH/riscv64-unknown-linux-gnu/lib/libatomic.la
- name: Build and Run Unit Tests
run: |
export PATH=$RISCV_PATH/bin:$PATH
export LD_LIBRARY_PATH="/opt/riscv/lib:$LD_LIBRARY_PATH"
export QEMU_LD_PREFIX=$RISCV_PATH/sysroot
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ../
make -j$(nproc)
make test
- name: Run Benchmark
run: ./build/snappy_benchmark
working-directory: ./

View File

@@ -26,10 +26,20 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
load("@bazel_skylib//rules:expand_template.bzl", "expand_template")
load("@bazel_skylib//rules:write_file.bzl", "write_file")
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
package(default_visibility = ["//visibility:public"]) package(default_visibility = ["//visibility:public"])
licenses(["notice"]) licenses(["notice"])
exports_files([
"COPYING",
"COPYING.notestdata",
])
SNAPPY_VERSION = (1, 2, 2) SNAPPY_VERSION = (1, 2, 2)
config_setting( config_setting(
@@ -52,8 +62,10 @@ cc_library(
name = "snappy-stubs-internal", name = "snappy-stubs-internal",
srcs = ["snappy-stubs-internal.cc"], srcs = ["snappy-stubs-internal.cc"],
hdrs = ["snappy-stubs-internal.h"], hdrs = ["snappy-stubs-internal.h"],
deps = [ implementation_deps = [
":config", ":config",
],
deps = [
":snappy-stubs-public", ":snappy-stubs-public",
], ],
) )
@@ -75,8 +87,10 @@ cc_library(
"-Wno-sign-compare", "-Wno-sign-compare",
], ],
}), }),
deps = [ implementation_deps = [
":config", ":config",
],
deps = [
":snappy-stubs-internal", ":snappy-stubs-internal",
":snappy-stubs-public", ":snappy-stubs-public",
], ],
@@ -133,10 +147,10 @@ cc_test(
) )
# Generate a config.h similar to what cmake would produce. # Generate a config.h similar to what cmake would produce.
genrule( write_file(
name = "config_h", name = "config_h",
outs = ["config.h"], out = "config.h",
cmd = """cat <<EOF >$@ content = """\
#define HAVE_STDDEF_H 1 #define HAVE_STDDEF_H 1
#define HAVE_STDINT_H 1 #define HAVE_STDINT_H 1
#ifdef __has_builtin #ifdef __has_builtin
@@ -193,19 +207,17 @@ genrule(
# define SNAPPY_IS_BIG_ENDIAN 1 # define SNAPPY_IS_BIG_ENDIAN 1
# endif # endif
#endif #endif
EOF """.splitlines(),
""",
) )
genrule( expand_template(
name = "snappy_stubs_public_h", name = "snappy_stubs_public_h",
srcs = ["snappy-stubs-public.h.in"], out = "snappy-stubs-public.h",
outs = ["snappy-stubs-public.h"], substitutions = {
# Assume sys/uio.h is available on non-Windows. "${HAVE_SYS_UIO_H_01}": "!_WIN32",
# Set the version numbers. "${PROJECT_VERSION_MAJOR}": str(SNAPPY_VERSION[0]),
cmd = ("""sed -e 's/$${HAVE_SYS_UIO_H_01}/!_WIN32/g' \ "${PROJECT_VERSION_MINOR}": str(SNAPPY_VERSION[1]),
-e 's/$${PROJECT_VERSION_MAJOR}/%d/g' \ "${PROJECT_VERSION_PATCH}": str(SNAPPY_VERSION[2]),
-e 's/$${PROJECT_VERSION_MINOR}/%d/g' \ },
-e 's/$${PROJECT_VERSION_PATCH}/%d/g' \ template = "snappy-stubs-public.h.in",
$< >$@""" % SNAPPY_VERSION),
) )

View File

@@ -155,10 +155,20 @@ int main() {
return __builtin_expect(0, 1); return __builtin_expect(0, 1);
}" HAVE_BUILTIN_EXPECT) }" HAVE_BUILTIN_EXPECT)
# Check if the built-in __builtin_ctz (count trailing zeros) is available.
# Require either a non-RISC-V target, or a RISC-V core that implements
# the Zbb bit-manipulation extension where ctz is guaranteed.
check_cxx_source_compiles(" check_cxx_source_compiles("
int main() { #ifdef __riscv
return __builtin_ctzll(0); #ifdef __riscv_zbb
}" HAVE_BUILTIN_CTZ) int main() { return __builtin_ctzll(0); }
#else
#error \"ZBB not enabled in current config\"
#endif
#else
int main() { return __builtin_ctzll(0); }
#endif
" HAVE_BUILTIN_CTZ)
check_cxx_source_compiles(" check_cxx_source_compiles("
int main() { int main() {
@@ -216,6 +226,31 @@ int main() {
return 0; return 0;
}" SNAPPY_HAVE_NEON) }" SNAPPY_HAVE_NEON)
#check RVV 1.0 need __riscv_ prefix
check_cxx_source_compiles("
#include <riscv_vector.h>
#include <stdint.h>
#include <stddef.h>
int main() {
uint8_t val = 3, dup[8];
size_t vl = __riscv_vsetvl_e8m1(8);
vuint8m1_t v = __riscv_vmv_v_x_u8m1(val, vl);
return 0;
}" SNAPPY_RVV_1)
#check RVV 0.7.1 not __riscv_ prefix
check_cxx_source_compiles("
#include <riscv_vector.h>
#include <stdint.h>
#include <stddef.h>
int main() {
uint8_t val = 3, dup[8];
size_t vl = vsetvl_e8m1(8);
vuint8m1_t v = vmv_v_x_u8m1(val, vl);
return 0;
}" SNAPPY_RVV_0_7)
include(CheckSymbolExists) include(CheckSymbolExists)
check_symbol_exists("mmap" "sys/mman.h" HAVE_FUNC_MMAP) check_symbol_exists("mmap" "sys/mman.h" HAVE_FUNC_MMAP)
check_symbol_exists("sysconf" "unistd.h" HAVE_FUNC_SYSCONF) check_symbol_exists("sysconf" "unistd.h" HAVE_FUNC_SYSCONF)

28
COPYING.notestdata Normal file
View File

@@ -0,0 +1,28 @@
Copyright 2011, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -4,20 +4,23 @@ module(
compatibility_level = 1, compatibility_level = 1,
) )
bazel_dep(name = "rules_cc", version = "0.2.4")
bazel_dep(name = "bazel_skylib", version = "1.8.2")
bazel_dep( bazel_dep(
name = "googletest", name = "googletest",
version = "1.14.0.bcr.1", version = "1.17.0.bcr.2",
dev_dependency = True, dev_dependency = True,
repo_name = "com_google_googletest", repo_name = "com_google_googletest",
) )
bazel_dep( bazel_dep(
name = "google_benchmark", name = "google_benchmark",
version = "1.9.0", version = "1.9.5",
dev_dependency = True, dev_dependency = True,
repo_name = "com_google_benchmark", repo_name = "com_google_benchmark",
) )
bazel_dep( bazel_dep(
name = "platforms", name = "platforms",
version = "0.0.9", version = "1.0.0",
) )

View File

View File

@@ -58,6 +58,12 @@
/* Define to 1 if you target processors with NEON and have <arm_neon.h>. */ /* Define to 1 if you target processors with NEON and have <arm_neon.h>. */
#cmakedefine01 SNAPPY_HAVE_NEON #cmakedefine01 SNAPPY_HAVE_NEON
/* Define to 1 if you target processors with RVV1.0 and have <riscv_vector.h>. */
#cmakedefine01 SNAPPY_RVV_1
/* Define to 1 if you target processors with RVV0.7 and have <riscv_vector.h>. */
#cmakedefine01 SNAPPY_RVV_0_7
/* Define to 1 if you have <arm_neon.h> and <arm_acle.h> and want to optimize /* Define to 1 if you have <arm_neon.h> and <arm_acle.h> and want to optimize
compression speed by using __crc32cw from <arm_acle.h>. */ compression speed by using __crc32cw from <arm_acle.h>. */
#cmakedefine01 SNAPPY_HAVE_NEON_CRC32 #cmakedefine01 SNAPPY_HAVE_NEON_CRC32

View File

@@ -46,6 +46,23 @@
#include <arm_neon.h> #include <arm_neon.h>
#endif #endif
#if SNAPPY_RVV_1 || SNAPPY_RVV_0_7
#define SNAPPY_HAVE_RVV 1
#include <riscv_vector.h>
#else
#define SNAPPY_HAVE_RVV 0
#endif
#ifdef SNAPPY_RVV_1
#define VSETVL_E8M2 __riscv_vsetvl_e8m2
#define VLE8_V_U8M2 __riscv_vle8_v_u8m2
#define VSE8_V_U8M2 __riscv_vse8_v_u8m2
#elif SNAPPY_RVV_0_7
#define VSETVL_E8M2 vsetvl_e8m2
#define VLE8_V_U8M2 vle8_v_u8m2
#define VSE8_V_U8M2 vse8_v_u8m2
#endif
#if SNAPPY_HAVE_SSSE3 || SNAPPY_HAVE_NEON #if SNAPPY_HAVE_SSSE3 || SNAPPY_HAVE_NEON
#define SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE 1 #define SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE 1
#else #else
@@ -110,6 +127,8 @@ inline V128 V128_Shuffle(V128 input, V128 shuffle_mask) {
} }
inline V128 V128_DupChar(char c) { return vdupq_n_u8(c); } inline V128 V128_DupChar(char c) { return vdupq_n_u8(c); }
#endif #endif
#endif // SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE #endif // SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE
@@ -172,9 +191,10 @@ char* CompressFragment(const char* input,
// loading from s2 + n. // loading from s2 + n.
// //
// Separate implementation for 64-bit, little-endian cpus. // Separate implementation for 64-bit, little-endian cpus.
// riscv and little-endian cpu choose this routinue can be done faster too.
#if !SNAPPY_IS_BIG_ENDIAN && \ #if !SNAPPY_IS_BIG_ENDIAN && \
(defined(__x86_64__) || defined(_M_X64) || defined(ARCH_PPC) || \ (defined(__x86_64__) || defined(_M_X64) || defined(ARCH_PPC) || \
defined(ARCH_ARM)) defined(__aarch64__) || (defined(__riscv) && (__riscv_xlen == 64)))
static inline std::pair<size_t, bool> FindMatchLength(const char* s1, static inline std::pair<size_t, bool> FindMatchLength(const char* s1,
const char* s2, const char* s2,
const char* s2_limit, const char* s2_limit,

View File

@@ -304,6 +304,7 @@ class Bits {
void operator=(const Bits&); void operator=(const Bits&);
}; };
// In RISC-V, CLZ is supported by instructions from the ZBB bit-manipulation extension.
#if HAVE_BUILTIN_CTZ #if HAVE_BUILTIN_CTZ
inline int Bits::Log2FloorNonZero(uint32_t n) { inline int Bits::Log2FloorNonZero(uint32_t n) {
@@ -393,6 +394,7 @@ inline int Bits::FindLSBSetNonZero(uint32_t n) {
#endif // End portable versions. #endif // End portable versions.
// In RISC-V, CLZ is supported by instructions from the ZBB bit-manipulation extension.
#if HAVE_BUILTIN_CTZ #if HAVE_BUILTIN_CTZ
inline int Bits::FindLSBSetNonZero64(uint64_t n) { inline int Bits::FindLSBSetNonZero64(uint64_t n) {

View File

@@ -74,7 +74,6 @@
#include <cstdint> #include <cstdint>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <functional>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility> #include <utility>
@@ -281,6 +280,8 @@ inline char* IncrementalCopySlow(const char* src, char* op,
// 4, 5, 0, 1, 2, 3, 4, 5, 0, 1}. These byte index sequences are generated by // 4, 5, 0, 1, 2, 3, 4, 5, 0, 1}. These byte index sequences are generated by
// calling MakePatternMaskBytes(0, 6, index_sequence<16>()) and // calling MakePatternMaskBytes(0, 6, index_sequence<16>()) and
// MakePatternMaskBytes(16, 6, index_sequence<16>()) respectively. // MakePatternMaskBytes(16, 6, index_sequence<16>()) respectively.
template <size_t... indexes> template <size_t... indexes>
inline constexpr std::array<char, sizeof...(indexes)> MakePatternMaskBytes( inline constexpr std::array<char, sizeof...(indexes)> MakePatternMaskBytes(
int index_offset, int pattern_size, index_sequence<indexes...>) { int index_offset, int pattern_size, index_sequence<indexes...>) {
@@ -298,7 +299,6 @@ MakePatternMaskBytesTable(int index_offset,
MakePatternMaskBytes(index_offset, pattern_sizes_minus_one + 1, MakePatternMaskBytes(index_offset, pattern_sizes_minus_one + 1,
make_index_sequence</*indexes=*/sizeof(V128)>())...}; make_index_sequence</*indexes=*/sizeof(V128)>())...};
} }
// This is an array of shuffle control masks that can be used as the source // This is an array of shuffle control masks that can be used as the source
// operand for PSHUFB to permute the contents of the destination XMM register // operand for PSHUFB to permute the contents of the destination XMM register
// into a repeating byte pattern. // into a repeating byte pattern.
@@ -494,7 +494,6 @@ inline char* IncrementalCopy(const char* src, char* op, char* const op_limit,
LoadPatternAndReshuffleMask(src, pattern_size); LoadPatternAndReshuffleMask(src, pattern_size);
V128 pattern = pattern_and_reshuffle_mask.first; V128 pattern = pattern_and_reshuffle_mask.first;
V128 reshuffle_mask = pattern_and_reshuffle_mask.second; V128 reshuffle_mask = pattern_and_reshuffle_mask.second;
// There is at least one, and at most four 16-byte blocks. Writing four // There is at least one, and at most four 16-byte blocks. Writing four
// conditionals instead of a loop allows FDO to layout the code with // conditionals instead of a loop allows FDO to layout the code with
// respect to the actual probabilities of each length. // respect to the actual probabilities of each length.
@@ -521,7 +520,6 @@ inline char* IncrementalCopy(const char* src, char* op, char* const op_limit,
LoadPatternAndReshuffleMask(src, pattern_size); LoadPatternAndReshuffleMask(src, pattern_size);
V128 pattern = pattern_and_reshuffle_mask.first; V128 pattern = pattern_and_reshuffle_mask.first;
V128 reshuffle_mask = pattern_and_reshuffle_mask.second; V128 reshuffle_mask = pattern_and_reshuffle_mask.second;
// This code path is relatively cold however so we save code size // This code path is relatively cold however so we save code size
// by avoiding unrolling and vectorizing. // by avoiding unrolling and vectorizing.
// //
@@ -1227,7 +1225,7 @@ inline bool Copy64BytesWithPatternExtension(ptrdiff_t dst, size_t offset) {
void MemCopy64(char* dst, const void* src, size_t size) { void MemCopy64(char* dst, const void* src, size_t size) {
// Always copy this many bytes. If that's below size then copy the full 64. // Always copy this many bytes. If that's below size then copy the full 64.
constexpr int kShortMemCopy = 32; constexpr int kShortMemCopy = 32;
(void)kShortMemCopy;
assert(size <= 64); assert(size <= 64);
assert(std::less_equal<const void*>()(static_cast<const char*>(src) + size, assert(std::less_equal<const void*>()(static_cast<const char*>(src) + size,
dst) || dst) ||
@@ -1246,6 +1244,27 @@ void MemCopy64(char* dst, const void* src, size_t size) {
data = _mm256_lddqu_si256(static_cast<const __m256i *>(src) + 1); data = _mm256_lddqu_si256(static_cast<const __m256i *>(src) + 1);
_mm256_storeu_si256(reinterpret_cast<__m256i *>(dst) + 1, data); _mm256_storeu_si256(reinterpret_cast<__m256i *>(dst) + 1, data);
} }
// RVV acceleration available on RISC-V when compiled with -march=rv64gcv
#elif defined(__riscv) && SNAPPY_HAVE_RVV
// Cast pointers to the type we will operate on.
unsigned char* dst_ptr = reinterpret_cast<unsigned char*>(dst);
const unsigned char* src_ptr = reinterpret_cast<const unsigned char*>(src);
size_t remaining_bytes = size;
// Loop as long as there are bytes remaining to be copied.
while (remaining_bytes > 0) {
// Set vector configuration: e8 (8-bit elements), m2 (LMUL=2).
// Use e8m2 configuration to maximize throughput.
size_t vl = VSETVL_E8M2(remaining_bytes);
// Load data from the current source pointer.
vuint8m2_t vec = VLE8_V_U8M2(src_ptr, vl);
// Store data to the current destination pointer.
VSE8_V_U8M2(dst_ptr, vec, vl);
// Update pointers and the remaining count.
src_ptr += vl;
dst_ptr += vl;
remaining_bytes -= vl;
}
#else #else
std::memmove(dst, src, kShortMemCopy); std::memmove(dst, src, kShortMemCopy);
// Profiling shows that nearly all copies are short. // Profiling shows that nearly all copies are short.
@@ -1345,19 +1364,51 @@ inline size_t AdvanceToNextTagX86Optimized(const uint8_t** ip_p, size_t* tag) {
return tag_type; return tag_type;
} }
SNAPPY_ATTRIBUTE_ALWAYS_INLINE
inline size_t AdvanceToNextTagRVOptimized(const uint8_t** ip_p, size_t* tag) {
const uint8_t*& ip = *ip_p;
// This section is crucial for the throughput of the decompression loop.
// The latency of an iteration is fundamentally constrained by the data chain on ip:
// ip -> c = *tag -> literal_len = c >> 2, tag_type = c & 3
// -> literal_advance = literal_len + 2, copy_advance = tag_type + 1
// -> next_ip = ip + literal_advance OR ip + copy_advance (literal vs copy)
// -> *tag = byte at (next_ip - 1); ip = next_ip
//
// Base RISC-V has no x86-style cmov and no AArch64 csinc on the same shape; this
// computes both candidate advances and both load offsets, then selects with
// (is_literal ? ... : ...). With the Zicond extension (czero.eqz / czero.nez), those
// selections typically lower to branchless conditional-zero ops instead of a
// hard-to-predict literal/copy branch, which is why this form tends to win there.
const size_t literal_len = *tag >> 2;
const size_t tag_type = *tag & 3;
const bool is_literal = (tag_type == 0);
const size_t copy_advance = tag_type + 1;
const size_t literal_advance = literal_len + 2;
const uint8_t* next_ip = is_literal ? (ip + literal_advance) : (ip + copy_advance);
*tag = is_literal ? ip[literal_advance - 1] : ip[copy_advance - 1];
ip = next_ip;
return tag_type;
}
// Extract the offset for copy-1 and copy-2 returns 0 for literals or copy-4. // Extract the offset for copy-1 and copy-2 returns 0 for literals or copy-4.
inline uint32_t ExtractOffset(uint32_t val, size_t tag_type) { inline uint32_t ExtractOffset(uint32_t val, size_t tag_type) {
// For x86 non-static storage works better. For ARM static storage is better. // For Arm non-static storage works better. For x86 static storage is better.
// TODO: Once the array is recognized as a register, improve the // TODO: Once the array is recognized as a register, improve the
// readability for x86. // readability for x86.
#if defined(__x86_64__) #if defined(__x86_64__)
constexpr uint64_t kExtractMasksCombined = 0x0000FFFF00FF0000ull; static constexpr uint64_t kExtractMasksCombined = 0x0000FFFF00FF0000ull;
uint16_t result; uint16_t result;
memcpy(&result, memcpy(&result,
reinterpret_cast<const char*>(&kExtractMasksCombined) + 2 * tag_type, reinterpret_cast<const char*>(&kExtractMasksCombined) + 2 * tag_type,
sizeof(result)); sizeof(result));
return val & result; return val & result;
#elif defined(__aarch64__) // For AArch64 and RISC-V, use a bit-twiddling trick to extract the mask from a
// single combined constant instead of a lookup table. The constant packs multiple
// 16-bit masks based on tag_type (see implementation below). The code calculates
// the shift amount from tag_type, right-shifts the constant to move the desired
// mask to the LSB position, then extracts it with & 0xFFFF. This branchless
// approach is often more performant on modern CPUs.
#elif defined(__aarch64__) || (defined(__riscv) && (__riscv_xlen == 64))
constexpr uint64_t kExtractMasksCombined = 0x0000FFFF00FF0000ull; constexpr uint64_t kExtractMasksCombined = 0x0000FFFF00FF0000ull;
return val & static_cast<uint32_t>( return val & static_cast<uint32_t>(
(kExtractMasksCombined >> (tag_type * 16)) & 0xFFFF); (kExtractMasksCombined >> (tag_type * 16)) & 0xFFFF);
@@ -1421,6 +1472,11 @@ std::pair<const uint8_t*, ptrdiff_t> DecompressBranchless(
// We never need more than 16 bits. Doing a Load16 allows the compiler // We never need more than 16 bits. Doing a Load16 allows the compiler
// to elide the masking operation in ExtractOffset. // to elide the masking operation in ExtractOffset.
next = LittleEndian::Load16(old_ip); next = LittleEndian::Load16(old_ip);
#elif defined(__riscv)
size_t tag_type = AdvanceToNextTagRVOptimized(&ip, &tag);
// We never need more than 16 bits. Doing a Load16 allows the compiler
// to elide the masking operation in ExtractOffset.
next = LittleEndian::Load16(old_ip);
#else #else
size_t tag_type = AdvanceToNextTagX86Optimized(&ip, &tag); size_t tag_type = AdvanceToNextTagX86Optimized(&ip, &tag);
next = LittleEndian::Load32(old_ip); next = LittleEndian::Load32(old_ip);
@@ -1779,13 +1835,13 @@ static bool InternalUncompressAllTags(SnappyDecompressor* decompressor,
Writer* writer, uint32_t compressed_len, Writer* writer, uint32_t compressed_len,
uint32_t uncompressed_len) { uint32_t uncompressed_len) {
int token = 0; int token = 0;
Report(token, "snappy_uncompress", compressed_len, uncompressed_len);
writer->SetExpectedLength(uncompressed_len); writer->SetExpectedLength(uncompressed_len);
// Process the entire input // Process the entire input
decompressor->DecompressAllTags(writer); decompressor->DecompressAllTags(writer);
writer->Flush(); writer->Flush();
Report(token, "snappy_uncompress", compressed_len, uncompressed_len);
return (decompressor->eof() && writer->CheckLength()); return (decompressor->eof() && writer->CheckLength());
} }
@@ -1800,11 +1856,9 @@ size_t Compress(Source* reader, Sink* writer) {
size_t Compress(Source* reader, Sink* writer, CompressionOptions options) { size_t Compress(Source* reader, Sink* writer, CompressionOptions options) {
assert(options.level == 1 || options.level == 2); assert(options.level == 1 || options.level == 2);
int token = 0;
size_t written = 0; size_t written = 0;
size_t N = reader->Available(); size_t N = reader->Available();
assert(N <= 0xFFFFFFFFu); assert(N <= 0xFFFFFFFFu);
const size_t uncompressed_size = N;
char ulength[Varint::kMax32]; char ulength[Varint::kMax32];
char* p = Varint::Encode32(ulength, N); char* p = Varint::Encode32(ulength, N);
writer->Append(ulength, p - ulength); writer->Append(ulength, p - ulength);
@@ -1865,14 +1919,13 @@ size_t Compress(Source* reader, Sink* writer, CompressionOptions options) {
fragment, fragment_size, dest, table, table_size >> 1, fragment, fragment_size, dest, table, table_size >> 1,
table + (table_size >> 1), table_size >> 1); table + (table_size >> 1), table_size >> 1);
} }
writer->Append(dest, end - dest); writer->Append(dest, end - dest);
written += (end - dest); written += (end - dest);
N -= num_to_read; N -= num_to_read;
reader->Skip(pending_advance); reader->Skip(pending_advance);
} }
Report(token, "snappy_compress", written, uncompressed_size);
return written; return written;
} }

View File

@@ -67,6 +67,7 @@ namespace snappy {
constexpr CompressionOptions() = default; constexpr CompressionOptions() = default;
constexpr CompressionOptions(int compression_level) constexpr CompressionOptions(int compression_level)
: level(compression_level) {} : level(compression_level) {}
static constexpr int MinCompressionLevel() { return 1; } static constexpr int MinCompressionLevel() { return 1; }
static constexpr int MaxCompressionLevel() { return 2; } static constexpr int MaxCompressionLevel() { return 2; }
static constexpr int DefaultCompressionLevel() { return 1; } static constexpr int DefaultCompressionLevel() { return 1; }
@@ -158,6 +159,7 @@ namespace snappy {
// RawCompress(input, input_length, output, &output_length); // RawCompress(input, input_length, output, &output_length);
// ... Process(output, output_length) ... // ... Process(output, output_length) ...
// delete [] output; // delete [] output;
// First version is to preserve ABI.
void RawCompress(const char* input, size_t input_length, char* compressed, void RawCompress(const char* input, size_t input_length, char* compressed,
size_t* compressed_length); size_t* compressed_length);
void RawCompress(const char* input, size_t input_length, char* compressed, void RawCompress(const char* input, size_t input_length, char* compressed,
@@ -166,6 +168,7 @@ namespace snappy {
// Same as `RawCompress` above but taking an `iovec` array as input. Note that // Same as `RawCompress` above but taking an `iovec` array as input. Note that
// `uncompressed_length` is the total number of bytes to be read from the // `uncompressed_length` is the total number of bytes to be read from the
// elements of `iov` (_not_ the number of elements in `iov`). // elements of `iov` (_not_ the number of elements in `iov`).
// First version is to preserve ABI.
void RawCompressFromIOVec(const struct iovec* iov, size_t uncompressed_length, void RawCompressFromIOVec(const struct iovec* iov, size_t uncompressed_length,
char* compressed, size_t* compressed_length); char* compressed, size_t* compressed_length);
void RawCompressFromIOVec(const struct iovec* iov, size_t uncompressed_length, void RawCompressFromIOVec(const struct iovec* iov, size_t uncompressed_length,