ranim_render/
upload_probe.rs1use std::{
12 collections::BTreeMap,
13 sync::{
14 Mutex, OnceLock,
15 atomic::{AtomicU8, AtomicU64, Ordering},
16 },
17 time::Duration,
18};
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
23pub enum UploadMode {
24 #[default]
25 Off,
26 Count,
28}
29
30impl UploadMode {
31 fn from_env() -> Self {
32 match std::env::var("RANIM_PROFILE_UPLOAD").as_deref() {
33 Ok(v) if v == "1" || v == "count" || v == "true" => UploadMode::Count,
34 _ => UploadMode::Off,
35 }
36 }
37
38 fn as_u8(self) -> u8 {
39 match self {
40 UploadMode::Off => 0,
41 UploadMode::Count => 1,
42 }
43 }
44
45 fn from_u8(v: u8) -> Self {
46 match v {
47 1 => UploadMode::Count,
48 _ => UploadMode::Off,
49 }
50 }
51
52 pub fn enabled(self) -> bool {
53 self != UploadMode::Off
54 }
55}
56
57static MODE: AtomicU8 = AtomicU8::new(u8::MAX);
59static MODE_SEEDED: OnceLock<()> = OnceLock::new();
60
61pub fn mode() -> UploadMode {
64 if MODE_SEEDED.get().is_none() {
65 let _ = MODE_SEEDED.set(());
66 MODE.store(UploadMode::from_env().as_u8(), Ordering::Relaxed);
67 }
68 UploadMode::from_u8(MODE.load(Ordering::Relaxed))
69}
70
71pub fn set_mode(new_mode: UploadMode) {
74 mode(); MODE.store(new_mode.as_u8(), Ordering::Relaxed);
76}
77
78#[derive(Default)]
79struct Counters {
80 calls: AtomicU64,
82 bytes: AtomicU64,
84 written_bytes: AtomicU64,
86 cpu_ns: AtomicU64,
88}
89
90fn registry() -> &'static Mutex<BTreeMap<&'static str, Counters>> {
91 static REG: OnceLock<Mutex<BTreeMap<&'static str, Counters>>> = OnceLock::new();
92 REG.get_or_init(|| Mutex::new(BTreeMap::new()))
93}
94
95fn label_or(label: Option<&'static str>) -> &'static str {
96 label.unwrap_or("<unnamed>")
97}
98
99pub(crate) fn record(label: Option<&'static str>, bytes: u64, written_bytes: u64, cpu_ns: u64) {
101 let mut reg = registry().lock().unwrap();
102 let c = reg.entry(label_or(label)).or_default();
103 c.calls.fetch_add(1, Ordering::Relaxed);
104 c.bytes.fetch_add(bytes, Ordering::Relaxed);
105 c.written_bytes.fetch_add(written_bytes, Ordering::Relaxed);
106 c.cpu_ns.fetch_add(cpu_ns, Ordering::Relaxed);
107}
108
109#[derive(Debug, Clone, Copy)]
111pub struct UploadStats {
112 pub calls: u64,
113 pub bytes: u64,
114 pub written_bytes: u64,
115 pub cpu_time: Duration,
116}
117
118pub fn take_stats() -> BTreeMap<&'static str, UploadStats> {
120 let mut reg = registry().lock().unwrap();
121 reg.iter_mut()
122 .map(|(&label, c)| {
123 (
124 label,
125 UploadStats {
126 calls: c.calls.swap(0, Ordering::Relaxed),
127 bytes: c.bytes.swap(0, Ordering::Relaxed),
128 written_bytes: c.written_bytes.swap(0, Ordering::Relaxed),
129 cpu_time: Duration::from_nanos(c.cpu_ns.swap(0, Ordering::Relaxed)),
130 },
131 )
132 })
133 .collect()
134}