buddy-alloc icon indicating copy to clipboard operation
buddy-alloc copied to clipboard

Understanding the meaning of "available_bytes"

Open hellertime opened this issue 3 years ago • 2 comments

I built a simple test of the buddy-alloc, which builds a 1MiB heap, and tries to allocate all of it.

First thing I noticed is that the heap I end up with in the allocator is smaller than my 1MiB heap.

I think this is due to the base_ptr getting aligned past the start of my buffer, but I'd like to confirm that is the case, or if that isn't expected.

The second thing I noticed is that if I try to allocate all the available bytes, I get back a null pointer from the call to malloc, this I didn't expect, as the call to available_bytes claims I have this many bytes to allocate.

I may have overlooked some fixed overhead each allocation needs, although perhaps if there is such overhead, it would make sense for available_bytes to reflect that in its response?

Here is a small test case that highlights what I'm seeing:

use buddy_alloc::buddy_alloc::BuddyAlloc;
use buddy_alloc::BuddyAllocParam;

fn main() {
    let (layout, mut alloc) = unsafe {
        let layout = std::alloc::Layout::from_size_align_unchecked(1<<20, 4096);
        let data = std::alloc::alloc(layout) as *mut u8;
        let alloc = BuddyAlloc::new(BuddyAllocParam::new(data, layout.size(), layout.align()));
        (layout, alloc)
    };
    println!("layout size: {}. allocator size {}.", layout.size(), alloc.available_bytes());
    let ptr = alloc.malloc(alloc.available_bytes());
    assert!(! ptr.is_null());
    alloc.free(ptr);
}

hellertime avatar Jan 31 '23 17:01 hellertime

Further digging I come up with this program which highlights things a bit more clearly:

use buddy_alloc::buddy_alloc::BuddyAlloc;
use buddy_alloc::BuddyAllocParam;

fn main() {
    let (layout, mut alloc) = unsafe {
        let layout = std::alloc::Layout::from_size_align_unchecked(1<<20, 4096);
        let data = std::alloc::alloc(layout) as *mut u8;
        let alloc = BuddyAlloc::new(BuddyAllocParam::new(data, layout.size(), layout.align()));
        (layout, alloc)
    };
    println!("layout size: {}. allocator size {}.", layout.size(), alloc.available_bytes());
    let ptr = alloc.malloc((layout.align()/2)+1+(alloc.available_bytes() / 2));
    assert!(! ptr.is_null());
    alloc.free(ptr);
}

It would appear we can allocate up to (layout.align()/2)+(alloc.available_bytes() / 2) bytes from an empty allocator, but not one byte more. That makes sense given the buddy algorithm, but it still indicates that perhaps available_bytes is unclear in its purpose.

hellertime avatar Jan 31 '23 17:01 hellertime

IMO we can add comments to hint users. And we can add another function to return the maximum allocatable size.

/// Returns the maximum size that this allocator can allocate at once.
fn max_allocate_size()

/// Returns the number of bytes currently available for allocation by this allocator.
/// Note that, due to the buddy allocation algorithm used, the available bytes may 
/// not be able to allocate all at once.
fn available_bytes()

jjyr avatar Feb 28 '23 07:02 jjyr