-
Notifications
You must be signed in to change notification settings - Fork 57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add choice of Two-Level Segregated Fit and Linked List First Fit #78
Conversation
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.
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();
} |
Fixes #36 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm generally not a fan of mutually exclusive features when they can be avoided.
I think this could be implemented without the use of mutually exclusive features by implementing each type of allocator as a separate struct
, instead of one struct that conditionally implements either?
I think the choice of algorithm behind the global heap is a mutually exclusive decision. With all the changes since I opened this PR, the use of the crate may be changing. The implementation of the Heap struct could be separated to allow multiple heap types within the same crate. Which one implementation would be the global Heap would be ambiguous. |
All the conflicts are resolved again |
In deployment, I have found TLSF to be superior in latency and power consumption on the nRF52840 on all workloads.(wearable sensing + BLE platforms). Broadly, I see ~2-3% improvements, especially evident after days of runtime. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for all your work here!
Sorry for the slow review, work got very crazy recently.
This adds a feature choice of 'tlsf' or 'llff' to choose the global heap allocator implementation provided either by the current linked_list_allocator or rlsf.
This allows a user the crate to directly compare the two implementations by flipping the feature flag as long as the linked list free and used interface are not used.