#reed-solomon #erasure-coding #erasure #x86-64 #leopard-rs

reed-solomon-simd

具有 O(n log n) 复杂度的 Reed-Solomon 编码。利用 x86(-64) 和 AArch64 上的 SIMD 指令。

5 个稳定版本

2.2.2 2024 年 4 月 22 日
2.2.1 2024 年 2 月 21 日
2.2.0 2024 年 2 月 12 日
2.1.0 2023 年 11 月 25 日
2.0.0 2023 年 11 月 16 日

#163 in 编码

Download history 282/week @ 2024-04-23 121/week @ 2024-04-30 139/week @ 2024-05-07 291/week @ 2024-05-14 236/week @ 2024-05-21 2978/week @ 2024-05-28 6870/week @ 2024-06-04 5726/week @ 2024-06-11 2988/week @ 2024-06-18 4264/week @ 2024-06-25 4760/week @ 2024-07-02 6302/week @ 2024-07-09 3018/week @ 2024-07-16 5620/week @ 2024-07-23 5577/week @ 2024-07-30 4729/week @ 2024-08-06

19,773 个月下载量

MIT AND BSD-3-Clause

240KB
5K SLoC

reed-solomon-simd

基于 Leopard-RS 的 Reed-Solomon 侵蚀编码,具有

  • O(n log n) 复杂度。
  • 完全用 Rust 编写。
  • 在 AArch64 (Neon) 和 x86(-64) (SSSE3 和 AVX2) 上运行时选择最佳的 SIMD 实现,并提供回退到纯 Rust。
  • 可以组合 1 - 32768 个原始碎片和 1 - 32768 个恢复碎片。
  • 还可以使用以下限制实现多达 65535 个原始或恢复碎片
original_count recovery_count
<= 2^16 - 2^n <= 2^n
<= 61440 <= 4096
<= 57344 <= 8192
<= 49152 <= 16384
<= 32768 <= 32768
<= 16384 <= 49152
<= 8192 <= 57344
<= 4096 <= 61440
<= 2^n <= 2^16 - 2^n

基准测试

原始 : 恢复 编码 解码(1% 丢失;100% 丢失)
32: 32 10.237 GiB/s 254.24 MiB/s ; 253.60 MiB/s
64: 64 8.6758 GiB/s 459.18 MiB/s ; 456.83 MiB/s
128 : 128 7.3891 GiB/s 753.11 MiB/s ; 758.65 MiB/s
256 : 256 6.3753 GiB/s 1.0391 GiB/s ; 1.0323 GiB/s
512 : 512 5.5076 GiB/s 1.1862 GiB/s ; 1.2542 GiB/s
1024 : 1024 4.8495 GiB/s 1.3017 GiB/s ; 1.4178 GiB/s
2048 : 2048 4.3733 GiB/s 1.3341 GiB/s ; 1.4640 GiB/s
4096 : 4096 3.9926 GiB/s 1.2008 GiB/s ; 1.3585 GiB/s
8192 : 8192 3.1220 GiB/s 942.68 MiB/s ; 1012.5 MiB/s
16384 : 16384 2.2468 GiB/s 701.36 MiB/s ; 687.75 MiB/s
32 768 : 32 768 1.6049 GiB/s 681.39 MiB/s ; 667.93 MiB/s
128 : 1 024 6.4068 GiB/s 857.36 MiB/s ; 856.25 MiB/s
1 000 : 100 5.6079 GiB/s 1021.7 MiB/s ; 1022.0 MiB/s
1 000 : 10 000 4.0041 GiB/s 1012.7 MiB/s ; 1014.9 MiB/s
8 192 : 57 344 2.3174 GiB/s 706.97 MiB/s ; 704.85 MiB/s
10 000 : 1 000 2.9598 GiB/s 924.42 MiB/s ; 942.26 MiB/s
57 344 : 8 192 1.8894 GiB/s 657.89 MiB/s ; 664.97 MiB/s
  • AMD Ryzen 5 3600 (Zen 2, 2019) 的单核 AVX2。
  • 在 Apple Silicon M1 CPU 上的吞吐量大约相同 (+-10%)。
  • MiB/s 和 GiB/s 是关于总数据量,即原始碎片 + 恢复碎片的。
    • 对于解码器,这包括丢失的碎片。
  • 碎片大小为 1024 字节。
  • 编码基准
  • 解码基准测试

请克隆reed-solomon-simd并运行自己的基准测试

$ cargo bench main

简单用法

  1. 将数据分成大小相等的原始数据块。数据块大小必须是64字节的倍数。
  2. 确定您想要的恢复数据块数量。
  3. 使用reed_solomon_simd::encode生成恢复数据块。
  4. 当一些原始数据块丢失时,使用reed_solomon_simd::decode恢复它们。
    • 您必须提供至少与原始数据块总数相等的数据块数量,可以是原始数据块和恢复数据块的任何组合。

注意:此包不检测或纠正数据块内的错误。因此,如果数据损坏是一个可能的场景,您应该在每个数据块中包含一个错误检测哈希,并跳过向解码器提供损坏的数据块。以下是一些非常快速的错误检测哈希建议:CRC32c(4字节)、HighwayHash(8、16或32字节)或xxHash(4、8或16字节)。

示例

将数据分成3个64字节的原始数据块,并生成5个恢复数据块。假设原始数据块#0和#2丢失,并通过提供1个原始数据块和2个恢复数据块来恢复它们。

let original = [
    b"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do ",
    b"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut e",
    b"nim ad minim veniam, quis nostrud exercitation ullamco laboris n",
];

let recovery = reed_solomon_simd::encode(
    3, // total number of original shards
    5, // total number of recovery shards
    original, // all original shards
)?;

let restored = reed_solomon_simd::decode(
    3, // total number of original shards
    5, // total number of recovery shards
    [  // provided original shards with indexes
        (1, &original[1]),
    ],
    [  // provided recovery shards with indexes
        (1, &recovery[1]),
        (4, &recovery[4]),
    ],
)?;

assert_eq!(restored[&0], original[0]);
assert_eq!(restored[&2], original[2]);
# Ok::<(), reed_solomon_simd::Error>(())

基本用法

ReedSolomonEncoderReedSolomonDecoder提供了对编码/解码过程的更多控制。

以下是使用这些示例

use reed_solomon_simd::{ReedSolomonDecoder, ReedSolomonEncoder};
use std::collections::HashMap;

let original = [
    b"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do ",
    b"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut e",
    b"nim ad minim veniam, quis nostrud exercitation ullamco laboris n",
];

let mut encoder = ReedSolomonEncoder::new(
    3, // total number of original shards
    5, // total number of recovery shards
    64, // shard size in bytes
)?;

for original in original {
    encoder.add_original_shard(original)?;
}

let result = encoder.encode()?;
let recovery: Vec<_> = result.recovery_iter().collect();

let mut decoder = ReedSolomonDecoder::new(
    3, // total number of original shards
    5, // total number of recovery shards
    64, // shard size in bytes
)?;

decoder.add_original_shard(1, original[1])?;
decoder.add_recovery_shard(1, recovery[1])?;
decoder.add_recovery_shard(4, recovery[4])?;

let result = decoder.decode()?;
let restored: HashMap<_, _> = result.restored_original_iter().collect();

assert_eq!(restored[&0], original[0]);
assert_eq!(restored[&2], original[2]);
# Ok::<(), reed_solomon_simd::Error>(())

高级用法

请参阅rate模块,以了解使用所选EngineRate进行高级编码/解码的方法。

与其他crate的基准测试

使用cargo run --release --example quick-comparison运行针对reed-solomon-16reed-solomon-erasurereed-solomon-novelpolycrate的几个简单基准测试。

该软件包在我的AMD Ryzen 5 3600上在所有情况下都是最快的,除了在解码大约42个或更少的恢复碎片时。此外,还有一次性的初始化(小于10毫秒)来计算表,这在处理非常小的数据量时可能会占主导地位。

运行测试

一些较大的测试被标记为 #[ignore],并且不会与 cargo test 一起运行。使用 cargo test -- --ignored 来运行这些测试。

安全性

此软件包中 unsafe 的唯一用途是允许在 Ssse3Avx2Neon 中进行针对特定目标的最优化。

致谢

该软件包是Markus Laire的reed-solomon-16软件包的分支,该软件包又基于Christopher A. Taylor的Leopard-RS

依赖项

约265KB