| 1 | use std::collections::HashMap; |
| 2 | |
| 3 | use crate::{ |
| 4 | alloc::ThreadAllocInfo, |
| 5 | counter::KnownCounterKind, |
| 6 | time::{FineDuration, Timer, Timestamp}, |
| 7 | }; |
| 8 | |
| 9 | /// Timing measurement. |
| 10 | pub(crate) struct TimeSample { |
| 11 | /// The time this sample took to run. |
| 12 | /// |
| 13 | /// This is gotten from [`RawSample`] with: |
| 14 | /// `end.duration_since(start, timer).clamp_to(timer.precision())`. |
| 15 | pub duration: FineDuration, |
| 16 | } |
| 17 | |
| 18 | /// Unprocessed measurement. |
| 19 | /// |
| 20 | /// This cannot be serialized because [`Timestamp`] is an implementation detail |
| 21 | /// for both the `Instant` and TSC timers. |
| 22 | pub(crate) struct RawSample { |
| 23 | pub start: Timestamp, |
| 24 | pub end: Timestamp, |
| 25 | pub timer: Timer, |
| 26 | pub alloc_info: ThreadAllocInfo, |
| 27 | pub counter_totals: [u128; KnownCounterKind::COUNT], |
| 28 | } |
| 29 | |
| 30 | impl RawSample { |
| 31 | /// Simply computes `end - start` without clamping to precision. |
| 32 | #[inline ] |
| 33 | pub fn duration(&self) -> FineDuration { |
| 34 | self.end.duration_since(self.start, self.timer) |
| 35 | } |
| 36 | } |
| 37 | |
| 38 | /// Sample collection. |
| 39 | #[derive (Default)] |
| 40 | pub(crate) struct SampleCollection { |
| 41 | /// The number of iterations within each sample. |
| 42 | pub sample_size: u32, |
| 43 | |
| 44 | /// Collected timings. |
| 45 | pub time_samples: Vec<TimeSample>, |
| 46 | |
| 47 | /// Allocation information associated with `time_samples` by index. |
| 48 | pub alloc_info_by_sample: HashMap<u32, ThreadAllocInfo>, |
| 49 | } |
| 50 | |
| 51 | impl SampleCollection { |
| 52 | /// Discards all recorded data. |
| 53 | #[inline ] |
| 54 | pub fn clear(&mut self) { |
| 55 | self.time_samples.clear(); |
| 56 | self.alloc_info_by_sample.clear(); |
| 57 | } |
| 58 | |
| 59 | /// Computes the total number of iterations across all samples. |
| 60 | /// |
| 61 | /// We use `u64` in case sample count and sizes are huge. |
| 62 | #[inline ] |
| 63 | pub fn iter_count(&self) -> u64 { |
| 64 | self.sample_size as u64 * self.time_samples.len() as u64 |
| 65 | } |
| 66 | |
| 67 | /// Computes the total time across all samples. |
| 68 | #[inline ] |
| 69 | pub fn total_duration(&self) -> FineDuration { |
| 70 | FineDuration { picos: self.time_samples.iter().map(|s| s.duration.picos).sum() } |
| 71 | } |
| 72 | |
| 73 | /// Returns all samples sorted by duration. |
| 74 | #[inline ] |
| 75 | pub fn sorted_samples(&self) -> Vec<&TimeSample> { |
| 76 | let mut result: Vec<&TimeSample> = self.time_samples.iter().collect(); |
| 77 | result.sort_unstable_by_key(|s| s.duration); |
| 78 | result |
| 79 | } |
| 80 | } |
| 81 | |