Skip to main content

gwr_track/tracker/
perfetto.rs

1// Copyright (c) 2025 Graphcore Ltd. All rights reserved.
2
3use std::cell::RefCell;
4use std::collections::HashMap;
5use std::rc::Rc;
6
7use crate::entity::Capacity;
8use crate::perfetto_trace_builder::PerfettoTraceBuilder;
9use crate::tracker::EntityManager;
10use crate::tracker::aka::AlternativeNames;
11use crate::{Id, SharedWriter, Track, Writer};
12
13/// A tracker that writes Perfetto binary data
14pub struct PerfettoTracker {
15    entity_manager: EntityManager,
16    writer: SharedWriter,
17    current_time_ns: RefCell<u64>,
18    trace_builder: RefCell<PerfettoTraceBuilder>,
19    group_memberships: RefCell<HashMap<Id, Id>>,
20    activity_lanes: RefCell<HashMap<Id, Id>>,
21}
22
23impl PerfettoTracker {
24    /// Create a new [`PerfettoTracker`] with an [`EntityManager`]
25    pub fn new(entity_manager: EntityManager, writer: Writer) -> Self {
26        Self {
27            entity_manager,
28            writer: Rc::new(RefCell::new(writer)),
29            current_time_ns: RefCell::new(0),
30            trace_builder: RefCell::new(PerfettoTraceBuilder::new()),
31            group_memberships: RefCell::new(HashMap::new()),
32            activity_lanes: RefCell::new(HashMap::new()),
33        }
34    }
35}
36
37impl Track for PerfettoTracker {
38    fn unique_id(&self) -> Id {
39        self.entity_manager.unique_id()
40    }
41
42    fn enabled_level(&self, id: Id) -> log::Level {
43        self.entity_manager.enabled_level(id)
44    }
45
46    fn monitoring_window_size_for(&self, id: Id) -> Option<u64> {
47        self.entity_manager.monitoring_window_size_for(id)
48    }
49
50    fn add_entity(
51        &self,
52        id: Id,
53        entity_name: &str,
54        alternative_names: AlternativeNames,
55    ) -> log::Level {
56        self.entity_manager
57            .add_entity(id, entity_name, alternative_names)
58    }
59
60    fn enter(&self, id: Id, entered: Id) {
61        if self.is_entity_enabled(id, log::Level::Trace) {
62            let guard = self.trace_builder.borrow_mut();
63            let trace_packet = guard.build_enter_track_event_trace_packet(
64                *self.current_time_ns.borrow(),
65                id,
66                entered,
67            );
68            let buf = guard.build_trace_to_bytes(vec![trace_packet]);
69            self.writer.borrow_mut().write_all(&buf).unwrap();
70        }
71    }
72
73    fn exit(&self, id: Id, exited: Id) {
74        if self.is_entity_enabled(id, log::Level::Trace) {
75            let guard = self.trace_builder.borrow_mut();
76            let trace_packet = guard.build_exit_track_event_trace_packet(
77                *self.current_time_ns.borrow(),
78                id,
79                exited,
80            );
81            let buf = guard.build_trace_to_bytes(vec![trace_packet]);
82            self.writer.borrow_mut().write_all(&buf).unwrap();
83        }
84    }
85
86    fn value(&self, id: Id, value: f64) {
87        if self.is_entity_enabled(id, log::Level::Trace) {
88            let guard = self.trace_builder.borrow_mut();
89            let trace_packet = guard.build_value_track_event_trace_packet(
90                *self.current_time_ns.borrow(),
91                id,
92                value,
93            );
94            let buf = guard.build_trace_to_bytes(vec![trace_packet]);
95            self.writer.borrow_mut().write_all(&buf).unwrap();
96        }
97    }
98
99    fn begin_activity(&self, activity: Id, lane: Id, name: &str) {
100        if self.is_entity_enabled(lane, log::Level::Trace) {
101            self.activity_lanes.borrow_mut().insert(activity, lane);
102            let guard = self.trace_builder.borrow_mut();
103            let correlation_id = self
104                .group_memberships
105                .borrow()
106                .get(&activity)
107                .map(|group_id| group_id.0);
108            let trace_packet = guard.build_activity_begin_trace_packet(
109                *self.current_time_ns.borrow(),
110                lane,
111                name,
112                correlation_id,
113            );
114            let buf = guard.build_trace_to_bytes(vec![trace_packet]);
115            self.writer.borrow_mut().write_all(&buf).unwrap();
116        }
117    }
118
119    fn add_to_group(&self, activity: Id, group_id: Id) {
120        self.group_memberships
121            .borrow_mut()
122            .insert(activity, group_id);
123    }
124
125    fn remove_from_group(&self, activity: Id, group_id: Id) {
126        let is_member = self.group_memberships.borrow().get(&activity) == Some(&group_id);
127        if is_member {
128            self.group_memberships.borrow_mut().remove(&activity);
129        }
130    }
131
132    fn end_activity(&self, activity: Id) {
133        if let Some(lane) = self.activity_lanes.borrow_mut().remove(&activity)
134            && self.is_entity_enabled(lane, log::Level::Trace)
135        {
136            let guard = self.trace_builder.borrow_mut();
137            let trace_packet =
138                guard.build_activity_end_trace_packet(*self.current_time_ns.borrow(), lane);
139            let buf = guard.build_trace_to_bytes(vec![trace_packet]);
140            self.writer.borrow_mut().write_all(&buf).unwrap();
141        }
142    }
143
144    fn create_entity(&self, created_by: Id, id: Id, name: &str) {
145        if self.is_entity_enabled(id, log::Level::Trace) {
146            let mut guard = self.trace_builder.borrow_mut();
147            let trace_packet = guard.build_enter_exit_track_descriptor_trace_packet(
148                *self.current_time_ns.borrow(),
149                id,
150                created_by,
151                name,
152            );
153            let buf = guard.build_trace_to_bytes(vec![trace_packet]);
154            self.writer.borrow_mut().write_all(&buf).unwrap();
155        }
156    }
157
158    fn create_monitor(&self, created_by: Id, id: Id, name: &str) {
159        if self.is_entity_enabled(id, log::Level::Trace) {
160            let mut guard = self.trace_builder.borrow_mut();
161            let trace_packet = guard.build_value_track_descriptor_trace_packet(
162                *self.current_time_ns.borrow(),
163                id,
164                created_by,
165                name,
166            );
167            let buf = guard.build_trace_to_bytes(vec![trace_packet]);
168            self.writer.borrow_mut().write_all(&buf).unwrap();
169        }
170    }
171
172    fn create_lane(&self, created_by: Id, id: Id, name: &str) {
173        if self.is_entity_enabled(id, log::Level::Trace) {
174            let mut guard = self.trace_builder.borrow_mut();
175            let trace_packet = guard.build_activity_track_descriptor_trace_packet(
176                *self.current_time_ns.borrow(),
177                id,
178                created_by,
179                name,
180            );
181            let buf = guard.build_trace_to_bytes(vec![trace_packet]);
182            self.writer.borrow_mut().write_all(&buf).unwrap();
183        }
184    }
185
186    fn create_group(&self, _created_by: Id, _id: Id, _name: &str) {}
187
188    fn create_object(
189        &self,
190        created_by: Id,
191        id: Id,
192        _size: usize,
193        _units: &str,
194        _req_type: u8,
195        details: &str,
196    ) {
197        if self.is_entity_enabled(created_by, log::Level::Trace) {
198            let mut guard = self.trace_builder.borrow_mut();
199            let trace_packet = guard.build_enter_exit_track_descriptor_trace_packet(
200                *self.current_time_ns.borrow(),
201                id,
202                created_by,
203                details,
204            );
205            let buf = guard.build_trace_to_bytes(vec![trace_packet]);
206            self.writer.borrow_mut().write_all(&buf).unwrap();
207        }
208    }
209
210    fn capacity(&self, _id: Id, _capacity: Capacity) {
211        // todo!()
212    }
213
214    fn destroy(&self, _destroyed_by: Id, _destroyed_obj: Id) {
215        // todo!()
216    }
217
218    fn connect(&self, _connect_from: Id, _connect_to: Id) {
219        // todo!()
220    }
221
222    fn log(&self, _msg_by: Id, _level: log::Level, _msg: std::fmt::Arguments) {
223        // todo!()
224    }
225
226    fn time(&self, _set_by: Id, time_ns: f64) {
227        *self.current_time_ns.borrow_mut() = time_ns as u64;
228    }
229
230    fn shutdown(&self) {
231        // todo!()
232    }
233}