simdcomp

fast-packBSD-3-Clause更新放缓

用 SIMD 指令对整数列表做二进制打包压缩的轻量 C 库,适合倒排索引、ID 序列这类场景,压缩快、解压更快。

A simple C library for compressing lists of integers using binary packing

v0.1.1发布于 2018-09-26 16:04 UTC537star54fork同步于 2026-11-07 07:33 UTC

怎么上手

由 README 提炼,执行前请确认
cmake -B build
cmake --build build
ctest --test-dir build
硬件要求按 README 说明

x86/x64 需支持 SSE4.1(2008 年后的多数 Intel/AMD 处理器),核心位打包函数只需 SSE2;ARM 需 AArch64 且支持 NEON(如 Apple Silicon)。README 未提及显存或 GPU 要求,纯 CPU 库。

支持 Apple Silicon
下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

用 SIMD 指令对整数列表做二进制打包压缩的 C 库,解码速度远超通用编解码器

用 SIMD 指令对整数列表做二进制打包压缩的轻量 C 库,适合倒排索引、ID 序列这类场景,压缩快、解压更快。

核心能力

  • 按 128 个整数分块做位打包,压缩比为 32/b
  • 提供差分编码接口,适合有序整数列表
  • 支持 Frame-of-Reference 编码,便于快速检索
  • 同一套 API 自动适配 x86 SSE/AVX 与 ARM NEON
  • 解码速度可达每秒数十亿整数,快于 gzip、LZ4 等

容易踩的坑

库本身不定义压缩格式,需自行设计上层格式;构建基准测试需 C++17 并会拉取 lemire/counters 依赖;在 Apple Silicon/Linux 上跑基准测试统计周期数需 sudo。

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

3 个版本v0.1.1
  1. v0.1.1version 0.1.1最新正式版2018-09-26 · 2018-09-26 16:04 UTC

    这个版本没有写更新说明。

  2. v0.1.0version 0.1.02018-09-20 · 2018-09-20 02:37 UTC

    这个版本没有写更新说明。

  3. v0.0.32014-05-19 · 2014-05-19 14:47 UTC

    这个版本没有写更新说明。

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    The SIMDComp library

    Build Status

    A simple C library for compressing lists of integers using binary packing and SIMD instructions. The assumption is either that you have a list of 32-bit integers where most of them are small, or a list of 32-bit integers where differences between successive integers are small. No software is able to reliably compress an array of 32-bit random numbers.

    This library can decode at least 4 billions of compressed integers per second on most desktop or laptop processors. That is, it can decompress data at a rate of 15 GB/s. This is significantly faster than generic codecs like gzip, LZO, Snappy or LZ4.

    On a Skylake Intel processor, it can decode integers at a rate 0.3 cycles per integer, which can easily translate into more than 8 decoded billions integers per second.

    It runs on both x86/x64 (SSE/AVX) and 64-bit ARM (NEON, e.g. Apple Silicon). See Platforms below.

    This library is part of the Awesome C list of C resources.

    Contributors: Daniel Lemire, Nathan Kurz, Christoph Rupp, Anatol Belski, Nick White and others

    What is it for?

    This is a low-level library for fast integer compression. By design it does not define a compressed format. It is up to the (sophisticated) user to create a compressed format.

    It is used by:

    Requirements

    • On x86/x64: your processor should support SSE4.1 (supported by most Intel and AMD processors released since 2008). The core bit-packing functions only require SSE2 (Pentium4 or better).
    • On ARM: an AArch64/ARM processor with NEON (e.g. Apple Silicon). The SSE intrinsics are mapped to NEON by our own self-contained shim (include/neon128.h); no third-party translation library is pulled in.
    • A C99 (or better) compiler, plus a C++17 compiler if you build the benchmarks.
    • CMake 3.14 or better.

    For a plain C version that does not use SIMD instructions, see https://github.com/lemire/LittleIntPacker

    Platforms

    The library supports two SIMD backends behind the same API:

    • x86 / x64 — Intel/AMD SSE (with optional AVX2 and AVX-512 code paths, enabled automatically when you build with -march=native on a capable host).
    • 64-bit ARM (AArch64) with NEON, such as Apple Silicon. The SSE intrinsics used by the 128-bit kernels are mapped onto ARM NEON by a small, self-contained shim that ships with the library (include/neon128.h). This is our own code written directly against <arm_neon.h>; no third-party translation layer (such as sse2neon) is pulled in. The wider AVX2/AVX-512 paths are x86-only and are simply inactive on ARM.

    The public API is identical on both: it is selected automatically at compile time, so the same source (including the __m128i-based entry points) builds on either architecture.

    Usage

    Compression works over blocks of 128 integers.

    For a complete working example, see example/example.c (after building, run it with "./build/example").

    1. Lists of integers in random order.
    const uint32_t b = maxbits(datain);// computes bit width
    simdpackwithoutmask(datain, buffer, b);//compressed to buffer, compressing 128 32-bit integers down to b*32 bytes
    simdunpack(buffer, backbuffer, b);//uncompressed to backbuffer
    

    While 128 32-bit integers are read, only b 128-bit words are written. Thus, the compression ratio is 32/b.

    1. Sorted lists of integers.

    We used differential coding: we store the difference between successive integers. For this purpose, we need an initial value (called offset).

    uint32_t offset = 0;
    uint32_t b1 = simdmaxbitsd1(offset,datain); // bit width
    simdpackwithoutmaskd1(offset, datain, buffer, b1);//compressing 128 32-bit integers down to b1*32 bytes
    simdunpackd1(offset, buffer, backbuffer, b1);//uncompressed
    

    General example for arrays of arbitrary length:

    int compress_decompress_demo() {
      size_t k, N = 9999;
      __m128i * endofbuf;
      uint32_t * datain = malloc(N * sizeof(uint32_t));
      uint8_t * buffer;
      uint32_t * backbuffer = malloc(N * sizeof(uint32_t));
      uint32_t b;
    
      for (k = 0; k < N; ++k){        /* start with k=0, not k=1! */
        datain[k] = k;
      }
    
      b = maxbits_length(datain, N);
      buffer = malloc(simdpack_compressedbytes(N,b)); // allocate just enough memory
      endofbuf = simdpack_length(datain, N, (__m128i *)buffer, b);
      /* compressed data is stored between buffer and endofbuf using (endofbuf-buffer)*sizeof(__m128i) bytes */
      /* would be safe to do : buffer = realloc(buffer,(endofbuf-(__m128i *)buffer)*sizeof(__m128i)); */
      simdunpack_length((const __m128i *)buffer, N, backbuffer, b);
    
      for (k = 0; k < N; ++k){
        if(datain[k] != backbuffer[k]) {
          printf("bug\n");
          return -1;
        }
      }
      return 0;
    }
    
    1. Frame-of-Reference

    We also have frame-of-reference (FOR) functions (see simdfor.h header). They work like the bit packing routines, but do not use differential coding so they allow faster search in some cases, at the expense of compression.

    Setup

    The library builds with CMake:

    cmake -B build
    cmake --build build
    ctest --test-dir build        # run the unit tests
    

    To install the library, headers, and a CMake package configuration:

    cmake --install build --prefix /your/install/prefix
    

    Once installed, another CMake project can use it with:

    find_package(simdcomp REQUIRED)
    target_link_libraries(myapp PRIVATE simdcomp::simdcomp)
    

    Or vendor it directly via FetchContent (no install needed):

    include(FetchContent)
    FetchContent_Declare(simdcomp
      GIT_REPOSITORY https://github.com/lemire/simdcomp.git
      GIT_TAG master)
    FetchContent_MakeAvailable(simdcomp)
    target_link_libraries(myapp PRIVATE simdcomp::simdcomp)
    

    Useful options: -DSIMDCOMP_BUILD_BENCHMARKS=OFF (the benchmarks pull in lemire/counters for cycle-accurate timing and require C++17), -DSIMDCOMP_BUILD_TESTS=OFF, and -DSIMDCOMP_NATIVE=OFF (disable -march=native).

    The benchmark reports CPU cycles per integer using hardware performance counters when they are available (otherwise it falls back to wall-clock time and throughput):

    ./build/bitpackingbenchmark        # on Apple Silicon/Linux, run with sudo for cycle counts
    

    Go

    If you are a go user, there is a "go" folder where you will find a simple demo.

    Other libraries

    Other programming languages

    References