Add choice of Two-Level Segregated Fit and Linked List First Fit by trueb2 · Pull Request #78 · rust-embedded/embedded-alloc (original) (raw)

I did some tests on a nRF52840 dev kit. The linked list first fit was better most of the time, but there were some cases where TLSF was better. Most of the time linked list allocator was better in this simple scenario.

TLSF and Linked List were very similar overall, and TSLF was only better when allocating nearly all the memory. They both OOM'd with repeat(7) on the 175KiB heap.

TSLF
7.864685 INFO  Allocations: Avg 5429 Min 5401 Max 5798)
└─ allocator::____embassy_main_task::{async_fn#0} @ src/bin/allocator.rs:734 
7.864776 INFO  Frees: Avg 2415 Min 2380 Max 2593)
└─ allocator::____embassy_main_task::{async_fn#0} @ src/bin/allocator.rs:740 
8.650054 INFO  Allocations: Avg 5427 Min 5401 Max 5798)
└─ allocator::____embassy_main_task::{async_fn#0} @ src/bin/allocator.rs:734 
8.650146 INFO  Frees: Avg 2420 Min 2380 Max 2593)
└─ allocator::____embassy_main_task::{async_fn#0} @ src/bin/allocator.rs:740 


LLFF
56.462280 INFO  Allocations: Avg 5621 Min 5584 Max 6011)
└─ allocator::____embassy_main_task::{async_fn#0} @ src/bin/allocator.rs:734 
56.462371 INFO  Frees: Avg 2920 Min 2868 Max 3234)
└─ allocator::____embassy_main_task::{async_fn#0} @ src/bin/allocator.rs:740 
57.317413 INFO  Allocations: Avg 5624 Min 5584 Max 6011)
└─ allocator::____embassy_main_task::{async_fn#0} @ src/bin/allocator.rs:734 
57.317535 INFO  Frees: Avg 2920 Min 2868 Max 3143)
└─ allocator::____embassy_main_task::{async_fn#0} @ src/bin/allocator.rs:740 
let fake_random_numbers: [u8; 100] = [
    42, 17, 88, 33, 125, 5, 60, 72, 200, 94, 11, 77, 8, 39, 2, 50, 21, 99, 3, 150, 64, 19, 55, 7, 31, 240, 59, 12,
    101, 78, 23, 44, 61, 9, 37, 255, 70, 28, 6, 121, 14, 85, 16, 68, 1, 91, 45, 35, 22, 109, 27, 47, 73, 4, 29,
    200, 51, 13, 102, 8, 54, 36, 66, 10, 20, 76, 200, 90, 25, 69, 56, 30, 87, 18, 80, 49, 132, 63, 74, 24, 37, 57,
    98, 15, 89, 53, 32, 123, 67, 38, 58, 82, 111, 58, 48, 122, 81, 26, 43, 34,
];
let mut allocated = VecDeque::new();
let mut alloc_durations = Vec::new();
let mut free_durations = Vec::new();
loop {
    // Allocate randomly roughly between 4 and 1024 bytes
    for _ in 0..100 {
        let instant = Instant::now();
        for x in fake_random_numbers.repeat(6) {
            allocated.push_back(VecDeque::from(vec![x; x as usize * 4]));
        }
        alloc_durations.push(instant.elapsed().as_micros() as u32);
        let instant = Instant::now();
        allocated.drain(..allocated.len() - 10);
        free_durations.push(instant.elapsed().as_micros() as u32);
    }

    // Report stats
    info!("Allocations: Avg {:?} Min {:?} Max {:?})",
        alloc_durations.iter().sum::<u32>() / alloc_durations.len() as u32,
        alloc_durations.iter().min().unwrap(),
        alloc_durations.iter().max().unwrap(),
    );
    alloc_durations.clear();
    info!("Frees: Avg {:?} Min {:?} Max {:?})",
        free_durations.iter().sum::<u32>() / free_durations.len() as u32,
        free_durations.iter().min().unwrap(),
        free_durations.iter().max().unwrap(),
    );
    free_durations.clear();
}