feat: add fan speed plot (#338)

This commit is contained in:
Ilya Zlobintsev 2024-06-06 23:06:00 +03:00 committed by GitHub
parent fd85122d4a
commit 3f99eab263
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 115 additions and 4 deletions

View File

@ -27,6 +27,7 @@ impl GraphsWindow {
let mut temperature_plot = imp.temperature_plot.data_mut(); let mut temperature_plot = imp.temperature_plot.data_mut();
let mut clockspeed_plot = imp.clockspeed_plot.data_mut(); let mut clockspeed_plot = imp.clockspeed_plot.data_mut();
let mut power_plot = imp.power_plot.data_mut(); let mut power_plot = imp.power_plot.data_mut();
let mut fan_plot = imp.fan_plot.data_mut();
let throttling_plots = [&mut temperature_plot, &mut clockspeed_plot, &mut power_plot]; let throttling_plots = [&mut temperature_plot, &mut clockspeed_plot, &mut power_plot];
match &stats.throttle_info { match &stats.throttle_info {
@ -81,13 +82,31 @@ impl GraphsWindow {
clockspeed_plot.push_line_series("VRAM", point as f64); clockspeed_plot.push_line_series("VRAM", point as f64);
} }
if let Some(max_speed) = stats.fan.speed_max {
fan_plot.push_line_series("Maximum", max_speed as f64);
}
if let Some(min_speed) = stats.fan.speed_min {
fan_plot.push_line_series("Minimum", min_speed as f64);
}
if let Some(current_speed) = stats.fan.speed_current {
fan_plot.push_line_series("Current", current_speed as f64);
}
if let Some(pwm) = stats.fan.pwm_current {
fan_plot
.push_secondary_line_series("Percentage", (pwm as f64 / u8::MAX as f64) * 100.0);
}
temperature_plot.trim_data(GRAPH_WIDTH_SECONDS); temperature_plot.trim_data(GRAPH_WIDTH_SECONDS);
clockspeed_plot.trim_data(GRAPH_WIDTH_SECONDS); clockspeed_plot.trim_data(GRAPH_WIDTH_SECONDS);
power_plot.trim_data(GRAPH_WIDTH_SECONDS); power_plot.trim_data(GRAPH_WIDTH_SECONDS);
fan_plot.trim_data(GRAPH_WIDTH_SECONDS);
imp.temperature_plot.queue_draw(); imp.temperature_plot.queue_draw();
imp.clockspeed_plot.queue_draw(); imp.clockspeed_plot.queue_draw();
imp.power_plot.queue_draw(); imp.power_plot.queue_draw();
imp.fan_plot.queue_draw();
} }
pub fn clear(&self) { pub fn clear(&self) {
@ -95,9 +114,12 @@ impl GraphsWindow {
*imp.temperature_plot.data_mut() = PlotData::default(); *imp.temperature_plot.data_mut() = PlotData::default();
*imp.clockspeed_plot.data_mut() = PlotData::default(); *imp.clockspeed_plot.data_mut() = PlotData::default();
*imp.power_plot.data_mut() = PlotData::default(); *imp.power_plot.data_mut() = PlotData::default();
*imp.fan_plot.data_mut() = PlotData::default();
imp.temperature_plot.queue_draw(); imp.temperature_plot.queue_draw();
imp.clockspeed_plot.queue_draw(); imp.clockspeed_plot.queue_draw();
imp.power_plot.queue_draw(); imp.power_plot.queue_draw();
imp.fan_plot.queue_draw();
} }
} }
@ -128,6 +150,8 @@ mod imp {
pub(super) clockspeed_plot: TemplateChild<Plot>, pub(super) clockspeed_plot: TemplateChild<Plot>,
#[template_child] #[template_child]
pub(super) power_plot: TemplateChild<Plot>, pub(super) power_plot: TemplateChild<Plot>,
#[template_child]
pub(super) fan_plot: TemplateChild<Plot>,
} }
#[glib::object_subclass] #[glib::object_subclass]

View File

@ -21,7 +21,11 @@ pub struct Plot {
#[property(get, set)] #[property(get, set)]
value_suffix: RefCell<String>, value_suffix: RefCell<String>,
#[property(get, set)] #[property(get, set)]
secondary_value_suffix: RefCell<String>,
#[property(get, set)]
y_label_area_size: Cell<u32>, y_label_area_size: Cell<u32>,
#[property(get, set)]
secondary_y_label_area_size: Cell<u32>,
pub(super) data: RefCell<PlotData>, pub(super) data: RefCell<PlotData>,
} }
@ -67,6 +71,7 @@ impl WidgetImpl for Plot {
#[cfg_attr(feature = "bench", derive(Clone))] #[cfg_attr(feature = "bench", derive(Clone))]
pub struct PlotData { pub struct PlotData {
line_series: BTreeMap<String, Vec<(i64, f64)>>, line_series: BTreeMap<String, Vec<(i64, f64)>>,
secondary_line_series: BTreeMap<String, Vec<(i64, f64)>>,
throttling: Vec<(i64, (String, bool))>, throttling: Vec<(i64, (String, bool))>,
} }
@ -75,6 +80,10 @@ impl PlotData {
self.push_line_series_with_time(name, point, chrono::Local::now().naive_local()); self.push_line_series_with_time(name, point, chrono::Local::now().naive_local());
} }
pub fn push_secondary_line_series(&mut self, name: &str, point: f64) {
self.push_secondary_line_series_with_time(name, point, chrono::Local::now().naive_local());
}
pub fn push_line_series_with_time(&mut self, name: &str, point: f64, time: NaiveDateTime) { pub fn push_line_series_with_time(&mut self, name: &str, point: f64, time: NaiveDateTime) {
self.line_series self.line_series
.entry(name.to_owned()) .entry(name.to_owned())
@ -82,6 +91,18 @@ impl PlotData {
.push((time.timestamp_millis(), point)); .push((time.timestamp_millis(), point));
} }
pub fn push_secondary_line_series_with_time(
&mut self,
name: &str,
point: f64,
time: NaiveDateTime,
) {
self.secondary_line_series
.entry(name.to_owned())
.or_default()
.push((time.timestamp_millis(), point));
}
pub fn push_throttling(&mut self, name: &str, point: bool) { pub fn push_throttling(&mut self, name: &str, point: bool) {
self.throttling.push(( self.throttling.push((
chrono::Local::now().naive_local().timestamp_millis(), chrono::Local::now().naive_local().timestamp_millis(),
@ -93,6 +114,10 @@ impl PlotData {
self.line_series.iter() self.line_series.iter()
} }
pub fn secondary_line_series_iter(&self) -> impl Iterator<Item = (&String, &Vec<(i64, f64)>)> {
self.secondary_line_series.iter()
}
pub fn throttling_iter(&self) -> impl Iterator<Item = (i64, &str, bool)> { pub fn throttling_iter(&self) -> impl Iterator<Item = (i64, &str, bool)> {
self.throttling self.throttling
.iter() .iter()
@ -112,6 +137,18 @@ impl PlotData {
self.line_series.retain(|_, data| !data.is_empty()); self.line_series.retain(|_, data| !data.is_empty());
for data in self.secondary_line_series.values_mut() {
let maximum_point = data
.last()
.map(|(date_time, _)| *date_time)
.unwrap_or_default();
data.retain(|(time_point, _)| ((maximum_point - *time_point) / 1000) < last_seconds);
}
self.secondary_line_series
.retain(|_, data| !data.is_empty());
// Limit data to N seconds // Limit data to N seconds
let maximum_point = self let maximum_point = self
.throttling .throttling
@ -162,12 +199,17 @@ impl Plot {
let mut chart = ChartBuilder::on(&root) let mut chart = ChartBuilder::on(&root)
.x_label_area_size(40) .x_label_area_size(40)
.y_label_area_size(self.y_label_area_size.get()) .y_label_area_size(self.y_label_area_size.get())
.right_y_label_area_size(self.secondary_y_label_area_size.get())
.margin(20) .margin(20)
.caption(self.title.borrow().as_str(), ("sans-serif", 30)) .caption(self.title.borrow().as_str(), ("sans-serif", 30))
.build_cartesian_2d( .build_cartesian_2d(
start_date..max(end_date, start_date + 60 * 1000), start_date..max(end_date, start_date + 60 * 1000),
0f64..maximum_value, 0f64..maximum_value,
)?; )?
.set_secondary_coord(
start_date..max(end_date, start_date + 60 * 1000),
0.0..100.0,
);
chart chart
.configure_mesh() .configure_mesh()
@ -182,6 +224,14 @@ impl Plot {
.draw() .draw()
.context("Failed to draw mesh")?; .context("Failed to draw mesh")?;
chart
.configure_secondary_axes()
.y_label_formatter(&|x| format!("{x}{}", self.secondary_value_suffix.borrow()))
.y_labels(10)
.label_style(("sans-serif", 30))
.draw()
.context("Failed to draw mesh")?;
// Draw the throttling histogram // Draw the throttling histogram
chart chart
.draw_series( .draw_series(
@ -229,6 +279,29 @@ impl Plot {
}); });
} }
for (idx, (caption, data)) in (0..).zip(data.secondary_line_series_iter()) {
chart
.draw_secondary_series(LineSeries::new(
cubic_spline_interpolation(data.iter())
.into_iter()
.flat_map(|((first_time, second_time), segment)| {
// Interpolate in intervals of one millisecond
(first_time..second_time).map(move |current_date| {
(current_date, segment.evaluate(current_date))
})
}),
Palette99::pick(idx + 10).stroke_width(1), // Offset the pallete pick compared to the main graph
))
.context("Failed to draw series")?
.label(caption)
.legend(move |(x, y)| {
Rectangle::new(
[(x - 10, y - 10), (x + 10, y + 10)],
Palette99::pick(idx + 10),
)
});
}
chart chart
.configure_series_labels() .configure_series_labels()
.margin(30) .margin(30)

View File

@ -1,7 +1,7 @@
using Gtk 4.0; using Gtk 4.0;
template $GraphsWindow: Window { template $GraphsWindow: Window {
default-height: 600; default-height: 800;
default-width: 600; default-width: 600;
title: "Historical data"; title: "Historical data";
hide-on-close: true; hide-on-close: true;
@ -27,6 +27,20 @@ template $GraphsWindow: Window {
} }
} }
$Plot fan_plot {
title: "Fan speed";
hexpand: true;
value-suffix: "PWM";
secondary-value-suffix: "%";
y-label-area-size: 140;
secondary-y-label-area-size: 80;
layout {
column: 0;
row: 1;
}
}
$Plot clockspeed_plot { $Plot clockspeed_plot {
title: "Clockspeed"; title: "Clockspeed";
hexpand: true; hexpand: true;
@ -35,7 +49,7 @@ template $GraphsWindow: Window {
layout { layout {
column: 0; column: 0;
row: 1; row: 2;
} }
} }
@ -47,7 +61,7 @@ template $GraphsWindow: Window {
layout { layout {
column: 0; column: 0;
row: 2; row: 3;
} }
} }
} }