axallocator 0.2.0

Various allocator algorithms in a unified interface
Documentation
#![feature(allocator_api)]
#![feature(btreemap_alloc)]

mod utils;

use std::alloc::Allocator;
use std::collections::BTreeMap;
use std::io::Write;

use allocator::{AllocatorRc, BuddyByteAllocator, SlabByteAllocator, TlsfByteAllocator};
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use rand::{rngs::SmallRng, seq::SliceRandom, RngCore, SeedableRng};

use self::utils::MemoryPool;

const POOL_SIZE: usize = 1024 * 1024 * 128;

fn vec_push(n: usize, alloc: &(impl Allocator + Clone)) {
    let mut v: Vec<u32, _> = Vec::new_in(alloc.clone());
    #[allow(clippy::same_item_push)]
    for _ in 0..n {
        v.push(0xdead_beef);
    }
    drop(v);
}

fn vec_rand_free(n: usize, blk_size: usize, alloc: &(impl Allocator + Clone)) {
    let mut v = Vec::new_in(alloc.clone());
    for _ in 0..n {
        let block = Vec::<u64, _>::with_capacity_in(blk_size, alloc.clone());
        v.push(block);
    }

    let mut rng = SmallRng::seed_from_u64(0xdead_beef);
    let mut index = Vec::with_capacity_in(n, alloc.clone());
    for i in 0..n {
        index.push(i);
    }
    index.shuffle(&mut rng);

    for i in index {
        v[i] = Vec::new_in(alloc.clone());
    }
    drop(v);
}

fn btree_map(n: usize, alloc: &(impl Allocator + Clone)) {
    let mut rng = SmallRng::seed_from_u64(0xdead_beef);
    let mut m = BTreeMap::new_in(alloc.clone());
    for _ in 0..n {
        if rng.next_u32() % 5 == 0 && !m.is_empty() {
            m.pop_first();
        } else {
            let value = rng.next_u32();
            let mut key = Vec::new_in(alloc.clone());
            write!(&mut key, "key_{value}").unwrap();
            m.insert(key, value);
        }
    }
    m.clear();
    drop(m);
}

fn bench(c: &mut Criterion, alloc_name: &str, alloc: impl Allocator + Clone) {
    let mut g = c.benchmark_group(alloc_name);
    g.bench_function("vec_push_3M", |b| {
        b.iter(|| vec_push(black_box(3_000_000), &alloc));
    });
    g.sample_size(10);
    g.bench_function("vec_rand_free_25K_64", |b| {
        b.iter(|| vec_rand_free(black_box(25_000), black_box(64), &alloc));
    });
    g.bench_function("vec_rand_free_7500_520", |b| {
        b.iter(|| vec_rand_free(black_box(7_500), black_box(520), &alloc));
    });
    g.bench_function("btree_map_50K", |b| {
        b.iter(|| btree_map(black_box(50_000), &alloc));
    });
}

fn criterion_benchmark(c: &mut Criterion) {
    let mut pool = MemoryPool::new(POOL_SIZE);
    bench(c, "system", std::alloc::System);
    bench(
        c,
        "tlsf",
        AllocatorRc::new(TlsfByteAllocator::new(), pool.as_slice()),
    );
    bench(
        c,
        "slab",
        AllocatorRc::new(SlabByteAllocator::new(), pool.as_slice()),
    );
    bench(
        c,
        "buddy",
        AllocatorRc::new(BuddyByteAllocator::new(), pool.as_slice()),
    );
}

criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);