packet_parser/timing/
mod.rs1#[cfg(feature = "parse_timing")]
2use std::default;
3
4#[cfg(feature = "parse_timing")]
6#[derive(Debug, Clone, Copy, Default)]
7pub struct ParseTiming {
8 pub l2_ns: u64,
9 pub l3_ns: u64,
10 pub l4_ns: u64,
11 pub l7_ns: u64,
12 pub total_ns: u64,
13}
14
15#[cfg(feature = "parse_timing")]
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
17pub enum LayerAttempt {
18 #[default]
19 Skipped = 0,
20 Ok = 1,
21 Unsupported = 2,
22}
23
24#[cfg(feature = "parse_timing")]
25#[derive(Debug, Clone, Copy, Default)]
26pub struct ParseReport {
27 pub timing: ParseTiming,
28 pub l3: LayerAttempt,
29 pub l4: LayerAttempt,
30 pub l7: LayerAttempt,
31}
32
33#[cfg(not(feature = "parse_timing"))]
34#[derive(Debug, Clone, Copy, Default)]
35pub struct ParseTiming;
36
37#[cfg(feature = "parse_timing")]
39#[inline(always)]
40pub fn now() -> std::time::Instant {
41 std::time::Instant::now()
42}
43
44#[cfg(feature = "parse_timing")]
45#[inline(always)]
46pub fn elapsed_ns(t0: std::time::Instant) -> u64 {
47 t0.elapsed().as_nanos() as u64
48}
49
50#[cfg(not(feature = "parse_timing"))]
51#[inline(always)]
52pub fn now() {}
53
54#[cfg(not(feature = "parse_timing"))]
55#[inline(always)]
56pub fn elapsed_ns(_: ()) -> u64 {
57 0
58}
59
60#[cfg(feature = "parse_timing")]
62#[macro_export]
63macro_rules! time_block_ns {
64 ($dst:expr, $body:block) => {{
65 let t0 = $crate::timing::now();
66 let out = $body;
67 *$dst = $crate::timing::elapsed_ns(t0);
68 out
69 }};
70}
71
72#[cfg(not(feature = "parse_timing"))]
73#[macro_export]
74macro_rules! time_block_ns {
75 ($dst:expr, $body:block) => {{
76 let _ = $dst;
77 $body
78 }};
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[cfg(feature = "parse_timing")]
86 #[test]
87 fn test_parse_timing_default() {
88 let timing = ParseTiming::default();
89
90 assert_eq!(timing.l2_ns, 0);
91 assert_eq!(timing.l3_ns, 0);
92 assert_eq!(timing.l4_ns, 0);
93 assert_eq!(timing.l7_ns, 0);
94 assert_eq!(timing.total_ns, 0);
95 }
96
97 #[cfg(feature = "parse_timing")]
98 #[test]
99 fn test_layer_attempt_default_is_skipped() {
100 let attempt = LayerAttempt::default();
101 assert_eq!(attempt, LayerAttempt::Skipped);
102 }
103
104 #[cfg(feature = "parse_timing")]
105 #[test]
106 fn test_layer_attempt_variants_values() {
107 assert_eq!(LayerAttempt::Skipped as u8, 0);
108 assert_eq!(LayerAttempt::Ok as u8, 1);
109 assert_eq!(LayerAttempt::Unsupported as u8, 2);
110 }
111
112 #[cfg(feature = "parse_timing")]
113 #[test]
114 fn test_parse_report_default() {
115 let report = ParseReport::default();
116
117 assert_eq!(report.timing.l2_ns, 0);
118 assert_eq!(report.timing.l3_ns, 0);
119 assert_eq!(report.timing.l4_ns, 0);
120 assert_eq!(report.timing.l7_ns, 0);
121 assert_eq!(report.timing.total_ns, 0);
122
123 assert_eq!(report.l3, LayerAttempt::Skipped);
124 assert_eq!(report.l4, LayerAttempt::Skipped);
125 assert_eq!(report.l7, LayerAttempt::Skipped);
126 }
127
128 #[cfg(feature = "parse_timing")]
129 #[test]
130 fn test_now_and_elapsed_ns() {
131 let t0 = now();
132 let elapsed = elapsed_ns(t0);
133
134 assert!(elapsed <= u64::MAX);
135 }
136
137 #[cfg(feature = "parse_timing")]
138 #[test]
139 fn test_elapsed_ns_is_non_zero_after_work() {
140 let t0 = now();
141
142 let mut acc = 0u64;
143 for i in 0..10_000 {
144 acc = acc.wrapping_add(i);
145 }
146
147 let elapsed = elapsed_ns(t0);
148
149 assert!(acc > 0);
150 assert!(elapsed > 0);
151 }
152
153 #[cfg(feature = "parse_timing")]
154 #[test]
155 fn test_time_block_ns_sets_duration_and_returns_value() {
156 let mut measured = 0u64;
157
158 let result = time_block_ns!(&mut measured, {
159 let mut sum = 0u64;
160 for i in 0..1_000 {
161 sum += i;
162 }
163 sum
164 });
165
166 assert_eq!(result, (0..1_000u64).sum::<u64>());
167 assert!(measured > 0);
168 }
169
170 #[cfg(feature = "parse_timing")]
171 #[test]
172 fn test_time_block_ns_with_unit_return() {
173 let mut measured = 0u64;
174 let mut value = 0u32;
175
176 time_block_ns!(&mut measured, {
177 value = 42;
178 });
179
180 assert_eq!(value, 42);
181 assert!(measured > 0);
182 }
183
184 #[cfg(not(feature = "parse_timing"))]
185 #[test]
186 fn test_parse_timing_default_without_feature() {
187 let _timing = ParseTiming;
188 }
189
190 #[cfg(not(feature = "parse_timing"))]
191 #[test]
192 fn test_now_without_feature() {
193 now();
194 let elapsed = elapsed_ns(());
195
196 assert_eq!(elapsed, 0);
197 }
198
199 #[cfg(not(feature = "parse_timing"))]
200 #[test]
201 fn test_time_block_ns_without_feature_returns_value_and_does_not_modify_dst() {
202 let mut measured = 123u64;
203
204 let result = time_block_ns!(&mut measured, {
205 let mut sum = 0u64;
206 for i in 0..10 {
207 sum += i;
208 }
209 sum
210 });
211
212 assert_eq!(result, 45);
213 assert_eq!(measured, 123);
214 }
215
216 #[cfg(not(feature = "parse_timing"))]
217 #[test]
218 fn test_time_block_ns_without_feature_with_unit_return() {
219 let mut measured = 999u64;
220 let value: u32;
221
222 time_block_ns!(&mut measured, {
223 value = 7;
224 });
225
226 assert_eq!(value, 7);
227 assert_eq!(measured, 999);
228 }
229}