refactor(benches): update benchmarks to use SIMD-only implementation

- Remove all conditional compilation (#[cfg(feature = "reed-solomon-simd")])
- Rewrite erasure_benchmark.rs to focus on SIMD performance testing
- Transform comparison_benchmark.rs into SIMD performance analysis
- Update all documentation and comments to English
- Remove references to reed-solomon-erasure implementation
- Streamline benchmark groups and test configurations
- Add comprehensive SIMD-specific performance tests

Breaking Changes:
- Benchmarks no longer compare different implementations
- All benchmarks now test SIMD implementation exclusively
- Benchmark naming conventions updated for clarity

Performance Testing:
- Enhanced shard size sensitivity analysis
- Improved concurrent performance testing
- Added memory efficiency benchmarks
- Comprehensive error recovery analysis
This commit is contained in:
weisd
2025-06-23 10:12:45 +08:00
parent 4559baaeeb
commit 080af2b39f
2 changed files with 220 additions and 285 deletions
+102 -115
View File
@@ -1,29 +1,28 @@
//! 专门比较 Pure Erasure 和 Hybrid (SIMD) 模式性能的基准测试
//! Reed-Solomon SIMD performance analysis benchmarks
//!
//! 这个基准测试使用不同的feature编译配置来直接对比两种实现的性能。
//! This benchmark analyzes the performance characteristics of the SIMD Reed-Solomon implementation
//! across different data sizes, shard configurations, and usage patterns.
//!
//! ## 运行比较测试
//! ## Running Performance Analysis
//!
//! ```bash
//! # 测试 Pure Erasure 实现 (默认)
//! # Run all SIMD performance tests
//! cargo bench --bench comparison_benchmark
//!
//! # 测试 Hybrid (SIMD) 实现
//! cargo bench --bench comparison_benchmark --features reed-solomon-simd
//! # Generate detailed performance report
//! cargo bench --bench comparison_benchmark -- --save-baseline simd_analysis
//!
//! # 测试强制 erasure-only 模式
//! cargo bench --bench comparison_benchmark
//!
//! # 生成对比报告
//! cargo bench --bench comparison_benchmark -- --save-baseline erasure
//! cargo bench --bench comparison_benchmark --features reed-solomon-simd -- --save-baseline hybrid
//! # Run specific test categories
//! cargo bench --bench comparison_benchmark encode_analysis
//! cargo bench --bench comparison_benchmark decode_analysis
//! cargo bench --bench comparison_benchmark shard_analysis
//! ```
use criterion::{BenchmarkId, Criterion, Throughput, black_box, criterion_group, criterion_main};
use ecstore::erasure_coding::Erasure;
use std::time::Duration;
/// 基准测试数据配置
/// Performance test data configuration
struct TestData {
data: Vec<u8>,
size_name: &'static str,
@@ -36,41 +35,41 @@ impl TestData {
}
}
/// 生成不同大小的测试数据集
/// Generate different sized test datasets for performance analysis
fn generate_test_datasets() -> Vec<TestData> {
vec![
TestData::new(1024, "1KB"), // 小数据
TestData::new(8 * 1024, "8KB"), // 中小数据
TestData::new(64 * 1024, "64KB"), // 中等数据
TestData::new(256 * 1024, "256KB"), // 中大数据
TestData::new(1024 * 1024, "1MB"), // 大数据
TestData::new(4 * 1024 * 1024, "4MB"), // 超大数据
TestData::new(1024, "1KB"), // Small data
TestData::new(8 * 1024, "8KB"), // Medium-small data
TestData::new(64 * 1024, "64KB"), // Medium data
TestData::new(256 * 1024, "256KB"), // Medium-large data
TestData::new(1024 * 1024, "1MB"), // Large data
TestData::new(4 * 1024 * 1024, "4MB"), // Extra large data
]
}
/// 编码性能比较基准测试
fn bench_encode_comparison(c: &mut Criterion) {
/// SIMD encoding performance analysis
fn bench_encode_analysis(c: &mut Criterion) {
let datasets = generate_test_datasets();
let configs = vec![
(4, 2, "4+2"), // 常用配置
(6, 3, "6+3"), // 50%冗余
(8, 4, "8+4"), // 50%冗余,更多分片
(4, 2, "4+2"), // Common configuration
(6, 3, "6+3"), // 50% redundancy
(8, 4, "8+4"), // 50% redundancy, more shards
];
for dataset in &datasets {
for (data_shards, parity_shards, config_name) in &configs {
let test_name = format!("{}_{}_{}", dataset.size_name, config_name, get_implementation_name());
let test_name = format!("{}_{}_{}", dataset.size_name, config_name, "simd");
let mut group = c.benchmark_group("encode_comparison");
let mut group = c.benchmark_group("encode_analysis");
group.throughput(Throughput::Bytes(dataset.data.len() as u64));
group.sample_size(20);
group.measurement_time(Duration::from_secs(10));
// 检查是否能够创建erasure实例(某些配置在纯SIMD模式下可能失败)
// Test SIMD encoding performance
match Erasure::new(*data_shards, *parity_shards, dataset.data.len()).encode_data(&dataset.data) {
Ok(_) => {
group.bench_with_input(
BenchmarkId::new("implementation", &test_name),
BenchmarkId::new("simd_encode", &test_name),
&(&dataset.data, *data_shards, *parity_shards),
|b, (data, data_shards, parity_shards)| {
let erasure = Erasure::new(*data_shards, *parity_shards, data.len());
@@ -82,7 +81,7 @@ fn bench_encode_comparison(c: &mut Criterion) {
);
}
Err(e) => {
println!("⚠️ 跳过测试 {} - 配置不支持: {}", test_name, e);
println!("⚠️ Skipping test {} - configuration not supported: {}", test_name, e);
}
}
group.finish();
@@ -90,35 +89,35 @@ fn bench_encode_comparison(c: &mut Criterion) {
}
}
/// 解码性能比较基准测试
fn bench_decode_comparison(c: &mut Criterion) {
/// SIMD decoding performance analysis
fn bench_decode_analysis(c: &mut Criterion) {
let datasets = generate_test_datasets();
let configs = vec![(4, 2, "4+2"), (6, 3, "6+3"), (8, 4, "8+4")];
for dataset in &datasets {
for (data_shards, parity_shards, config_name) in &configs {
let test_name = format!("{}_{}_{}", dataset.size_name, config_name, get_implementation_name());
let test_name = format!("{}_{}_{}", dataset.size_name, config_name, "simd");
let erasure = Erasure::new(*data_shards, *parity_shards, dataset.data.len());
// 预先编码数据 - 检查是否支持此配置
// Pre-encode data - check if this configuration is supported
match erasure.encode_data(&dataset.data) {
Ok(encoded_shards) => {
let mut group = c.benchmark_group("decode_comparison");
let mut group = c.benchmark_group("decode_analysis");
group.throughput(Throughput::Bytes(dataset.data.len() as u64));
group.sample_size(20);
group.measurement_time(Duration::from_secs(10));
group.bench_with_input(
BenchmarkId::new("implementation", &test_name),
BenchmarkId::new("simd_decode", &test_name),
&(&encoded_shards, *data_shards, *parity_shards),
|b, (shards, data_shards, parity_shards)| {
let erasure = Erasure::new(*data_shards, *parity_shards, dataset.data.len());
b.iter(|| {
// 模拟最大可恢复的数据丢失
// Simulate maximum recoverable data loss
let mut shards_opt: Vec<Option<Vec<u8>>> =
shards.iter().map(|shard| Some(shard.to_vec())).collect();
// 丢失等于奇偶校验分片数量的分片
// Lose up to parity_shards number of shards
for item in shards_opt.iter_mut().take(*parity_shards) {
*item = None;
}
@@ -131,33 +130,33 @@ fn bench_decode_comparison(c: &mut Criterion) {
group.finish();
}
Err(e) => {
println!("⚠️ 跳过解码测试 {} - 配置不支持: {}", test_name, e);
println!("⚠️ Skipping decode test {} - configuration not supported: {}", test_name, e);
}
}
}
}
}
/// 分片大小敏感性测试
fn bench_shard_size_sensitivity(c: &mut Criterion) {
/// Shard size sensitivity analysis for SIMD optimization
fn bench_shard_size_analysis(c: &mut Criterion) {
let data_shards = 4;
let parity_shards = 2;
// 测试不同的分片大小,特别关注SIMD的临界点
// Test different shard sizes, focusing on SIMD optimization thresholds
let shard_sizes = vec![32, 64, 128, 256, 512, 1024, 2048, 4096, 8192];
let mut group = c.benchmark_group("shard_size_sensitivity");
let mut group = c.benchmark_group("shard_size_analysis");
group.sample_size(15);
group.measurement_time(Duration::from_secs(8));
for shard_size in shard_sizes {
let total_size = shard_size * data_shards;
let data = (0..total_size).map(|i| (i % 256) as u8).collect::<Vec<u8>>();
let test_name = format!("{}B_shard_{}", shard_size, get_implementation_name());
let test_name = format!("{}B_shard_simd", shard_size);
group.throughput(Throughput::Bytes(total_size as u64));
// 检查此分片大小是否支持
// Check if this shard size is supported
let erasure = Erasure::new(data_shards, parity_shards, data.len());
match erasure.encode_data(&data) {
Ok(_) => {
@@ -170,15 +169,15 @@ fn bench_shard_size_sensitivity(c: &mut Criterion) {
});
}
Err(e) => {
println!("⚠️ 跳过分片大小测试 {} - 不支持: {}", test_name, e);
println!("⚠️ Skipping shard size test {} - not supported: {}", test_name, e);
}
}
}
group.finish();
}
/// 高负载并发测试
fn bench_concurrent_load(c: &mut Criterion) {
/// High-load concurrent performance analysis
fn bench_concurrent_analysis(c: &mut Criterion) {
use std::sync::Arc;
use std::thread;
@@ -186,14 +185,14 @@ fn bench_concurrent_load(c: &mut Criterion) {
let data = Arc::new((0..data_size).map(|i| (i % 256) as u8).collect::<Vec<u8>>());
let erasure = Arc::new(Erasure::new(4, 2, data_size));
let mut group = c.benchmark_group("concurrent_load");
let mut group = c.benchmark_group("concurrent_analysis");
group.throughput(Throughput::Bytes(data_size as u64));
group.sample_size(10);
group.measurement_time(Duration::from_secs(15));
let test_name = format!("1MB_concurrent_{}", get_implementation_name());
let test_name = "1MB_concurrent_simd";
group.bench_function(&test_name, |b| {
group.bench_function(test_name, |b| {
b.iter(|| {
let handles: Vec<_> = (0..4)
.map(|_| {
@@ -214,42 +213,44 @@ fn bench_concurrent_load(c: &mut Criterion) {
group.finish();
}
/// 错误恢复能力测试
fn bench_error_recovery_performance(c: &mut Criterion) {
let data_size = 256 * 1024; // 256KB
/// Error recovery performance analysis
fn bench_error_recovery_analysis(c: &mut Criterion) {
let data_size = 512 * 1024; // 512KB
let data = (0..data_size).map(|i| (i % 256) as u8).collect::<Vec<u8>>();
let configs = vec![
(4, 2, 1), // 丢失1个分片
(4, 2, 2), // 丢失2个分片(最大可恢复)
(6, 3, 2), // 丢失2个分片
(6, 3, 3), // 丢失3个分片(最大可恢复)
(8, 4, 3), // 丢失3个分片
(8, 4, 4), // 丢失4个分片(最大可恢复)
// Test different error recovery scenarios
let scenarios = vec![
(4, 2, 1, "single_loss"), // Lose 1 shard
(4, 2, 2, "double_loss"), // Lose 2 shards (maximum)
(6, 3, 1, "single_loss_6_3"), // Lose 1 shard with 6+3
(6, 3, 3, "triple_loss_6_3"), // Lose 3 shards (maximum)
(8, 4, 2, "double_loss_8_4"), // Lose 2 shards with 8+4
(8, 4, 4, "quad_loss_8_4"), // Lose 4 shards (maximum)
];
let mut group = c.benchmark_group("error_recovery");
let mut group = c.benchmark_group("error_recovery_analysis");
group.throughput(Throughput::Bytes(data_size as u64));
group.sample_size(15);
group.measurement_time(Duration::from_secs(8));
group.measurement_time(Duration::from_secs(10));
for (data_shards, parity_shards, lost_shards) in configs {
for (data_shards, parity_shards, loss_count, scenario_name) in scenarios {
let erasure = Erasure::new(data_shards, parity_shards, data_size);
let test_name = format!("{}+{}_lost{}_{}", data_shards, parity_shards, lost_shards, get_implementation_name());
// 检查此配置是否支持
match erasure.encode_data(&data) {
Ok(encoded_shards) => {
let test_name = format!("{}+{}_{}", data_shards, parity_shards, scenario_name);
group.bench_with_input(
BenchmarkId::new("recovery", &test_name),
&(&encoded_shards, data_shards, parity_shards, lost_shards),
|b, (shards, data_shards, parity_shards, lost_shards)| {
&(&encoded_shards, data_shards, parity_shards, loss_count),
|b, (shards, data_shards, parity_shards, loss_count)| {
let erasure = Erasure::new(*data_shards, *parity_shards, data_size);
b.iter(|| {
// Simulate specific number of shard losses
let mut shards_opt: Vec<Option<Vec<u8>>> = shards.iter().map(|shard| Some(shard.to_vec())).collect();
// 丢失指定数量的分片
for item in shards_opt.iter_mut().take(*lost_shards) {
// Lose the specified number of shards
for item in shards_opt.iter_mut().take(*loss_count) {
*item = None;
}
@@ -260,71 +261,57 @@ fn bench_error_recovery_performance(c: &mut Criterion) {
);
}
Err(e) => {
println!("⚠️ 跳过错误恢复测试 {} - 配置不支持: {}", test_name, e);
println!("⚠️ Skipping recovery test {}: {}", scenario_name, e);
}
}
}
group.finish();
}
/// 内存效率测试
fn bench_memory_efficiency(c: &mut Criterion) {
let data_shards = 4;
let parity_shards = 2;
let data_size = 1024 * 1024; // 1MB
/// Memory efficiency analysis
fn bench_memory_analysis(c: &mut Criterion) {
let data_sizes = vec![64 * 1024, 256 * 1024, 1024 * 1024]; // 64KB, 256KB, 1MB
let config = (4, 2); // 4+2 configuration
let mut group = c.benchmark_group("memory_efficiency");
group.throughput(Throughput::Bytes(data_size as u64));
group.sample_size(10);
let mut group = c.benchmark_group("memory_analysis");
group.sample_size(15);
group.measurement_time(Duration::from_secs(8));
let test_name = format!("memory_pattern_{}", get_implementation_name());
for data_size in data_sizes {
let data = (0..data_size).map(|i| (i % 256) as u8).collect::<Vec<u8>>();
let size_name = format!("{}KB", data_size / 1024);
// 测试连续多次编码对内存的影响
group.bench_function(format!("{}_continuous", test_name), |b| {
let erasure = Erasure::new(data_shards, parity_shards, data_size);
b.iter(|| {
for i in 0..10 {
let data = vec![(i % 256) as u8; data_size];
let shards = erasure.encode_data(black_box(&data)).unwrap();
group.throughput(Throughput::Bytes(data_size as u64));
// Test instance reuse vs new instance creation
group.bench_with_input(BenchmarkId::new("reuse_instance", &size_name), &data, |b, data| {
let erasure = Erasure::new(config.0, config.1, data.len());
b.iter(|| {
let shards = erasure.encode_data(black_box(data)).unwrap();
black_box(shards);
}
});
});
});
// 测试大量小编码任务
group.bench_function(format!("{}_small_chunks", test_name), |b| {
let chunk_size = 1024; // 1KB chunks
let erasure = Erasure::new(data_shards, parity_shards, chunk_size);
b.iter(|| {
for i in 0..1024 {
let data = vec![(i % 256) as u8; chunk_size];
let shards = erasure.encode_data(black_box(&data)).unwrap();
group.bench_with_input(BenchmarkId::new("new_instance", &size_name), &data, |b, data| {
b.iter(|| {
let erasure = Erasure::new(config.0, config.1, data.len());
let shards = erasure.encode_data(black_box(data)).unwrap();
black_box(shards);
}
});
});
});
}
group.finish();
}
/// 获取当前实现的名称
fn get_implementation_name() -> &'static str {
#[cfg(feature = "reed-solomon-simd")]
return "hybrid";
#[cfg(not(feature = "reed-solomon-simd"))]
return "erasure";
}
// Benchmark group configuration
criterion_group!(
benches,
bench_encode_comparison,
bench_decode_comparison,
bench_shard_size_sensitivity,
bench_concurrent_load,
bench_error_recovery_performance,
bench_memory_efficiency
bench_encode_analysis,
bench_decode_analysis,
bench_shard_size_analysis,
bench_concurrent_analysis,
bench_error_recovery_analysis,
bench_memory_analysis
);
criterion_main!(benches);