1#[cfg(all(feature = "std", feature = "benchmark-metrics"))]
2use std::sync::atomic::AtomicUsize;
3#[cfg(feature = "std")]
4use std::sync::atomic::Ordering;
5
6#[cfg(feature = "std")]
7#[derive(Debug, Default)]
8pub(crate) struct MetricCounter {
9 #[cfg(feature = "benchmark-metrics")]
10 value: AtomicUsize,
11}
12
13#[cfg(feature = "std")]
14impl MetricCounter {
15 #[inline]
16 fn load(&self, ordering: Ordering) -> usize {
17 #[cfg(feature = "benchmark-metrics")]
18 {
19 self.value.load(ordering)
20 }
21 #[cfg(not(feature = "benchmark-metrics"))]
22 {
23 let _ = ordering;
24 0
25 }
26 }
27
28 #[inline]
29 fn store(&self, value: usize, ordering: Ordering) {
30 #[cfg(feature = "benchmark-metrics")]
31 {
32 self.value.store(value, ordering);
33 }
34 #[cfg(not(feature = "benchmark-metrics"))]
35 {
36 let _ = (value, ordering);
37 }
38 }
39
40 #[inline]
41 pub(crate) fn fetch_add(&self, value: usize, ordering: Ordering) -> usize {
42 #[cfg(feature = "benchmark-metrics")]
43 {
44 self.value.fetch_add(value, ordering)
45 }
46 #[cfg(not(feature = "benchmark-metrics"))]
47 {
48 let _ = (value, ordering);
49 0
50 }
51 }
52}
53
54#[cfg(feature = "std")]
55#[derive(Debug, Default)]
56pub(crate) struct ReconstructionCacheMetrics {
57 pub(crate) requests: MetricCounter,
58 pub(crate) hits: MetricCounter,
59 pub(crate) misses: MetricCounter,
60 pub(crate) inserts: MetricCounter,
61 pub(crate) evictions: MetricCounter,
62}
63
64#[cfg(feature = "std")]
65#[derive(Debug, Default)]
66pub(crate) struct RuntimeProfileMetrics {
67 code_some_serial_calls: MetricCounter,
68 code_some_parallel_calls: MetricCounter,
69 code_some_total_bytes: MetricCounter,
70 code_some_total_chunks: MetricCounter,
71 code_some_small_output_chunk_parallel_calls: MetricCounter,
72 code_some_small_output_chunk_parallel_outputs: MetricCounter,
73 code_some_small_output_chunk_parallel_chunks: MetricCounter,
74 code_single_serial_calls: MetricCounter,
75 code_single_parallel_calls: MetricCounter,
76 code_single_total_bytes: MetricCounter,
77 code_single_total_chunks: MetricCounter,
78 parallel_policy_calls: MetricCounter,
79 parallel_policy_parallel: MetricCounter,
80 parallel_policy_serial: MetricCounter,
81 parallel_policy_total_jobs: MetricCounter,
82 parallel_policy_total_chunk_len: MetricCounter,
83 reconstruct_calls: MetricCounter,
84 reconstruct_data_only_calls: MetricCounter,
85 reconstruct_entry_parallel_calls: MetricCounter,
86 reconstruct_entry_serial_calls: MetricCounter,
87 reconstruct_opt_fallback_serial_calls: MetricCounter,
88 reconstruct_total_missing_data: MetricCounter,
89 reconstruct_total_missing_parity: MetricCounter,
90 reconstruct_all_present_fast_path: MetricCounter,
91 reconstruct_data_stage_calls: MetricCounter,
92 reconstruct_data_stage_bytes: MetricCounter,
93 reconstruct_parity_stage_calls: MetricCounter,
94 reconstruct_parity_stage_bytes: MetricCounter,
95 reconstruct_data_small_output_specialized_calls: MetricCounter,
96}
97
98#[cfg(feature = "std")]
99#[derive(Debug, Clone, Copy, PartialEq, Eq)]
100pub struct ReconstructionCacheStats {
101 pub requests: usize,
102 pub hits: usize,
103 pub misses: usize,
104 pub inserts: usize,
105 pub evictions: usize,
106}
107
108#[cfg(feature = "std")]
109#[derive(Debug, Clone, Copy, PartialEq)]
110pub struct ReconstructionCacheAnalysis {
111 pub hit_rate: f64,
112 pub reuse_ratio: f64,
113 pub miss_cost_per_request: f64,
114}
115
116#[cfg(feature = "std")]
117#[derive(Debug, Clone, Copy, PartialEq, Eq)]
118pub struct RuntimeProfileStats {
119 pub code_some_serial_calls: usize,
120 pub code_some_parallel_calls: usize,
121 pub code_some_total_bytes: usize,
122 pub code_some_total_chunks: usize,
123 pub code_some_small_output_chunk_parallel_calls: usize,
124 pub code_some_small_output_chunk_parallel_outputs: usize,
125 pub code_some_small_output_chunk_parallel_chunks: usize,
126 pub code_single_serial_calls: usize,
127 pub code_single_parallel_calls: usize,
128 pub code_single_total_bytes: usize,
129 pub code_single_total_chunks: usize,
130 pub parallel_policy_calls: usize,
131 pub parallel_policy_parallel: usize,
132 pub parallel_policy_serial: usize,
133 pub parallel_policy_total_jobs: usize,
134 pub parallel_policy_total_chunk_len: usize,
135 pub reconstruct_calls: usize,
136 pub reconstruct_data_only_calls: usize,
137 pub reconstruct_entry_parallel_calls: usize,
138 pub reconstruct_entry_serial_calls: usize,
139 pub reconstruct_opt_fallback_serial_calls: usize,
140 pub reconstruct_total_missing_data: usize,
141 pub reconstruct_total_missing_parity: usize,
142 pub reconstruct_all_present_fast_path: usize,
143 pub reconstruct_data_stage_calls: usize,
144 pub reconstruct_data_stage_bytes: usize,
145 pub reconstruct_parity_stage_calls: usize,
146 pub reconstruct_parity_stage_bytes: usize,
147 pub reconstruct_data_small_output_specialized_calls: usize,
148}
149
150#[cfg(feature = "std")]
151impl ReconstructionCacheMetrics {
152 pub(crate) fn snapshot(&self) -> ReconstructionCacheStats {
153 ReconstructionCacheStats {
154 requests: self.requests.load(Ordering::Relaxed),
155 hits: self.hits.load(Ordering::Relaxed),
156 misses: self.misses.load(Ordering::Relaxed),
157 inserts: self.inserts.load(Ordering::Relaxed),
158 evictions: self.evictions.load(Ordering::Relaxed),
159 }
160 }
161}
162
163#[cfg(feature = "std")]
164impl ReconstructionCacheStats {
165 #[inline]
167 pub fn hit_rate(&self) -> f64 {
168 if self.requests == 0 {
169 0.0
170 } else {
171 self.hits as f64 / self.requests as f64
172 }
173 }
174
175 #[inline]
177 pub fn reuse_ratio(&self) -> f64 {
178 if self.inserts == 0 {
179 0.0
180 } else {
181 self.hits as f64 / self.inserts as f64
182 }
183 }
184
185 #[inline]
187 pub fn miss_cost_per_request(&self) -> f64 {
188 if self.requests == 0 {
189 0.0
190 } else {
191 self.misses as f64 / self.requests as f64
192 }
193 }
194
195 #[inline]
197 pub fn analysis(&self) -> ReconstructionCacheAnalysis {
198 ReconstructionCacheAnalysis {
199 hit_rate: self.hit_rate(),
200 reuse_ratio: self.reuse_ratio(),
201 miss_cost_per_request: self.miss_cost_per_request(),
202 }
203 }
204}
205
206#[cfg(feature = "std")]
207impl RuntimeProfileMetrics {
208 pub(crate) fn snapshot(&self) -> RuntimeProfileStats {
209 RuntimeProfileStats {
210 code_some_serial_calls: self.code_some_serial_calls.load(Ordering::Relaxed),
211 code_some_parallel_calls: self.code_some_parallel_calls.load(Ordering::Relaxed),
212 code_some_total_bytes: self.code_some_total_bytes.load(Ordering::Relaxed),
213 code_some_total_chunks: self.code_some_total_chunks.load(Ordering::Relaxed),
214 code_some_small_output_chunk_parallel_calls: self
215 .code_some_small_output_chunk_parallel_calls
216 .load(Ordering::Relaxed),
217 code_some_small_output_chunk_parallel_outputs: self
218 .code_some_small_output_chunk_parallel_outputs
219 .load(Ordering::Relaxed),
220 code_some_small_output_chunk_parallel_chunks: self
221 .code_some_small_output_chunk_parallel_chunks
222 .load(Ordering::Relaxed),
223 code_single_serial_calls: self.code_single_serial_calls.load(Ordering::Relaxed),
224 code_single_parallel_calls: self.code_single_parallel_calls.load(Ordering::Relaxed),
225 code_single_total_bytes: self.code_single_total_bytes.load(Ordering::Relaxed),
226 code_single_total_chunks: self.code_single_total_chunks.load(Ordering::Relaxed),
227 parallel_policy_calls: self.parallel_policy_calls.load(Ordering::Relaxed),
228 parallel_policy_parallel: self.parallel_policy_parallel.load(Ordering::Relaxed),
229 parallel_policy_serial: self.parallel_policy_serial.load(Ordering::Relaxed),
230 parallel_policy_total_jobs: self.parallel_policy_total_jobs.load(Ordering::Relaxed),
231 parallel_policy_total_chunk_len: self
232 .parallel_policy_total_chunk_len
233 .load(Ordering::Relaxed),
234 reconstruct_calls: self.reconstruct_calls.load(Ordering::Relaxed),
235 reconstruct_data_only_calls: self.reconstruct_data_only_calls.load(Ordering::Relaxed),
236 reconstruct_entry_parallel_calls: self
237 .reconstruct_entry_parallel_calls
238 .load(Ordering::Relaxed),
239 reconstruct_entry_serial_calls: self
240 .reconstruct_entry_serial_calls
241 .load(Ordering::Relaxed),
242 reconstruct_opt_fallback_serial_calls: self
243 .reconstruct_opt_fallback_serial_calls
244 .load(Ordering::Relaxed),
245 reconstruct_total_missing_data: self
246 .reconstruct_total_missing_data
247 .load(Ordering::Relaxed),
248 reconstruct_total_missing_parity: self
249 .reconstruct_total_missing_parity
250 .load(Ordering::Relaxed),
251 reconstruct_all_present_fast_path: self
252 .reconstruct_all_present_fast_path
253 .load(Ordering::Relaxed),
254 reconstruct_data_stage_calls: self.reconstruct_data_stage_calls.load(Ordering::Relaxed),
255 reconstruct_data_stage_bytes: self.reconstruct_data_stage_bytes.load(Ordering::Relaxed),
256 reconstruct_parity_stage_calls: self
257 .reconstruct_parity_stage_calls
258 .load(Ordering::Relaxed),
259 reconstruct_parity_stage_bytes: self
260 .reconstruct_parity_stage_bytes
261 .load(Ordering::Relaxed),
262 reconstruct_data_small_output_specialized_calls: self
263 .reconstruct_data_small_output_specialized_calls
264 .load(Ordering::Relaxed),
265 }
266 }
267
268 pub(crate) fn reset(&self) {
269 self.code_some_serial_calls.store(0, Ordering::Relaxed);
270 self.code_some_parallel_calls.store(0, Ordering::Relaxed);
271 self.code_some_total_bytes.store(0, Ordering::Relaxed);
272 self.code_some_total_chunks.store(0, Ordering::Relaxed);
273 self.code_some_small_output_chunk_parallel_calls
274 .store(0, Ordering::Relaxed);
275 self.code_some_small_output_chunk_parallel_outputs
276 .store(0, Ordering::Relaxed);
277 self.code_some_small_output_chunk_parallel_chunks
278 .store(0, Ordering::Relaxed);
279 self.code_single_serial_calls.store(0, Ordering::Relaxed);
280 self.code_single_parallel_calls.store(0, Ordering::Relaxed);
281 self.code_single_total_bytes.store(0, Ordering::Relaxed);
282 self.code_single_total_chunks.store(0, Ordering::Relaxed);
283 self.parallel_policy_calls.store(0, Ordering::Relaxed);
284 self.parallel_policy_parallel.store(0, Ordering::Relaxed);
285 self.parallel_policy_serial.store(0, Ordering::Relaxed);
286 self.parallel_policy_total_jobs.store(0, Ordering::Relaxed);
287 self.parallel_policy_total_chunk_len
288 .store(0, Ordering::Relaxed);
289 self.reconstruct_calls.store(0, Ordering::Relaxed);
290 self.reconstruct_data_only_calls.store(0, Ordering::Relaxed);
291 self.reconstruct_entry_parallel_calls
292 .store(0, Ordering::Relaxed);
293 self.reconstruct_entry_serial_calls
294 .store(0, Ordering::Relaxed);
295 self.reconstruct_opt_fallback_serial_calls
296 .store(0, Ordering::Relaxed);
297 self.reconstruct_total_missing_data
298 .store(0, Ordering::Relaxed);
299 self.reconstruct_total_missing_parity
300 .store(0, Ordering::Relaxed);
301 self.reconstruct_all_present_fast_path
302 .store(0, Ordering::Relaxed);
303 self.reconstruct_data_stage_calls
304 .store(0, Ordering::Relaxed);
305 self.reconstruct_data_stage_bytes
306 .store(0, Ordering::Relaxed);
307 self.reconstruct_parity_stage_calls
308 .store(0, Ordering::Relaxed);
309 self.reconstruct_parity_stage_bytes
310 .store(0, Ordering::Relaxed);
311 self.reconstruct_data_small_output_specialized_calls
312 .store(0, Ordering::Relaxed);
313 }
314
315 pub(crate) fn record_code_some(
316 &self,
317 parallel: bool,
318 shard_len: usize,
319 inputs: usize,
320 outputs: usize,
321 chunk_len: usize,
322 ) {
323 if parallel {
324 self.code_some_parallel_calls
325 .fetch_add(1, Ordering::Relaxed);
326 } else {
327 self.code_some_serial_calls.fetch_add(1, Ordering::Relaxed);
328 }
329 self.code_some_total_bytes.fetch_add(
330 shard_len.saturating_mul(inputs).saturating_mul(outputs),
331 Ordering::Relaxed,
332 );
333 let chunks = if chunk_len == 0 {
334 0
335 } else {
336 shard_len.div_ceil(chunk_len)
337 };
338 self.code_some_total_chunks
339 .fetch_add(chunks, Ordering::Relaxed);
340 }
341
342 pub(crate) fn record_code_some_small_output_chunk_parallel(
343 &self,
344 outputs: usize,
345 chunks: usize,
346 ) {
347 self.code_some_small_output_chunk_parallel_calls
348 .fetch_add(1, Ordering::Relaxed);
349 self.code_some_small_output_chunk_parallel_outputs
350 .fetch_add(outputs, Ordering::Relaxed);
351 self.code_some_small_output_chunk_parallel_chunks
352 .fetch_add(chunks, Ordering::Relaxed);
353 }
354
355 pub(crate) fn record_code_single(
356 &self,
357 parallel: bool,
358 shard_len: usize,
359 outputs: usize,
360 chunk_len: usize,
361 ) {
362 if parallel {
363 self.code_single_parallel_calls
364 .fetch_add(1, Ordering::Relaxed);
365 } else {
366 self.code_single_serial_calls
367 .fetch_add(1, Ordering::Relaxed);
368 }
369 self.code_single_total_bytes
370 .fetch_add(shard_len.saturating_mul(outputs), Ordering::Relaxed);
371 let chunks = if chunk_len == 0 {
372 0
373 } else {
374 shard_len.div_ceil(chunk_len)
375 };
376 self.code_single_total_chunks
377 .fetch_add(chunks, Ordering::Relaxed);
378 }
379
380 pub(crate) fn record_parallel_policy(&self, decision: crate::ParallelDecision) {
381 self.parallel_policy_calls.fetch_add(1, Ordering::Relaxed);
382 if decision.use_parallel {
383 self.parallel_policy_parallel
384 .fetch_add(1, Ordering::Relaxed);
385 } else {
386 self.parallel_policy_serial.fetch_add(1, Ordering::Relaxed);
387 }
388 self.parallel_policy_total_jobs
389 .fetch_add(decision.jobs, Ordering::Relaxed);
390 self.parallel_policy_total_chunk_len
391 .fetch_add(decision.chunk_len, Ordering::Relaxed);
392 }
393
394 pub(crate) fn record_reconstruct(
395 &self,
396 data_only: bool,
397 missing_data_count: usize,
398 missing_parity_count: usize,
399 all_present_fast_path: bool,
400 ) {
401 self.reconstruct_calls.fetch_add(1, Ordering::Relaxed);
402 if data_only {
403 self.reconstruct_data_only_calls
404 .fetch_add(1, Ordering::Relaxed);
405 }
406 if all_present_fast_path {
407 self.reconstruct_all_present_fast_path
408 .fetch_add(1, Ordering::Relaxed);
409 }
410 self.reconstruct_total_missing_data
411 .fetch_add(missing_data_count, Ordering::Relaxed);
412 self.reconstruct_total_missing_parity
413 .fetch_add(missing_parity_count, Ordering::Relaxed);
414 }
415
416 pub(crate) fn record_reconstruct_entry(&self, parallel: bool) {
417 if parallel {
418 self.reconstruct_entry_parallel_calls
419 .fetch_add(1, Ordering::Relaxed);
420 } else {
421 self.reconstruct_entry_serial_calls
422 .fetch_add(1, Ordering::Relaxed);
423 }
424 }
425
426 pub(crate) fn record_reconstruct_opt_fallback_serial(&self) {
427 self.reconstruct_opt_fallback_serial_calls
428 .fetch_add(1, Ordering::Relaxed);
429 }
430
431 pub(crate) fn record_reconstruct_data_stage(&self, shard_len: usize, output_count: usize) {
432 self.reconstruct_data_stage_calls
433 .fetch_add(1, Ordering::Relaxed);
434 self.reconstruct_data_stage_bytes
435 .fetch_add(shard_len.saturating_mul(output_count), Ordering::Relaxed);
436 }
437
438 pub(crate) fn record_reconstruct_parity_stage(&self, shard_len: usize, output_count: usize) {
439 self.reconstruct_parity_stage_calls
440 .fetch_add(1, Ordering::Relaxed);
441 self.reconstruct_parity_stage_bytes
442 .fetch_add(shard_len.saturating_mul(output_count), Ordering::Relaxed);
443 }
444
445 pub(crate) fn record_reconstruct_data_small_output_specialized(&self) {
446 self.reconstruct_data_small_output_specialized_calls
447 .fetch_add(1, Ordering::Relaxed);
448 }
449}