///|
/// Estimated memory footprint of row-major simulation arrays.
pub(all) struct MemoryEstimate {
cells : Int
distribution_bytes : Int
next_bytes : Int
mask_bytes : Int
scalar_field_bytes : Int
vector_field_bytes : Int
total_bytes : Int
} derive(Debug)
///|
/// Estimate payload memory without hiding allocation overhead.
pub fn memory_estimate(size : Size) -> MemoryEstimate {
let cells = size.width.max(0) * size.height.max(0)
let distributions = cells * q * 8
let next = distributions
let mask = cells
let scalar = cells * 8
let vector = cells * 16
{
cells,
distribution_bytes: distributions,
next_bytes: next,
mask_bytes: mask,
scalar_field_bytes: scalar,
vector_field_bytes: vector,
total_bytes: distributions + next + mask + scalar + vector,
}
}
///|
/// Format a memory estimate in a readable form.
pub fn MemoryEstimate::to_string(self : MemoryEstimate) -> String {
"cells=\{self.cells}\ndistribution_bytes=\{self.distribution_bytes}\nnext_bytes=\{self.next_bytes}\nmask_bytes=\{self.mask_bytes}\nscalar_field_bytes=\{self.scalar_field_bytes}\nvector_field_bytes=\{self.vector_field_bytes}\ntotal_bytes=\{self.total_bytes}\n"
}
///|
/// Return the number of distribution values in a domain.
pub fn distribution_length(size : Size) -> Int {
size.width.max(0) * size.height.max(0) * q
}
///|
/// Convert bytes to mebibytes.
pub fn bytes_to_mebibytes(bytes : Int) -> Double {
bytes.to_double() / 1048576.0
}
///|
/// Return true when a domain has a safe positive allocation size.
pub fn size_is_allocatable(size : Size) -> Bool {
size.width > 0 && size.height > 0 && distribution_length(size) > 0
}
///|
/// Return an upper bound on bytes for a scalar/vector/checkpoint bundle.
pub fn bundle_memory_bytes(size : Size, checkpoints? : Int = 1) -> Int {
memory_estimate(size).total_bytes +
checkpoints.max(0) * distribution_length(size) * 16
}
///|
/// Return an upper bound on a square simulation footprint.
pub fn square_memory_estimate(side : Int) -> MemoryEstimate {
memory_estimate(Size::new(width=side, height=side))
}