1use std::sync::atomic::Ordering;
7
8use crate::config::StatsLevel;
9
10use super::{EdgeId, GraphInner, InputQueueStatsSnapshot, NodeStatsSnapshot};
11
12impl GraphInner {
13 pub(super) fn queue_depth(&self, edge: EdgeId) -> usize {
14 self.edges[edge]
15 .consumers
16 .iter()
17 .map(|&(n, p)| self.nodes[n].queue_len(p))
18 .sum()
19 }
20
21 pub(super) fn node_stats(&self, i: usize) -> Option<NodeStatsSnapshot> {
22 let node = self.nodes.get(i)?;
23 let st = &node.stats;
24 let running = st.in_flight.load(Ordering::Relaxed) > 0;
26 let running_for_us = if running && self.stats_level == StatsLevel::Full {
27 let now_us = self.epoch.elapsed().as_micros() as i64;
28 (now_us - st.started_us.load(Ordering::Relaxed)).max(0)
29 } else {
30 0
31 };
32 Some(NodeStatsSnapshot {
33 node_name: node.name.clone(),
34 kernel_name: node.kernel_name.clone(),
35 running,
36 running_for_us,
37 processed: st.processed.load(Ordering::Relaxed),
38 errors: st.errors.load(Ordering::Relaxed),
39 total_process_us: st.total_us.load(Ordering::Relaxed),
40 max_process_us: st.max_us.load(Ordering::Relaxed),
41 packets_in: st.packets_in.load(Ordering::Relaxed),
42 packets_out: st.packets_out.load(Ordering::Relaxed),
43 peak_queue_depth: st.peak_queue_depth.load(Ordering::Relaxed),
44 queued: (0..node.input_queues.len())
45 .map(|p| node.queue_len(p))
46 .sum(),
47 })
48 }
49
50 pub fn to_chrome_trace(&self) -> String {
54 let events = self.shared.trace_snapshot();
55 let labels: Vec<(String, String)> = self
56 .nodes
57 .iter()
58 .map(|n| (n.name.clone(), n.kernel_name.clone()))
59 .collect();
60 crate::trace::to_chrome_trace_json(&events, &labels)
61 }
62
63 pub(super) fn input_queue_stats(
64 &self,
65 node_id: usize,
66 port: usize,
67 ) -> Option<InputQueueStatsSnapshot> {
68 self.input_queue_stats_at(node_id, port, self.epoch_us())
69 }
70
71 pub(super) fn input_queue_stats_at(
72 &self,
73 node_id: usize,
74 port: usize,
75 now_us: i64,
76 ) -> Option<InputQueueStatsSnapshot> {
77 let node = self.nodes.get(node_id)?;
78 let port_name = node.in_ports.name(port)?.to_string();
79 let stats = node.input_queue_stats.get(port)?;
80 let queued_packets = node.queue_len(port);
81 let queued_bytes = node.input_queue_bytes[port].load(Ordering::SeqCst);
82 let reserved_packets = node.input_queue_reserved[port].load(Ordering::SeqCst);
83 let since = stats.blocked_since_us.load(Ordering::SeqCst);
84 let blocked_for_us = if since == 0 {
85 0
86 } else {
87 now_us.saturating_sub(since.saturating_sub(1)).max(0) as u64
88 };
89 let edge = node.inputs[port];
90 let producer_name = self.edges[edge]
91 .producer
92 .map(|producer| self.nodes[producer].name.clone());
93 Some(InputQueueStatsSnapshot {
94 node_name: node.name.clone(),
95 port_name,
96 producer_name,
97 packet_capacity: node.input_queue_capacity[port],
98 queued_packets,
99 queued_bytes,
100 reserved_packets,
101 peak_queued_packets: stats.peak_packets.load(Ordering::Relaxed),
102 peak_queued_bytes: stats.peak_bytes.load(Ordering::Relaxed),
103 blocked: since != 0,
104 blocked_for_us,
105 block_events: stats.block_events.load(Ordering::Relaxed),
106 total_blocked_us: stats
107 .blocked_total_us
108 .load(Ordering::Relaxed)
109 .saturating_add(blocked_for_us),
110 })
111 }
112
113 pub(super) fn dump(&self) -> String {
114 let mut s = String::new();
115 s.push_str(&format!(
116 "graph state={:?} nodes={} edges={} queued={} ({} bytes)\n",
117 self.state(),
118 self.nodes.len(),
119 self.edges.len(),
120 self.shared.total_queued(),
121 self.shared.total_queued_bytes()
122 ));
123 s.push_str("node state queued processed errors avg_us max_us\n");
124 for i in 0..self.nodes.len() {
125 let st = self.node_stats(i).expect("node exists");
126 let sched = self.nodes[i].sched.lock().expect("scheduler lock poisoned");
127 let state = if st.running {
128 format!("RUNNING {}ms", st.running_for_us / 1000)
129 } else if sched.closed {
130 "closed".to_string()
131 } else if sched.opened {
132 "idle".to_string()
133 } else {
134 "new".to_string()
135 };
136 let avg = if st.processed > 0 {
137 st.total_process_us / st.processed as i64
138 } else {
139 0
140 };
141 s.push_str(&format!(
142 "{:<17} {:<12} {:>6} {:>9} {:>6} {:>6} {:>6}\n",
143 st.node_name, state, st.queued, st.processed, st.errors, avg, st.max_process_us
144 ));
145 for port in 0..self.nodes[i].input_queues.len() {
146 let queue = self.input_queue_stats(i, port).expect("input port exists");
147 let capacity = queue
148 .packet_capacity
149 .map_or_else(|| "unbounded".to_string(), |value| value.to_string());
150 s.push_str(&format!(
151 " input `{}` capacity={} packets queued={}/{}B reserved={} peak={}/{}B blocked={} events={} total={}us\n",
152 queue.port_name,
153 capacity,
154 queue.queued_packets,
155 queue.queued_bytes,
156 queue.reserved_packets,
157 queue.peak_queued_packets,
158 queue.peak_queued_bytes,
159 queue.blocked,
160 queue.block_events,
161 queue.total_blocked_us,
162 ));
163 }
164 }
165 for e in &self.edges {
166 s.push_str(&format!(
167 "edge `{}` closed={} dropped={}\n",
168 e.name,
169 e.is_closed(),
170 e.dropped_count()
171 ));
172 if e.is_graph_input {
173 let watermark = e.watermark_backpressure.snapshot(self.epoch_us());
174 s.push_str(&format!(
175 " watermark limit={} queued={} blocked={} waiters={} events={} total={}us\n",
176 self.shared.config.max_queued_packets,
177 self.shared.total_queued(),
178 watermark.blocked,
179 watermark.active_waiters,
180 watermark.block_events,
181 watermark.total_blocked_us,
182 ));
183 }
184 for poller in e.pollers.lock().expect("poller list lock poisoned").iter() {
185 let block = poller.block_backpressure.snapshot(self.epoch_us());
186 let queued = poller.queue.lock().expect("poller lock poisoned").len();
187 s.push_str(&format!(
188 " poller policy={:?} capacity={} queued={} dropped={} blocked={} waiters={} events={} total={}us\n",
189 poller.overflow,
190 poller
191 .capacity
192 .map_or_else(|| "unbounded".to_string(), |value| value.to_string()),
193 queued,
194 poller.dropped.load(Ordering::Relaxed),
195 block.blocked,
196 block.active_waiters,
197 block.block_events,
198 block.total_blocked_us,
199 ));
200 }
201 }
202 s
203 }
204}