macro_rules! stages {
($($(#[$doc:meta])* $name:ident),* $(,)?) => {
$(
$(#[$doc])*
#[inline(never)]
#[allow(dead_code)]
pub(crate) fn $name<R>(f: impl FnOnce() -> R) -> R {
#[cfg(feature = "alloc-stats")]
let start = stats::enter();
let result = f();
#[cfg(feature = "alloc-stats")]
stats::leave(stringify!($name), start);
result
}
)*
pub const STAGES: &[&str] = &[$(stringify!($name)),*];
};
}
stages! {
rows,
merge,
write_schema,
rewrite,
materialise,
reorder,
avro,
normalise,
}
#[cfg(feature = "alloc-stats")]
pub use stats::{take_stats, Counting, StageAllocs};
#[cfg(feature = "alloc-stats")]
mod stats {
use std::alloc::{GlobalAlloc, Layout};
use std::sync::atomic::{AtomicU64, Ordering::Relaxed};
use std::sync::Mutex;
static ALLOCS: AtomicU64 = AtomicU64::new(0);
static BYTES: AtomicU64 = AtomicU64::new(0);
static LIVE: AtomicU64 = AtomicU64::new(0);
static PEAK: AtomicU64 = AtomicU64::new(0);
static STAGES: Mutex<Vec<StageAllocs>> = Mutex::new(Vec::new());
#[derive(Clone, Debug)]
pub struct StageAllocs {
pub stage: &'static str,
pub allocations: u64,
pub bytes: u64,
pub peak_live: u64,
}
pub fn take_stats() -> Vec<StageAllocs> {
std::mem::take(&mut *STAGES.lock().unwrap())
}
pub(super) fn enter() -> (u64, u64) {
PEAK.store(LIVE.load(Relaxed), Relaxed);
(ALLOCS.load(Relaxed), BYTES.load(Relaxed))
}
pub(super) fn leave(stage: &'static str, (allocations, bytes): (u64, u64)) {
STAGES.lock().unwrap().push(StageAllocs {
stage,
allocations: ALLOCS.load(Relaxed) - allocations,
bytes: BYTES.load(Relaxed) - bytes,
peak_live: PEAK.load(Relaxed),
});
}
fn grew(size: usize) {
ALLOCS.fetch_add(1, Relaxed);
BYTES.fetch_add(size as u64, Relaxed);
let live = LIVE.fetch_add(size as u64, Relaxed) + size as u64;
PEAK.fetch_max(live, Relaxed);
}
pub struct Counting;
unsafe impl GlobalAlloc for Counting {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
grew(layout.size());
unsafe { mimalloc::MiMalloc.alloc(layout) }
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
LIVE.fetch_sub(layout.size() as u64, Relaxed);
unsafe { mimalloc::MiMalloc.dealloc(ptr, layout) }
}
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
LIVE.fetch_sub(layout.size() as u64, Relaxed);
grew(new_size);
unsafe { mimalloc::MiMalloc.realloc(ptr, layout, new_size) }
}
}
}