@@ -273,62 +273,138 @@ impl Default for AllocatorDebugSettings {
273
273
274
274
/// The sizes of the memory blocks that the allocator will create.
275
275
///
276
- /// Useful for tuning the allocator to your application's needs. For example most games will be fine with the default
276
+ /// Useful for tuning the allocator to your application's needs. For example most games will be fine with the defaultsize
277
277
/// values, but eg. an app might want to use smaller block sizes to reduce the amount of memory used.
278
278
///
279
279
/// Clamped between 4MB and 256MB, and rounds up to the nearest multiple of 4MB for alignment reasons.
280
+ ///
281
+ /// # Fixed or growable block size
282
+ ///
283
+ /// This structure represents ranges of allowed sizes for shared memory blocks.
284
+ /// By default, If the bounds of a given range are equal, the allocator will
285
+ /// be configured to used a fixed memory block size for shared allocations.
286
+ ///
287
+ /// Otherwise, the allocator will pick a memory block size within the specifed
288
+ /// range, dependending on the number of existing allocations for the memory
289
+ /// type.
290
+ /// As a rule of thumb, the allocator will start with the minimum block size
291
+ /// and double the size with each new allocation, up to the specified maximum
292
+ /// block size. This growth is tracked independently for each memory type.
293
+ /// The block size also decreases when blocks are deallocated.
294
+ ///
295
+ /// # Example
296
+ ///
297
+ /// ```
298
+ /// use gpu_allocator::AllocationSizes;
299
+ /// const MB: u64 = 1024 * 1024;
300
+ /// // This configuration uses fixed memory block sizes.
301
+ /// let fixed = AllocationSizes::new(256 * MB, 64 * MB);
302
+ ///
303
+ /// // This configuration starts with 8MB memory blocks
304
+ /// // and grows the block size of a given memory type each
305
+ /// // time a new allocation is needed, up to a limit of
306
+ /// // 256MB for device memory and 64MB for host memory.
307
+ /// let growing = AllocationSizes::new(8 * MB, 8 * MB)
308
+ /// .with_max_device_memblock_size(256 * MB)
309
+ /// .with_max_host_memblock_size(64 * MB);
310
+ /// ```
280
311
#[ derive( Clone , Copy , Debug ) ]
281
312
pub struct AllocationSizes {
282
- /// The size of the memory blocks that will be created for the GPU only memory type.
313
+ /// The initial size of the memory blocks that will be created for the GPU only memory type.
283
314
///
284
315
/// Defaults to 256MB.
285
- device_memblock_size : u64 ,
316
+ min_device_memblock_size : u64 ,
317
+ /// The size of device memory blocks doubles each time a new allocation is needed, up to
318
+ /// `device_maximum_memblock_size`.
319
+ max_device_memblock_size : u64 ,
286
320
/// The size of the memory blocks that will be created for the CPU visible memory types.
287
321
///
288
322
/// Defaults to 64MB.
289
- host_memblock_size : u64 ,
323
+ min_host_memblock_size : u64 ,
324
+ /// The size of host memory blocks doubles each time a new allocation is needed, up to
325
+ /// `host_maximum_memblock_size`.
326
+ max_host_memblock_size : u64 ,
290
327
}
291
328
292
329
impl AllocationSizes {
330
+ /// Sets the minimum device and host memory block sizes.
331
+ ///
332
+ /// The maximum block sizes are initialized to the minimum sizes and
333
+ /// can be changed using `with_max_device_memblock_size` and
334
+ /// `with_max_host_memblock_size`.
293
335
pub fn new ( device_memblock_size : u64 , host_memblock_size : u64 ) -> Self {
294
- const FOUR_MB : u64 = 4 * 1024 * 1024 ;
295
- const TWO_HUNDRED_AND_FIFTY_SIX_MB : u64 = 256 * 1024 * 1024 ;
296
-
297
- let mut device_memblock_size =
298
- device_memblock_size. clamp ( FOUR_MB , TWO_HUNDRED_AND_FIFTY_SIX_MB ) ;
299
- let mut host_memblock_size =
300
- host_memblock_size. clamp ( FOUR_MB , TWO_HUNDRED_AND_FIFTY_SIX_MB ) ;
336
+ let device_memblock_size = Self :: adjust_memblock_size ( device_memblock_size, "Device" ) ;
337
+ let host_memblock_size = Self :: adjust_memblock_size ( host_memblock_size, "Host" ) ;
301
338
302
- if device_memblock_size % FOUR_MB != 0 {
303
- let val = device_memblock_size / FOUR_MB + 1 ;
304
- device_memblock_size = val * FOUR_MB ;
305
- log:: warn!(
306
- "Device memory block size must be a multiple of 4MB, clamping to {}MB" ,
307
- device_memblock_size / 1024 / 1024
308
- )
339
+ Self {
340
+ min_device_memblock_size : device_memblock_size,
341
+ max_device_memblock_size : device_memblock_size,
342
+ min_host_memblock_size : host_memblock_size,
343
+ max_host_memblock_size : host_memblock_size,
309
344
}
345
+ }
310
346
311
- if host_memblock_size % FOUR_MB != 0 {
312
- let val = host_memblock_size / FOUR_MB + 1 ;
313
- host_memblock_size = val * FOUR_MB ;
314
- log:: warn!(
315
- "Host memory block size must be a multiple of 4MB, clamping to {}MB" ,
316
- host_memblock_size / 1024 / 1024
317
- )
318
- }
347
+ /// Sets the maximum device memblock size, in bytes.
348
+ pub fn with_max_device_memblock_size ( mut self , size : u64 ) -> Self {
349
+ self . max_device_memblock_size =
350
+ Self :: adjust_memblock_size ( size, "Device" ) . max ( self . min_device_memblock_size ) ;
319
351
320
- Self {
321
- device_memblock_size,
322
- host_memblock_size,
352
+ self
353
+ }
354
+
355
+ /// Sets the maximum host memblock size, in bytes.
356
+ pub fn with_max_host_memblock_size ( mut self , size : u64 ) -> Self {
357
+ self . max_host_memblock_size =
358
+ Self :: adjust_memblock_size ( size, "Host" ) . max ( self . min_host_memblock_size ) ;
359
+
360
+ self
361
+ }
362
+
363
+ fn adjust_memblock_size ( size : u64 , kind : & str ) -> u64 {
364
+ const MB : u64 = 1024 * 1024 ;
365
+
366
+ let size = size. clamp ( 4 * MB , 256 * MB ) ;
367
+
368
+ if size % ( 4 * MB ) == 0 {
369
+ return size;
323
370
}
371
+
372
+ let val = size / ( 4 * MB ) + 1 ;
373
+ let new_size = val * 4 * MB ;
374
+ log:: warn!(
375
+ "{kind} memory block size must be a multiple of 4MB, clamping to {}MB" ,
376
+ new_size / MB
377
+ ) ;
378
+
379
+ new_size
380
+ }
381
+
382
+ /// Used internally to decide the size of a shared memory block
383
+ /// based withing the allowed range, based on the number of
384
+ /// existing allocations
385
+ pub ( crate ) fn get_memblock_size ( & self , is_host : bool , count : usize ) -> u64 {
386
+ let ( min_size, max_size) = if is_host {
387
+ ( self . min_host_memblock_size , self . max_host_memblock_size )
388
+ } else {
389
+ ( self . min_device_memblock_size , self . max_device_memblock_size )
390
+ } ;
391
+
392
+ // The ranges are clamped to 4MB..256MB so we never need to
393
+ // shift by more than 7 bits. Clamping here to avoid having
394
+ // to worry about overflows.
395
+ let shift = count. min ( 7 ) as u64 ;
396
+ ( min_size << shift) . min ( max_size)
324
397
}
325
398
}
326
399
327
400
impl Default for AllocationSizes {
328
401
fn default ( ) -> Self {
402
+ const MB : u64 = 1024 * 1024 ;
329
403
Self {
330
- device_memblock_size : 256 * 1024 * 1024 ,
331
- host_memblock_size : 64 * 1024 * 1024 ,
404
+ min_device_memblock_size : 256 * MB ,
405
+ max_device_memblock_size : 256 * MB ,
406
+ min_host_memblock_size : 64 * MB ,
407
+ max_host_memblock_size : 64 * MB ,
332
408
}
333
409
}
334
410
}
0 commit comments