Files
jap_learn/benches/repo_cache_bench.rs
T

285 lines
8.6 KiB
Rust
Raw Normal View History

2026-08-25 15:46:39 +03:00
use criterion::{criterion_group, criterion_main, Criterion, BenchmarkId};
use std::collections::{BTreeMap, HashMap};
use std::hint::black_box;
use hashbrown::HashMap as HashbrownMap;
use rustc_hash::FxHashMap;
// Тестовая структура (аналог вашей сущности)
#[derive(Debug, Clone)]
struct Entity {
id: i64,
data: [u8; 64], // 64 байта данных для реалистичности
}
impl Entity {
fn new(id: i64) -> Self {
Self {
id,
data: [id as u8; 64],
}
}
}
// ========== ТЕСТОВЫЕ ФУНКЦИИ ==========
fn bench_vec_insert_sorted(vec: &mut Vec<Entity>, entities: &[Entity]) {
vec.clear();
for entity in entities {
vec.push(entity.clone());
}
// Vec уже отсортирован, так как ID монотонно возрастают
}
fn bench_vec_search_separated<'a>(ids: &[i64], vec: &'a [Entity], id: i64) -> Option<&'a Entity> {
match ids.binary_search(&id) {
Ok(index) => Some(&vec[index]),
Err(_) => None,
}
}
fn bench_vec_search(vec: &Vec<Entity>, id: i64) -> Option<&Entity> {
match vec.binary_search_by(|probe| probe.id.cmp(&id)) {
Ok(index) => Some(&vec[index]),
Err(_) => None,
}
}
fn bench_btreemap_insert(map: &mut BTreeMap<i64, Entity>, entities: &[Entity]) {
map.clear();
for entity in entities {
map.insert(entity.id, entity.clone());
}
}
fn bench_btreemap_search(map: &BTreeMap<i64, Entity>, id: i64) -> Option<&Entity> {
map.get(&id)
}
fn bench_hashmap_insert(map: &mut HashMap<i64, Entity>, entities: &[Entity]) {
map.clear();
for entity in entities {
map.insert(entity.id, entity.clone());
}
}
fn bench_hashmap_search(map: &HashMap<i64, Entity>, id: i64) -> Option<&Entity> {
map.get(&id)
}
fn bench_hashbrown_insert(map: &mut HashbrownMap<i64, Entity>, entities: &[Entity]) {
map.clear();
for entity in entities {
map.insert(entity.id, entity.clone());
}
}
fn bench_hashbrown_search(map: &HashbrownMap<i64, Entity>, id: i64) -> Option<&Entity> {
map.get(&id)
}
fn bench_fxhashmap_insert(map: &mut FxHashMap<i64, Entity>, entities: &[Entity]) {
map.clear();
for entity in entities {
map.insert(entity.id, entity.clone());
}
}
fn bench_fxhashmap_search(map: &FxHashMap<i64, Entity>, id: i64) -> Option<&Entity> {
map.get(&id)
}
// ========== ГЕНЕРАЦИЯ ДАННЫХ ==========
fn generate_entities(count: usize) -> Vec<Entity> {
(0..count).map(|i| Entity::new(i as i64)).collect()
}
fn generate_search_ids(count: usize, max_id: i64) -> Vec<i64> {
// 70% попаданий, 30% промахов (реалистичный сценарий)
let mut ids = Vec::with_capacity(count);
for i in 0..count {
if i % 10 < 7 {
// Попадание
ids.push((i as i64 * 13) % max_id);
} else {
// Промах (несуществующий ID)
ids.push(max_id + i as i64);
}
}
ids
}
// ========== БЕНЧМАРКИ ==========
fn bench_insert(c: &mut Criterion) {
let mut group = c.benchmark_group("insert");
for size in [10_000, 100_000, 500_000] {
let entities = generate_entities(size);
group.bench_with_input(BenchmarkId::new("Vec (sorted)", size), &entities, |b, entities| {
let mut vec = Vec::with_capacity(size);
b.iter(|| {
bench_vec_insert_sorted(&mut vec, black_box(entities));
});
});
group.bench_with_input(BenchmarkId::new("BTreeMap", size), &entities, |b, entities| {
let mut map = BTreeMap::new();
b.iter(|| {
bench_btreemap_insert(&mut map, black_box(entities));
});
});
group.bench_with_input(BenchmarkId::new("HashMap (std)", size), &entities, |b, entities| {
let mut map = HashMap::new();
b.iter(|| {
bench_hashmap_insert(&mut map, black_box(entities));
});
});
group.bench_with_input(BenchmarkId::new("HashMap (hashbrown)", size), &entities, |b, entities| {
let mut map = HashbrownMap::new();
b.iter(|| {
bench_hashbrown_insert(&mut map, black_box(entities));
});
});
group.bench_with_input(BenchmarkId::new("FxHashMap", size), &entities, |b, entities| {
let mut map = FxHashMap::default();
b.iter(|| {
bench_fxhashmap_insert(&mut map, black_box(entities));
});
});
}
group.finish();
}
fn bench_search(c: &mut Criterion) {
let mut group = c.benchmark_group("search");
for size in [10_000, 100_000, 500_000] {
let entities = generate_entities(size);
let entity_ids = entities.iter().map(|entity| entity.id).collect::<Vec<_>>();
let search_ids = generate_search_ids(1000, size as i64);
// Подготовка коллекций
let mut vec = Vec::with_capacity(size);
bench_vec_insert_sorted(&mut vec, &entities);
let mut btreemap = BTreeMap::new();
bench_btreemap_insert(&mut btreemap, &entities);
let mut hashmap = HashMap::new();
bench_hashmap_insert(&mut hashmap, &entities);
let mut hashbrown = HashbrownMap::new();
bench_hashbrown_insert(&mut hashbrown, &entities);
let mut fxhashmap = FxHashMap::default();
bench_fxhashmap_insert(&mut fxhashmap, &entities);
group.bench_with_input(BenchmarkId::new("Vec (binary search)", size), &search_ids, |b, ids| {
b.iter(|| {
for &id in ids {
black_box(bench_vec_search_separated(&entity_ids, &vec, black_box(id)));
}
});
});
group.bench_with_input(BenchmarkId::new("Vec (binary search) separated", size), &search_ids, |b, ids| {
b.iter(|| {
for &id in ids {
black_box(bench_vec_search(&vec, black_box(id)));
}
});
});
group.bench_with_input(BenchmarkId::new("BTreeMap", size), &search_ids, |b, ids| {
b.iter(|| {
for &id in ids {
black_box(bench_btreemap_search(&btreemap, black_box(id)));
}
});
});
group.bench_with_input(BenchmarkId::new("HashMap (std)", size), &search_ids, |b, ids| {
b.iter(|| {
for &id in ids {
black_box(bench_hashmap_search(&hashmap, black_box(id)));
}
});
});
group.bench_with_input(BenchmarkId::new("HashMap (hashbrown)", size), &search_ids, |b, ids| {
b.iter(|| {
for &id in ids {
black_box(bench_hashbrown_search(&hashbrown, black_box(id)));
}
});
});
group.bench_with_input(BenchmarkId::new("FxHashMap", size), &search_ids, |b, ids| {
b.iter(|| {
for &id in ids {
black_box(bench_fxhashmap_search(&fxhashmap, black_box(id)));
}
});
});
}
group.finish();
}
fn bench_memory_efficiency(c: &mut Criterion) {
let mut group = c.benchmark_group("memory_efficiency");
let size = 100_000;
let entities = generate_entities(size);
group.bench_function("Vec memory", |b| {
b.iter(|| {
let mut vec = Vec::with_capacity(size);
bench_vec_insert_sorted(&mut vec, black_box(&entities));
black_box(vec);
});
});
group.bench_function("BTreeMap memory", |b| {
b.iter(|| {
let mut map = BTreeMap::new();
bench_btreemap_insert(&mut map, black_box(&entities));
black_box(map);
});
});
group.bench_function("HashMap (std) memory", |b| {
b.iter(|| {
let mut map = HashMap::new();
bench_hashmap_insert(&mut map, black_box(&entities));
black_box(map);
});
});
group.bench_function("HashMap (hashbrown) memory", |b| {
b.iter(|| {
let mut map = HashbrownMap::new();
bench_hashbrown_insert(&mut map, black_box(&entities));
black_box(map);
});
});
group.bench_function("FxHashMap memory", |b| {
b.iter(|| {
let mut map = FxHashMap::default();
bench_fxhashmap_insert(&mut map, black_box(&entities));
black_box(map);
});
});
group.finish();
}
criterion_group!(benches, bench_insert, bench_search, bench_memory_efficiency);
criterion_main!(benches);