use core::mem::size_of;
use super::{DecompositionStorage, TileDecodeContext};
use crate::Result;
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct WorkspaceBytes {
pub(crate) coefficients: usize,
pub(crate) channels: usize,
pub(crate) idwt: usize,
pub(crate) tier1: usize,
pub(crate) structure: usize,
}
impl WorkspaceBytes {
pub(crate) fn sample(
tile_ctx: &TileDecodeContext,
storage: &DecompositionStorage<'_>,
) -> Result<Self> {
Ok(Self {
coefficients: capacity_bytes::<f32>(storage.coefficients.capacity())
.saturating_add(capacity_bytes::<i64>(storage.coefficients_i64.capacity())),
channels: tile_ctx.retained_channel_bytes()?,
idwt: tile_ctx.idwt_capacity_bytes()?,
tier1: tile_ctx.tier1_capacity_bytes()?,
structure: structure_bytes(storage),
})
}
pub(crate) fn with_idwt(self, bytes: usize) -> Self {
Self {
idwt: self.idwt.saturating_add(bytes),
..self
}
}
pub(crate) fn with_structure(self, bytes: usize) -> Self {
Self {
structure: self.structure.saturating_add(bytes),
..self
}
}
#[cfg(feature = "parallel")]
pub(crate) fn with_tier1(self, bytes: usize) -> Self {
Self {
tier1: self.tier1.saturating_add(bytes),
..self
}
}
#[cfg(feature = "parallel")]
pub(crate) fn plus(self, other: Self) -> Self {
Self {
coefficients: self.coefficients.saturating_add(other.coefficients),
channels: self.channels.saturating_add(other.channels),
idwt: self.idwt.saturating_add(other.idwt),
tier1: self.tier1.saturating_add(other.tier1),
structure: self.structure.saturating_add(other.structure),
}
}
pub(crate) fn total(self) -> usize {
self.coefficients
.saturating_add(self.channels)
.saturating_add(self.idwt)
.saturating_add(self.tier1)
.saturating_add(self.structure)
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct WorkspacePeak(WorkspaceBytes);
impl WorkspacePeak {
pub(crate) fn record(&mut self, sample: WorkspaceBytes) {
if sample.total() > self.0.total() {
self.0 = sample;
}
}
pub(crate) fn bytes(self) -> WorkspaceBytes {
self.0
}
}
pub(crate) fn record_workspace(
tile_ctx: &mut TileDecodeContext,
storage: &DecompositionStorage<'_>,
extra_structure_bytes: usize,
) -> Result<()> {
let sample = WorkspaceBytes::sample(tile_ctx, storage)?.with_structure(extra_structure_bytes);
tile_ctx.debug_counters.workspace_peak.record(sample);
Ok(())
}
fn structure_bytes(storage: &DecompositionStorage<'_>) -> usize {
[
capacity_bytes::<super::Segment<'_>>(storage.segments.capacity()),
capacity_bytes::<super::Layer>(storage.layers.capacity()),
capacity_bytes::<super::CodeBlock>(storage.code_blocks.capacity()),
capacity_bytes::<super::Precinct>(storage.precincts.capacity()),
capacity_bytes::<super::TagNode>(storage.tag_tree_nodes.capacity()),
capacity_bytes::<super::SubBand>(storage.sub_bands.capacity()),
capacity_bytes::<super::Decomposition>(storage.decompositions.capacity()),
capacity_bytes::<super::TileDecompositions>(storage.tile_decompositions.capacity()),
]
.into_iter()
.fold(0, usize::saturating_add)
}
fn capacity_bytes<T>(capacity: usize) -> usize {
capacity.saturating_mul(size_of::<T>())
}