mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
feat: add fan speed plot (#338)
This commit is contained in:
parent
fd85122d4a
commit
3f99eab263
@ -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]
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user