fxprof_processed_profile/
counters.rs

1use serde::ser::{Serialize, SerializeMap, Serializer};
2
3use crate::{ProcessHandle, Timestamp};
4
5/// A counter. Can be created with [`Profile::add_counter`](crate::Profile::add_counter).
6#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
7pub struct CounterHandle(pub(crate) usize);
8
9#[derive(Debug)]
10pub struct Counter {
11    name: String,
12    category: String,
13    description: String,
14    process: ProcessHandle,
15    pid: String,
16    samples: CounterSamples,
17}
18
19impl Counter {
20    pub fn new(
21        name: &str,
22        category: &str,
23        description: &str,
24        process: ProcessHandle,
25        pid: &str,
26    ) -> Self {
27        Counter {
28            name: name.to_owned(),
29            category: category.to_owned(),
30            description: description.to_owned(),
31            process,
32            pid: pid.to_owned(),
33            samples: CounterSamples::new(),
34        }
35    }
36
37    pub fn process(&self) -> ProcessHandle {
38        self.process
39    }
40
41    pub fn add_sample(
42        &mut self,
43        timestamp: Timestamp,
44        value_delta: f64,
45        number_of_operations_delta: u32,
46    ) {
47        self.samples
48            .add_sample(timestamp, value_delta, number_of_operations_delta)
49    }
50
51    pub fn as_serializable(&self, main_thread_index: usize) -> impl Serialize + '_ {
52        SerializableCounter {
53            counter: self,
54            main_thread_index,
55        }
56    }
57}
58
59struct SerializableCounter<'a> {
60    counter: &'a Counter,
61    /// The index of the main thread for the counter's process in the profile threads list.
62    main_thread_index: usize,
63}
64
65impl<'a> Serialize for SerializableCounter<'a> {
66    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
67        let mut map = serializer.serialize_map(None)?;
68        map.serialize_entry("category", &self.counter.category)?;
69        map.serialize_entry("name", &self.counter.name)?;
70        map.serialize_entry("description", &self.counter.description)?;
71        map.serialize_entry("mainThreadIndex", &self.main_thread_index)?;
72        map.serialize_entry("pid", &self.counter.pid)?;
73        map.serialize_entry(
74            "sampleGroups",
75            &[SerializableCounterSampleGroup(self.counter)],
76        )?;
77        map.end()
78    }
79}
80
81struct SerializableCounterSampleGroup<'a>(&'a Counter);
82
83impl<'a> Serialize for SerializableCounterSampleGroup<'a> {
84    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
85        let mut map = serializer.serialize_map(None)?;
86        map.serialize_entry("id", &0)?; // It's not clear what the meaning of this ID is.
87        map.serialize_entry("samples", &self.0.samples)?;
88        map.end()
89    }
90}
91
92#[derive(Debug)]
93struct CounterSamples {
94    time: Vec<Timestamp>,
95    number: Vec<u32>,
96    count: Vec<f64>,
97}
98
99impl CounterSamples {
100    pub fn new() -> Self {
101        Self {
102            time: Vec::new(),
103            number: Vec::new(),
104            count: Vec::new(),
105        }
106    }
107
108    pub fn add_sample(
109        &mut self,
110        timestamp: Timestamp,
111        value_delta: f64,
112        number_of_operations_delta: u32,
113    ) {
114        self.time.push(timestamp);
115        self.count.push(value_delta);
116        self.number.push(number_of_operations_delta);
117    }
118}
119
120impl Serialize for CounterSamples {
121    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
122        let len = self.time.len();
123        let mut map = serializer.serialize_map(None)?;
124        map.serialize_entry("length", &len)?;
125        map.serialize_entry("count", &self.count)?;
126        map.serialize_entry("number", &self.number)?;
127        map.serialize_entry("time", &self.time)?;
128        map.end()
129    }
130}