use alloc::vec::Vec;
use crate::{MemoryPoolKind, MemoryScope};
use cubecl_runtime::{client::Client, runtime::Runtime};
const MIB: usize = 1024 * 1024;
const KEPT_SIZE: usize = 4 * MIB + 3;
pub fn relocation_moves_live_bytes_off_outdated_pages<R: Runtime>() {
let client = R::client(&Default::default());
client.memory_cleanup().expect("no stream records a graph");
let pattern = pattern(KEPT_SIZE);
let kept = client.create_from_slice(&pattern);
let (page_size, _) = adaptive(&client);
let large = client.empty(page_size as usize + MIB);
assert_eq!(adaptive(&client).1, 1, "`kept`'s page is outdated");
drop(large);
client.memory_cleanup().expect("no stream records a graph");
assert_eq!(adaptive(&client).1, 0, "the outdated pool is gone");
let bytes = client.read_one(kept).unwrap();
assert_eq!(bytes.len(), KEPT_SIZE, "the read-back ran");
assert_eq!(
&bytes[..],
&pattern[..],
"the bytes moved with the allocation"
);
}
pub fn a_held_read_back_keeps_its_allocation_in_place<R: Runtime>() {
let client = R::client(&Default::default());
client.memory_cleanup().expect("no stream records a graph");
let pattern = pattern(KEPT_SIZE);
let kept = client.create_from_slice(&pattern);
let read = client.read_one(kept.clone()).unwrap();
let (page_size, _) = adaptive(&client);
let large = client.empty(page_size as usize + MIB);
drop(large);
client.memory_cleanup().expect("no stream records a graph");
assert_eq!(
adaptive(&client).1,
1,
"the read-back's page stays where it is"
);
assert_eq!(
&read[..],
&pattern[..],
"the read-back still reads the bytes"
);
drop(read);
drop(client.empty(KEPT_SIZE));
client.memory_cleanup().expect("no stream records a graph");
assert_eq!(
adaptive(&client).1,
0,
"once the read-back goes, the allocation moves"
);
let bytes = client.read_one(kept).unwrap();
assert_eq!(&bytes[..], &pattern[..], "the bytes moved with it");
}
fn pattern(size: usize) -> Vec<u8> {
(0..size).map(|i| (i % 251) as u8).collect()
}
fn adaptive(client: &Client) -> (u64, u64) {
client
.memory_report(MemoryScope::CurrentStream)
.streams
.iter()
.flat_map(|stream| stream.pools.dynamic.iter())
.find_map(|pool| match pool.kind {
MemoryPoolKind::Adaptive {
page_size,
outdated_pages,
} => Some((page_size, outdated_pages)),
_ => None,
})
.expect("the default memory has an adaptive pool")
}