From: Joshua Simmons Date: Mon, 29 May 2023 18:09:24 +0000 (+0200) Subject: narcissus-gpu: Document block splitting behavior X-Git-Url: https://git.nega.tv//gitweb.cgi?a=commitdiff_plain;h=7902cec243fa4a3eff0ae39466f773b426f8bc2e;p=josh%2Fnarcissus narcissus-gpu: Document block splitting behavior A relatively subtle part of the TLSF paper is the choice of size when splitting blocks as part of an allocation. Add a short comment and test. --- diff --git a/libs/narcissus-gpu/src/tlsf.rs b/libs/narcissus-gpu/src/tlsf.rs index 6508150..889939e 100644 --- a/libs/narcissus-gpu/src/tlsf.rs +++ b/libs/narcissus-gpu/src/tlsf.rs @@ -554,6 +554,16 @@ where self.extract_block(block_index); + // It's important to use the rounded size here, not the requested size. This + // avoids a failure case where freeing an allocation of a given size, fails + // to leave the allocator in a state where that block can be re-used for + // another allocation of the same size as the returned block can be placed into + // a smaller bin. + // + // We're trading arbitrary wasted blocks in this workload, for a small bounded + // amount of fragmentation. + // + // Tested in `tests::split_policy_avoids_memory_waste` let remainder = self.blocks[block_index].size - rounded_size; let super_block_index = self.blocks[block_index].super_block_index; @@ -712,6 +722,25 @@ mod tests { } } + #[test] + fn split_policy_avoids_memory_waste() { + let mut tlsf = Tlsf::new(); + tlsf.insert_super_block(1024, ()); + + let large_size = 990; + let small_size = 30; + + // Make a large allocation that splits the block. + let large = tlsf.alloc(large_size, 1).unwrap(); + // Make a small allocation to inhibit merging upon free. + tlsf.alloc(small_size, 1).unwrap(); + // Free the large block, if all goes well this will be added to a bin which is + // large enough to service another allocation of the same size. + tlsf.free(large); + // Allocate another large block, if this fails we've "lost" memory. + tlsf.alloc(large_size, 1).unwrap(); + } + #[test] #[should_panic] fn double_free() {