Skip to content

Improve the documentation of the memory block size growth feature #263

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

Merged
merged 2 commits into from
Feb 4, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 32 additions & 14 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,20 +278,27 @@ impl Default for AllocatorDebugSettings {

/// The sizes of the memory blocks that the allocator will create.
///
/// Useful for tuning the allocator to your application's needs. For example most games will be fine with the defaultsize
/// Useful for tuning the allocator to your application's needs. For example most games will be fine with the default
/// values, but eg. an app might want to use smaller block sizes to reduce the amount of memory used.
///
/// Clamped between 4MB and 256MB, and rounds up to the nearest multiple of 4MB for alignment reasons.
///
/// Note that these limits only apply to shared memory blocks that can hold multiple allocations.
/// If an allocation does not fit within the corresponding maximum block size, it will be placed
/// in a dedicated memory block holding only this allocation, without limitations other than what
/// the underlying hardware and driver are able to provide.
Comment on lines +286 to +289
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not something to fix in this PR, nor to mention in the documentation, but I think there's currently a mistake where we allocate such a "dedicated memory block" directly also if the minimum size didn't yet grow to the maximum size:

let memblock_size = allocation_sizes.get_memblock_size(is_host, self.active_general_blocks);
let size = desc.requirements.size;
let alignment = desc.requirements.alignment;
let dedicated_allocation = desc.allocation_scheme != AllocationScheme::GpuAllocatorManaged;
let requires_personal_block = size > memblock_size;

But fixing that in whichever way (i.e. let requires_personal_block = size > allocation_sizes.max_xxx_memblock_size;) might only make the code more confusing, as we'd have to either immediately allocate all blocks up until a block that would fit, or find the smallest multiple between min..max where that allocation would fit (that's a shared and not dedicated block).

///
/// # Fixed or growable block size
///
/// This structure represents ranges of allowed sizes for shared memory blocks.
/// By default, If the bounds of a given range are equal, the allocator will
/// be configured to used a fixed memory block size for shared allocations.
/// By default, if the upper bounds are not extended using `with_max_*_memblock_size`,
/// the allocator will be configured to use a fixed memory block size for shared
/// allocations.
///
/// Otherwise, the allocator will pick a memory block size within the specifed
/// range, dependending on the number of existing allocations for the memory
/// range, depending on the number of existing allocations for the memory
/// type.
///
/// As a rule of thumb, the allocator will start with the minimum block size
/// and double the size with each new allocation, up to the specified maximum
/// block size. This growth is tracked independently for each memory type.
Expand All @@ -315,28 +322,36 @@ impl Default for AllocatorDebugSettings {
/// ```
#[derive(Clone, Copy, Debug)]
pub struct AllocationSizes {
/// The initial size of the memory blocks that will be created for the GPU only memory type.
/// The initial size for device memory blocks.
///
/// The size of new device memory blocks doubles each time a new block is needed, up to
/// [`AllocationSizes::max_device_memblock_size`].
///
/// Defaults to 256MB.
min_device_memblock_size: u64,
/// The size of device memory blocks doubles each time a new allocation is needed, up to
/// `device_maximum_memblock_size`.
/// The maximum size for device memory blocks.
///
/// Defaults to the value of [`AllocationSizes::min_device_memblock_size`].
max_device_memblock_size: u64,
/// The size of the memory blocks that will be created for the CPU visible memory types.
/// The initial size for host memory blocks.
///
/// The size of new host memory blocks doubles each time a new block is needed, up to
/// [`AllocationSizes::max_host_memblock_size`].
///
/// Defaults to 64MB.
min_host_memblock_size: u64,
/// The size of host memory blocks doubles each time a new allocation is needed, up to
/// `host_maximum_memblock_size`.
/// The maximum size for host memory blocks.
///
/// Defaults to the value of [`AllocationSizes::min_host_memblock_size`].
max_host_memblock_size: u64,
}

impl AllocationSizes {
/// Sets the minimum device and host memory block sizes.
///
/// The maximum block sizes are initialized to the minimum sizes and
/// can be changed using `with_max_device_memblock_size` and
/// `with_max_host_memblock_size`.
/// can be increased using [`AllocationSizes::with_max_device_memblock_size`] and
/// [`AllocationSizes::with_max_host_memblock_size`].
pub fn new(device_memblock_size: u64, host_memblock_size: u64) -> Self {
let device_memblock_size = Self::adjust_memblock_size(device_memblock_size, "Device");
let host_memblock_size = Self::adjust_memblock_size(host_memblock_size, "Host");
Expand Down Expand Up @@ -385,8 +400,11 @@ impl AllocationSizes {
}

/// Used internally to decide the size of a shared memory block
/// based withing the allowed range, based on the number of
/// existing allocations
/// based within the allowed range, based on the number of
/// existing allocations. The more blocks there already are
/// (where the requested allocation didn't fit), the larger
/// the returned memory block size is going to be (up to
/// `max_*_memblock_size`).
pub(crate) fn get_memblock_size(&self, is_host: bool, count: usize) -> u64 {
let (min_size, max_size) = if is_host {
(self.min_host_memblock_size, self.max_host_memblock_size)
Expand Down