polkadot_subsystem_bench/
display.rs1use crate::configuration::TestConfiguration;
23use colored::Colorize;
24use prometheus::{
25 proto::{MetricFamily, MetricType},
26 Registry,
27};
28use std::fmt::Display;
29
30const LOG_TARGET: &str = "subsystem-bench::display";
31
32#[derive(Default, Debug)]
33pub struct MetricCollection(Vec<TestMetric>);
34
35impl From<Vec<TestMetric>> for MetricCollection {
36 fn from(metrics: Vec<TestMetric>) -> Self {
37 MetricCollection(metrics)
38 }
39}
40
41impl MetricCollection {
42 pub fn all(&self) -> &Vec<TestMetric> {
43 &self.0
44 }
45
46 pub fn sum_by(&self, name: &str) -> f64 {
48 self.all()
49 .iter()
50 .filter(|metric| metric.name == name)
51 .map(|metric| metric.value)
52 .sum()
53 }
54
55 pub fn metric_lower_than(&self, metric_name: &str, value: f64) -> bool {
57 self.sum_by(metric_name) < value
58 }
59
60 pub fn subset_with_label_value(&self, label_name: &str, label_value: &str) -> MetricCollection {
61 self.0
62 .iter()
63 .filter_map(|metric| {
64 if let Some(index) = metric.label_names.iter().position(|label| label == label_name)
65 {
66 if Some(&String::from(label_value)) == metric.label_values.get(index) {
67 Some(metric.clone())
68 } else {
69 None
70 }
71 } else {
72 None
73 }
74 })
75 .collect::<Vec<_>>()
76 .into()
77 }
78}
79
80impl Display for MetricCollection {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 writeln!(f)?;
83 let metrics = self.all();
84 for metric in metrics {
85 writeln!(f, "{metric}")?;
86 }
87 Ok(())
88 }
89}
90
91#[derive(Debug, Clone)]
92pub struct TestMetric {
93 name: String,
94 label_names: Vec<String>,
95 label_values: Vec<String>,
96 value: f64,
97}
98
99impl TestMetric {
100 pub fn name(&self) -> &str {
101 &self.name
102 }
103
104 pub fn value(&self) -> f64 {
105 self.value
106 }
107
108 pub fn label_value(&self, label_name: &str) -> Option<&str> {
109 self.label_names
110 .iter()
111 .position(|name| name == label_name)
112 .and_then(|index| self.label_values.get(index).map(|s| s.as_str()))
113 }
114}
115
116impl Display for TestMetric {
117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118 write!(
119 f,
120 "({} = {}) [{:?}, {:?}]",
121 self.name.cyan(),
122 format!("{}", self.value).white(),
123 self.label_names,
124 self.label_values
125 )
126 }
127}
128
129fn check_metric_family(mf: &MetricFamily) -> bool {
131 if mf.get_metric().is_empty() {
132 gum::error!(target: LOG_TARGET, "MetricFamily has no metrics: {:?}", mf);
133 return false
134 }
135 if mf.get_name().is_empty() {
136 gum::error!(target: LOG_TARGET, "MetricFamily has no name: {:?}", mf);
137 return false
138 }
139
140 true
141}
142
143pub fn parse_metrics(registry: &Registry) -> MetricCollection {
144 let metric_families = registry.gather();
145 let mut test_metrics = Vec::new();
146 for mf in metric_families {
147 if !check_metric_family(&mf) {
148 continue
149 }
150
151 let name: String = mf.get_name().into();
152 let metric_type = mf.get_field_type();
153 for m in mf.get_metric() {
154 let (label_names, label_values): (Vec<String>, Vec<String>) = m
155 .get_label()
156 .iter()
157 .map(|pair| (String::from(pair.get_name()), String::from(pair.get_value())))
158 .unzip();
159
160 match metric_type {
161 MetricType::COUNTER => {
162 test_metrics.push(TestMetric {
163 name: name.clone(),
164 label_names,
165 label_values,
166 value: m.get_counter().get_value(),
167 });
168 },
169 MetricType::GAUGE => {
170 test_metrics.push(TestMetric {
171 name: name.clone(),
172 label_names,
173 label_values,
174 value: m.get_gauge().get_value(),
175 });
176 },
177 MetricType::HISTOGRAM => {
178 let h = m.get_histogram();
179 let h_name = name.clone() + "_sum";
180 test_metrics.push(TestMetric {
181 name: h_name,
182 label_names: label_names.clone(),
183 label_values: label_values.clone(),
184 value: h.get_sample_sum(),
185 });
186
187 let h_name = name.clone() + "_count";
188 test_metrics.push(TestMetric {
189 name: h_name,
190 label_names,
191 label_values,
192 value: h.get_sample_count() as f64,
193 });
194 },
195 MetricType::SUMMARY => {
196 unimplemented!();
197 },
198 MetricType::UNTYPED => {
199 unimplemented!();
200 },
201 }
202 }
203 }
204 test_metrics.into()
205}
206
207impl Display for TestConfiguration {
208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 write!(
210 f,
211 "{}, {}, {}, {}, {}",
212 format!("n_validators = {}", self.n_validators).blue(),
213 format!("n_cores = {}", self.n_cores).blue(),
214 format!("pov_size = {} - {}", self.min_pov_size, self.max_pov_size).bright_black(),
215 format!("connectivity = {}", self.connectivity).bright_black(),
216 format!("latency = {:?}", self.latency).bright_black(),
217 )
218 }
219}