#![allow(dead_code)]
use std::sync::atomic::{AtomicU64, Ordering};
pub fn emit_marker(name: &str) {
use std::io::Write;
write_fifo(|f, us| {
drop((&*f).write_all(format!("{us} {name}\n").as_bytes()));
});
}
pub fn emit_counter(name: &str, value: i64) {
use std::io::Write;
write_fifo(|f, us| {
drop((&*f).write_all(format!("{us} @{name}={value}\n").as_bytes()));
});
}
pub fn emit_counter_u64(name: &str, value: u64) {
emit_counter(name, i64::try_from(value).unwrap_or(i64::MAX));
}
pub fn emit_counter_usize(name: &str, value: usize) {
emit_counter(name, i64::try_from(value).unwrap_or(i64::MAX));
}
macro_rules! counter_group {
($struct_name:ident { $($field:ident => $name:literal),* $(,)? }) => {
pub struct $struct_name {
$(pub $field: AtomicU64,)*
}
impl $struct_name {
const fn new() -> Self {
Self { $($field: AtomicU64::new(0),)* }
}
fn emit(&self) {
$(
let ns = self.$field.load(Ordering::Relaxed);
if ns > 0 {
emit_counter_u64($name, ns);
}
)*
}
}
};
}
counter_group!(WaitCounters {
sort_chunk_write => "sort_chunk_write_wait_ns",
sort_flush => "sort_flush_wait_ns",
sort_open => "sort_open_wait_ns",
sort_finish => "sort_finish_wait_ns",
assemble_partition_batch => "assemble_partition_batch_wait_ns",
assemble_claim_window => "assemble_claim_window_wait_ns",
assemble_reader_backpressure => "assemble_reader_backpressure_wait_ns",
assemble_writer_backpressure => "assemble_writer_backpressure_wait_ns",
assemble_encode_input => "assemble_encode_input_wait_ns",
assemble_encode_backpressure => "assemble_encode_backpressure_wait_ns",
assemble_write_input => "assemble_write_input_wait_ns",
assemble_reader_join => "assemble_reader_join_wait_ns",
assemble_writer_join => "assemble_writer_join_wait_ns",
pmtiles_write => "pmtiles_write_wait_ns",
way_block_send => "way_block_send_wait_ns",
way_budget => "way_budget_wait_ns",
way_result_send => "way_result_send_wait_ns",
node_block_send => "node_block_send_wait_ns",
node_worker_join => "node_worker_join_wait_ns",
prepass_join => "prepass_join_wait_ns",
input_hash_join => "input_hash_join_wait_ns",
read_raw_send => "read_raw_send_wait_ns",
read_decoded_send => "read_decoded_send_wait_ns",
read_decoded_recv => "read_decoded_recv_wait_ns",
});
counter_group!(RingCapCounters {
partitions => "ring_cap_partitions",
pieces => "ring_cap_pieces",
});
counter_group!(BusyCounters {
phase12_node_blocks => "phase12_node_blocks_ns",
phase12_plan_build => "phase12_plan_build_ns",
phase12_drain => "phase12_drain_ns",
phase12_relation_tail => "phase12_relation_tail_ns",
});
pub static WAIT: WaitCounters = WaitCounters::new();
pub static BUSY: BusyCounters = BusyCounters::new();
pub static RING_CAP: RingCapCounters = RingCapCounters::new();
pub fn emit_wait_counters() {
WAIT.emit();
BUSY.emit();
RING_CAP.emit();
}
pub struct WaitSpan {
counter: &'static AtomicU64,
start: std::time::Instant,
}
impl Drop for WaitSpan {
fn drop(&mut self) {
let ns = u64::try_from(self.start.elapsed().as_nanos()).unwrap_or(u64::MAX);
self.counter.fetch_add(ns, Ordering::Relaxed);
}
}
#[must_use]
pub fn wait_span(counter: &'static AtomicU64) -> WaitSpan {
WaitSpan {
counter,
start: std::time::Instant::now(),
}
}
#[cfg(all(target_os = "linux", target_env = "gnu"))]
pub fn emit_alloc_boundary(boundary: &str) {
let info = unsafe { libc::mallinfo2() };
emit_counter_usize(&format!("malloc_held_{boundary}"), info.arena + info.hblkhd);
emit_counter_usize(
&format!("malloc_live_{boundary}"),
info.uordblks + info.hblkhd,
);
}
#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
pub fn emit_alloc_boundary(_boundary: &str) {}
#[cfg(all(target_os = "linux", target_env = "gnu"))]
pub fn malloc_trim() -> i32 {
unsafe { libc::malloc_trim(0) }
}
#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
pub fn malloc_trim() -> i32 {
0
}
#[cfg(all(target_os = "linux", target_env = "gnu"))]
pub fn set_mmap_threshold(bytes: i32) -> i32 {
unsafe { libc::mallopt(libc::M_MMAP_THRESHOLD, bytes) }
}
#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
pub fn set_mmap_threshold(_bytes: i32) -> i32 {
0
}
#[cfg(target_os = "linux")]
pub fn read_page_faults() -> (u64, u64) {
let Ok(stat) = std::fs::read_to_string("/proc/self/stat") else {
return (0, 0);
};
let mut fields = stat.split_whitespace();
let minflt = fields
.nth(9)
.and_then(|s| s.parse::<u64>().ok())
.unwrap_or(0);
let majflt = fields
.nth(1)
.and_then(|s| s.parse::<u64>().ok())
.unwrap_or(0);
(minflt, majflt)
}
#[cfg(not(target_os = "linux"))]
pub fn read_page_faults() -> (u64, u64) {
(0, 0)
}
fn write_fifo(f: impl FnOnce(&std::fs::File, u128)) {
use std::sync::OnceLock;
static STATE: OnceLock<Option<(std::fs::File, std::time::Instant)>> = OnceLock::new();
let state = STATE.get_or_init(|| {
let path = std::env::var("BROKKR_MARKER_FIFO").ok()?;
#[cfg(unix)]
{
use std::os::unix::fs::OpenOptionsExt;
#[cfg(target_os = "linux")]
const O_NONBLOCK: i32 = 0x800;
#[cfg(target_os = "macos")]
const O_NONBLOCK: i32 = 0x0004;
let file = std::fs::OpenOptions::new()
.write(true)
.custom_flags(O_NONBLOCK)
.open(&path)
.ok()?;
Some((file, std::time::Instant::now()))
}
#[cfg(not(unix))]
{
let _ = path;
None
}
});
if let Some((file, start)) = state.as_ref() {
let us = start.elapsed().as_micros();
f(file, us);
}
}