diskann_disk/utils/instrumentation/
timer.rs1use std::time::{Duration, Instant};
6
7#[cfg(target_os = "linux")]
8mod linux;
9#[cfg(target_os = "linux")]
10use linux::{
11 get_number_of_processors, get_peak_workingset_size, get_process_cycle_time, get_process_time,
12 get_system_time,
13};
14#[cfg(target_os = "macos")]
15mod macos;
16#[cfg(target_os = "macos")]
17use macos::{
18 get_number_of_processors, get_peak_workingset_size, get_process_cycle_time, get_process_time,
19 get_system_time,
20};
21#[cfg(target_os = "windows")]
22mod windows;
23#[cfg(target_os = "windows")]
24use windows::{
25 get_number_of_processors, get_peak_workingset_size, get_process_cycle_time, get_process_time,
26 get_system_time,
27};
28
29#[derive(Clone)]
30pub struct Timer {
31 check_point: Instant,
32 cycles: Option<u64>,
33 start_process_time: Option<u64>,
34 start_system_time: Option<u64>,
35 number_of_processors: Option<u64>,
36}
37
38impl Default for Timer {
39 fn default() -> Self {
40 Self::new()
41 }
42}
43
44impl Timer {
45 pub fn new() -> Timer {
46 let cycles = get_process_cycle_time();
47 Timer {
48 check_point: Instant::now(),
49 cycles,
50 start_process_time: get_process_time(),
51 start_system_time: get_system_time(),
52 number_of_processors: get_number_of_processors(),
53 }
54 }
55
56 pub fn reset(&mut self) {
57 self.check_point = Instant::now();
58 self.cycles = get_process_cycle_time();
59 self.start_process_time = get_process_time();
60 self.start_system_time = get_system_time();
61 }
62
63 pub fn elapsed(&self) -> Duration {
64 Instant::now().duration_since(self.check_point)
65 }
66
67 pub fn elapsed_gcycles(&self) -> f32 {
68 let cur_cycles = get_process_cycle_time();
69 if let (Some(cur_cycles), Some(cycles)) = (cur_cycles, self.cycles) {
70 let spent_cycles =
71 ((cur_cycles - cycles) as f64 * 1.0f64) / (1024 * 1024 * 1024) as f64;
72 return spent_cycles as f32;
73 }
74
75 0.0
76 }
77
78 pub fn get_average_cpu_time_in_percents(&self) -> f64 {
80 let cur_process_time = get_process_time();
81 let cur_system_time = get_system_time();
82 if let (
83 Some(cur_process_time),
84 Some(cur_system_time),
85 Some(start_process_time),
86 Some(start_system_time),
87 Some(number_of_processors),
88 ) = (
89 cur_process_time,
90 cur_system_time,
91 self.start_process_time,
92 self.start_system_time,
93 self.number_of_processors,
94 ) {
95 let process_time_delta = cur_process_time - start_process_time;
96 let system_time_delta = cur_system_time - start_system_time;
97
98 if system_time_delta > 0 {
99 return (process_time_delta as f64) / (system_time_delta as f64)
100 * number_of_processors as f64
101 * 100f64;
102 }
103 }
104
105 0.0
106 }
107
108 pub fn get_peak_memory_usage(&self) -> f32 {
109 let memory_in_bytes = get_peak_workingset_size();
110 if let Some(bytes) = memory_in_bytes {
111 let memory_in_gbs = bytes as f64 / (1024 * 1024 * 1024) as f64;
112 return memory_in_gbs as f32;
113 }
114
115 0.0
116 }
117}
118
119#[cfg(test)]
120mod timer_tests {
121 use std::{thread, time};
122
123 use super::*;
124
125 #[test]
126 #[allow(clippy::if_same_then_else)]
127 fn test_new() {
128 let timer = Timer::new();
129 if cfg!(windows) {
130 assert!(timer.cycles.is_some());
131 } else if cfg!(target_os = "linux") {
132 assert!(timer.cycles.is_some());
133 } else if cfg!(target_os = "macos") {
134 assert!(timer.cycles.is_some());
135 } else {
136 panic!("No timer::test_new defined for current configuration");
137 }
138 }
139
140 #[test]
141 fn test_reset() {
142 let mut timer = Timer::new();
143 let checkpoint_before_reset = timer.check_point;
144
145 for _ in 0..10 {
146 timer.reset();
147 let checkpoint_after_reset = timer.check_point;
148 if checkpoint_after_reset > checkpoint_before_reset {
149 return;
150 }
151
152 thread::sleep(time::Duration::from_millis(10));
153 }
154
155 timer.reset();
156
157 assert!(
158 timer.check_point > checkpoint_before_reset,
159 "Timer::reset() did not update check_point"
160 );
161 }
162
163 #[test]
164 fn test_elapsed() {
165 let timer = Timer::new();
166 let t0 = timer.elapsed();
167
168 for _ in 0..10 {
169 let t1 = timer.elapsed();
170 if t1 > t0 {
171 return;
172 }
173
174 thread::sleep(time::Duration::from_millis(10));
175 }
176
177 assert!(
178 timer.elapsed() > t0,
179 "Timer::elapsed() did not increase over time"
180 );
181 }
182
183 #[test]
184 fn test_get_average_cpu_time_in_percents() {
185 let timer = Timer::new();
186 thread::sleep(time::Duration::from_millis(10));
187 assert!(timer.get_average_cpu_time_in_percents() >= 0f64);
188 }
189
190 #[test]
191 fn test_get_peak_memory_usage() {
192 let timer = Timer::new();
193 let peak_memory_usage = timer.get_peak_memory_usage();
194 assert!(peak_memory_usage >= 0.0);
195 }
196}