1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//! Regression tests for the single-freelist + class-floor cache design.
//!
//! The chunk provider keeps at most one freelist per chunk type. The
//! freelist's "floor" class ratchets monotonically: chunks released
//! below the current floor are returned to the system, and any cached
//! chunks below the floor are evicted at the next floor bump.
#![cfg(feature = "stats")]
use multitude::Arena;
/// Bumping the cache class via successive refills should evict
/// previously cached small chunks, returning them to the system.
#[test]
fn cache_floor_evicts_smaller_chunks_on_bump() {
let arena: Arena = Arena::builder().build();
// Trigger several refills so the local-class ratchet advances.
// Each `alloc_slice_fill_with` of an increasing length forces a
// refill once the current chunk runs out, advancing the ratchet.
for class in 0..6_u32 {
// Allocate enough bytes to force a refill at the next-larger class.
let bytes = 256_usize << class;
let _slice = arena.alloc_slice_fill_with(bytes, |_| 0);
}
let stats = arena.stats();
// The provider should have allocated multiple normal chunks
// (one per refill), and most of the smaller ones should have been
// evicted (returned to the backing allocator) as the floor advanced.
assert!(stats.normal_chunks_allocated >= 1);
}
/// After enough refills to saturate the ratchet at class 7, the cache
/// floor is at class 7 and any newly released small chunk (e.g. an
/// oversized one-shot whose total happens to land on a smaller class
/// size) is returned to the system rather than cached.
#[test]
fn release_below_floor_bypasses_cache() {
let arena: Arena = Arena::builder().build();
// Drive the ratchet up to class 7 by issuing many shared-chunk refills.
for _ in 0..NUM_REFILLS {
// Each alloc_arc forces a small-chunk shared allocation if the
// current chunk runs out; cycling through these advances the ratchet.
let _a = arena.alloc_arc([0u32; 16]);
}
let stats = arena.stats();
// We expect a bounded number of chunks: ratchet saturates at class 7,
// and the cache holds at most one chunk per refill that hasn't been
// released yet. The point is that we don't accumulate `NUM_REFILLS`
// chunks worth of memory.
assert!(stats.normal_chunks_allocated <= NUM_REFILLS as u64);
}
const NUM_REFILLS: usize = 32;