comfy_core/
perf_counters.rs1use crate::*;
2
3static PERF_COUNTERS: Lazy<AtomicRefCell<PerfCounters>> =
4 Lazy::new(|| AtomicRefCell::new(PerfCounters::default()));
5
6static TIMINGS: Lazy<AtomicRefCell<Timings>> =
7 Lazy::new(|| AtomicRefCell::new(Timings::new()));
8
9pub struct TimingEntry {
10 pub history: egui::util::History<Duration>,
11 pub time: Instant,
12}
13
14pub struct Timings {
15 pub data: HashMap<&'static str, TimingEntry>,
16}
17
18impl Timings {
19 pub fn new() -> Self {
20 Self { data: HashMap::new() }
21 }
22
23 pub fn add_value(
24 &mut self,
25 name: &'static str,
26 value: Duration,
27 time: Instant,
28 ) {
29 let entry = self.data.entry(name).or_insert(TimingEntry {
30 history: egui::util::History::new(50..2000, 2.0),
31 time: Instant::now(),
32 });
33
34 entry.time = time;
35 entry.history.add(get_time(), value);
36 }
37
38 pub fn span(&mut self, name: &'static str) -> TimingGuard<'_> {
39 TimingGuard { timings: self, name, start: Instant::now() }
40 }
41}
42
43pub struct TimingGuard<'a> {
44 timings: &'a mut Timings,
45 name: &'static str,
46 start: Instant,
47}
48
49impl<'a> Drop for TimingGuard<'a> {
50 fn drop(&mut self) {
51 self.timings.add_value(self.name, self.start.elapsed(), self.start);
52 }
53}
54
55pub struct AtomicTimingGuard {
56 name: &'static str,
57 start: Instant,
58}
59
60impl Drop for AtomicTimingGuard {
61 fn drop(&mut self) {
62 TIMINGS.borrow_mut().add_value(
63 self.name,
64 self.start.elapsed(),
65 self.start,
66 );
67 }
68}
69
70pub fn timings() -> impl std::ops::Deref<Target = Timings> {
71 TIMINGS.borrow_mut()
72}
73
74pub fn timing_start(name: &'static str) -> AtomicTimingGuard {
75 AtomicTimingGuard { name, start: Instant::now() }
76}
77
78pub fn timings_add_value(name: &'static str, value: f32) {
80 TIMINGS.borrow_mut().add_value(
81 name,
82 Duration::from_secs_f32(value),
83 Instant::now(),
84 );
85}
86
87#[derive(Default)]
88pub struct PerfCounters {
89 pub counters: HashMap<Cow<'static, str>, Counter>,
91}
92
93#[derive(Default)]
94pub struct Counter {
95 pub count: u64,
96 pub decayed_average: f64,
97}
98
99impl PerfCounters {
100 pub fn global() -> AtomicRef<'static, PerfCounters> {
101 PERF_COUNTERS.borrow()
102 }
103
104 pub fn update_counter(
105 &mut self,
106 counter_name: impl Into<Cow<'static, str>>,
107 count: u64,
108 ) {
109 let counter = self.counters.entry(counter_name.into()).or_default();
110 counter.count = count;
111 }
112
113 pub fn new_frame(&mut self, delta: f64) {
114 for counter in self.counters.values_mut() {
115 let t = delta * 5.0;
116
117 counter.decayed_average = counter.decayed_average * (1.0 - t) +
118 (counter.count as f64) * t;
119
120 counter.count = 0;
121 }
122 }
123
124 pub fn get_counter(&self, counter_name: &str) -> (u64, f64) {
125 if let Some(counter) = self.counters.get(counter_name) {
126 (counter.count, counter.decayed_average)
127 } else {
128 (0, 0.0)
129 }
130 }
131
132 pub fn reset_counters(&mut self) {
133 self.counters.clear();
134 }
135}
136
137pub fn perf_counters_new_frame(delta: f64) {
138 let mut counters = PERF_COUNTERS.borrow_mut();
139 counters.new_frame(delta);
140}
141
142pub fn reset_perf_counters() {
143 let mut counters = PERF_COUNTERS.borrow_mut();
144 counters.reset_counters();
145}
146
147pub fn perf_counter(counter_name: impl Into<Cow<'static, str>>, count: u64) {
148 let mut counters = PERF_COUNTERS.borrow_mut();
149 counters.update_counter(counter_name, count);
150}
151
152pub fn perf_counter_inc(counter_name: impl Into<Cow<'static, str>>, inc: u64) {
153 let mut counters = PERF_COUNTERS.borrow_mut();
154 let counter_name_cow = counter_name.into();
155 let (current_value, _) = counters.get_counter(&counter_name_cow);
156 counters.update_counter(counter_name_cow, current_value + inc);
157}
158
159pub fn get_perf_counter(
160 counter_name: impl Into<Cow<'static, str>>,
161) -> (u64, f64) {
162 let counters = PERF_COUNTERS.borrow_mut();
163 counters.get_counter(&counter_name.into())
164}
165
166