mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
feat: configurable graphs period (#431)
* chore: update test snapshot * feat: configurable graphs period
This commit is contained in:
@@ -46,84 +46,19 @@ expression: device_info
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
4
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
800
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
3
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
800,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
1,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
@@ -135,84 +70,19 @@ expression: device_info
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
4
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
650
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
650,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
@@ -224,84 +94,19 @@ expression: device_info
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
3
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
@@ -313,84 +118,19 @@ expression: device_info
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
4
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
@@ -402,84 +142,19 @@ expression: device_info
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
4
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1000
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
4,
|
||||
1,
|
||||
1000,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
@@ -491,84 +166,19 @@ expression: device_info
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
4
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1000
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
4,
|
||||
1,
|
||||
1000,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
@@ -580,84 +190,19 @@ expression: device_info
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
4
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
800
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
3
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
800,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
1,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
@@ -669,84 +214,19 @@ expression: device_info
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
4
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
650
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
3
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"clock_type": null,
|
||||
"values": [
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
650,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
1,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
@@ -787,6 +267,7 @@ expression: device_info
|
||||
"speed_min": 0
|
||||
},
|
||||
"memory_power_state": 0,
|
||||
"performance_level": "auto",
|
||||
"power": {
|
||||
"average": 1.0,
|
||||
"cap_current": 100.0,
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::{APP_ID, GUI_VERSION};
|
||||
use anyhow::{anyhow, Context};
|
||||
use apply_revealer::{ApplyRevealer, ApplyRevealerMsg};
|
||||
use confirmation_dialog::ConfirmationDialog;
|
||||
use graphs_window::GraphsWindow;
|
||||
use graphs_window::{GraphsWindow, GraphsWindowMsg};
|
||||
use gtk::{
|
||||
glib::{self, clone, ControlFlow},
|
||||
prelude::{
|
||||
@@ -46,7 +46,7 @@ const STATS_POLL_INTERVAL_MS: u64 = 250;
|
||||
|
||||
pub struct AppModel {
|
||||
daemon_client: DaemonClient,
|
||||
graphs_window: GraphsWindow,
|
||||
graphs_window: relm4::Controller<GraphsWindow>,
|
||||
|
||||
info_page: relm4::Controller<InformationPage>,
|
||||
oc_page: OcPage,
|
||||
@@ -212,7 +212,7 @@ impl AsyncComponent for AppModel {
|
||||
));
|
||||
}
|
||||
|
||||
let graphs_window = GraphsWindow::new();
|
||||
let graphs_window = GraphsWindow::builder().launch(()).detach();
|
||||
|
||||
let model = AppModel {
|
||||
daemon_client,
|
||||
@@ -297,7 +297,8 @@ impl AppModel {
|
||||
|
||||
self.thermals_page.set_stats(&stats, false);
|
||||
self.oc_page.set_stats(&stats, false);
|
||||
self.graphs_window.set_stats(&stats);
|
||||
|
||||
self.graphs_window.emit(GraphsWindowMsg::Stats(stats));
|
||||
}
|
||||
AppMsg::ApplyChanges => {
|
||||
self.apply_settings(self.current_gpu_id()?, root, &sender)
|
||||
@@ -328,7 +329,7 @@ impl AppModel {
|
||||
sender.input(AppMsg::ReloadData { full: false });
|
||||
}
|
||||
AppMsg::ShowGraphsWindow => {
|
||||
self.graphs_window.show();
|
||||
self.graphs_window.emit(GraphsWindowMsg::Show);
|
||||
}
|
||||
AppMsg::DumpVBios => {
|
||||
self.dump_vbios(&self.current_gpu_id()?, root).await;
|
||||
@@ -405,13 +406,14 @@ impl AppModel {
|
||||
.as_ref()
|
||||
.map(|info| info.vram_clock_ratio)
|
||||
.unwrap_or(1.0);
|
||||
self.graphs_window.set_vram_clock_ratio(vram_clock_ratio);
|
||||
self.graphs_window
|
||||
.emit(GraphsWindowMsg::VramClockRatio(vram_clock_ratio));
|
||||
|
||||
self.update_gpu_data(gpu_id, sender).await?;
|
||||
|
||||
self.thermals_page.set_info(&info);
|
||||
|
||||
self.graphs_window.clear();
|
||||
self.graphs_window.emit(GraphsWindowMsg::Clear);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,185 +1,239 @@
|
||||
pub(crate) mod plot;
|
||||
|
||||
use self::plot::PlotData;
|
||||
use glib::Object;
|
||||
use gtk::{
|
||||
glib::{self, subclass::types::ObjectSubclassIsExt},
|
||||
prelude::WidgetExt,
|
||||
};
|
||||
use lact_client::schema::DeviceStats;
|
||||
use gtk::prelude::*;
|
||||
use lact_schema::DeviceStats;
|
||||
use plot::{Plot, PlotData};
|
||||
use relm4::{ComponentParts, ComponentSender, RelmWidgetExt};
|
||||
use std::rc::Rc;
|
||||
|
||||
const GRAPH_WIDTH_SECONDS: i64 = 60;
|
||||
pub struct GraphsWindow {
|
||||
time_period_seconds_adj: gtk::Adjustment,
|
||||
vram_clock_ratio: f64,
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct GraphsWindow(ObjectSubclass<imp::GraphsWindow>)
|
||||
@extends gtk::Box, gtk::Widget, gtk::Window,
|
||||
@implements gtk::Orientable, gtk::Accessible, gtk::Buildable;
|
||||
#[derive(Debug)]
|
||||
pub enum GraphsWindowMsg {
|
||||
Stats(Rc<DeviceStats>),
|
||||
VramClockRatio(f64),
|
||||
Refresh,
|
||||
Show,
|
||||
Clear,
|
||||
}
|
||||
|
||||
#[relm4::component(pub)]
|
||||
impl relm4::Component for GraphsWindow {
|
||||
type Init = ();
|
||||
type Input = GraphsWindowMsg;
|
||||
type Output = ();
|
||||
type CommandOutput = ();
|
||||
|
||||
view! {
|
||||
gtk::Window {
|
||||
set_default_height: 400,
|
||||
set_default_width: 1200,
|
||||
set_title: Some("Historical data"),
|
||||
set_hide_on_close: true,
|
||||
|
||||
gtk::Grid {
|
||||
set_margin_all: 10,
|
||||
set_row_spacing: 20,
|
||||
set_column_spacing: 20,
|
||||
|
||||
attach[0, 0, 1, 1]: temperature_plot = &Plot {
|
||||
set_title: "Temperature",
|
||||
set_hexpand: true,
|
||||
set_value_suffix: "°C",
|
||||
set_y_label_area_relative_size: 0.15,
|
||||
#[watch]
|
||||
set_time_period_seconds: model.time_period_seconds_adj.value() as i64,
|
||||
},
|
||||
|
||||
attach[0, 1, 1, 1]: fan_plot = &Plot {
|
||||
set_title: "Fan speed",
|
||||
set_hexpand: true,
|
||||
set_value_suffix: "RPM",
|
||||
set_y_label_area_relative_size: 0.25,
|
||||
set_secondary_y_label_area_relative_size: 0.15,
|
||||
#[watch]
|
||||
set_time_period_seconds: model.time_period_seconds_adj.value() as i64,
|
||||
},
|
||||
|
||||
attach[1, 0, 1, 1]: clockspeed_plot = &Plot {
|
||||
set_title: "Clockspeed",
|
||||
set_hexpand: true,
|
||||
set_value_suffix: "MHz",
|
||||
set_y_label_area_relative_size: 0.3,
|
||||
#[watch]
|
||||
set_time_period_seconds: model.time_period_seconds_adj.value() as i64,
|
||||
},
|
||||
|
||||
attach[1, 1, 1, 1]: power_plot = &Plot {
|
||||
set_title: "Power usage",
|
||||
set_hexpand: true,
|
||||
set_value_suffix: "W",
|
||||
set_y_label_area_relative_size: 0.2,
|
||||
#[watch]
|
||||
set_time_period_seconds: model.time_period_seconds_adj.value() as i64,
|
||||
},
|
||||
|
||||
attach[1, 2, 1, 1] = >k::Box {
|
||||
set_halign: gtk::Align::End,
|
||||
set_spacing: 5,
|
||||
|
||||
gtk::Label {
|
||||
set_label: "Time period (seconds):"
|
||||
},
|
||||
|
||||
gtk::SpinButton {
|
||||
set_adjustment: &model.time_period_seconds_adj,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn init(
|
||||
_init: Self::Init,
|
||||
root: Self::Root,
|
||||
sender: ComponentSender<Self>,
|
||||
) -> ComponentParts<Self> {
|
||||
let time_period_seconds_adj = gtk::Adjustment::new(60.0, 15.0, 3601.0, 1.0, 1.0, 1.0);
|
||||
|
||||
time_period_seconds_adj.connect_value_changed(move |_| {
|
||||
sender.input(GraphsWindowMsg::Refresh);
|
||||
});
|
||||
|
||||
let model = Self {
|
||||
time_period_seconds_adj,
|
||||
vram_clock_ratio: 1.0,
|
||||
};
|
||||
|
||||
let widgets = view_output!();
|
||||
|
||||
ComponentParts { model, widgets }
|
||||
}
|
||||
|
||||
fn update_with_view(
|
||||
&mut self,
|
||||
widgets: &mut Self::Widgets,
|
||||
msg: Self::Input,
|
||||
sender: ComponentSender<Self>,
|
||||
root: &Self::Root,
|
||||
) {
|
||||
match msg {
|
||||
GraphsWindowMsg::Refresh => {}
|
||||
GraphsWindowMsg::Show => {
|
||||
root.show();
|
||||
}
|
||||
GraphsWindowMsg::VramClockRatio(ratio) => {
|
||||
self.vram_clock_ratio = ratio;
|
||||
}
|
||||
GraphsWindowMsg::Stats(stats) => {
|
||||
let mut temperature_plot = widgets.temperature_plot.data_mut();
|
||||
let mut clockspeed_plot = widgets.clockspeed_plot.data_mut();
|
||||
let mut power_plot = widgets.power_plot.data_mut();
|
||||
let mut fan_plot = widgets.fan_plot.data_mut();
|
||||
|
||||
let throttling_plots =
|
||||
[&mut temperature_plot, &mut clockspeed_plot, &mut power_plot];
|
||||
match &stats.throttle_info {
|
||||
Some(throttle_info) => {
|
||||
if throttle_info.is_empty() {
|
||||
for plot in throttling_plots {
|
||||
plot.push_throttling("No", false);
|
||||
}
|
||||
} else {
|
||||
let type_text: Vec<String> = throttle_info
|
||||
.iter()
|
||||
.map(|(throttle_type, details)| {
|
||||
format!("{throttle_type} ({})", details.join(", "))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let text = type_text.join(", ");
|
||||
|
||||
for plot in throttling_plots {
|
||||
plot.push_throttling(&text, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
for plot in throttling_plots {
|
||||
plot.push_throttling("Unknown", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (name, value) in &stats.temps {
|
||||
temperature_plot.push_line_series(name, value.current.unwrap_or(0.0) as f64);
|
||||
}
|
||||
|
||||
if let Some(average) = stats.power.average {
|
||||
power_plot.push_line_series("Average", average);
|
||||
}
|
||||
if let Some(current) = stats.power.current {
|
||||
power_plot.push_line_series("Current", current);
|
||||
}
|
||||
if let Some(limit) = stats.power.cap_current {
|
||||
power_plot.push_line_series("Limit", limit);
|
||||
}
|
||||
|
||||
if let Some(point) = stats.clockspeed.gpu_clockspeed {
|
||||
clockspeed_plot.push_line_series("GPU (Avg)", point as f64);
|
||||
}
|
||||
if let Some(point) = stats.clockspeed.current_gfxclk {
|
||||
clockspeed_plot.push_line_series("GPU (Trgt)", point as f64);
|
||||
}
|
||||
if let Some(point) = stats.clockspeed.vram_clockspeed {
|
||||
clockspeed_plot.push_line_series("VRAM", point as f64 * self.vram_clock_ratio);
|
||||
}
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
||||
let time_period_seconds = self.time_period_seconds_adj.value() as i64;
|
||||
temperature_plot.trim_data(time_period_seconds);
|
||||
clockspeed_plot.trim_data(time_period_seconds);
|
||||
power_plot.trim_data(time_period_seconds);
|
||||
fan_plot.trim_data(time_period_seconds);
|
||||
|
||||
Self::queue_plots_draw(widgets);
|
||||
}
|
||||
GraphsWindowMsg::Clear => {
|
||||
*widgets.temperature_plot.data_mut() = PlotData::default();
|
||||
*widgets.clockspeed_plot.data_mut() = PlotData::default();
|
||||
*widgets.power_plot.data_mut() = PlotData::default();
|
||||
*widgets.fan_plot.data_mut() = PlotData::default();
|
||||
|
||||
Self::queue_plots_draw(widgets);
|
||||
}
|
||||
}
|
||||
|
||||
self.update_view(widgets, sender);
|
||||
}
|
||||
}
|
||||
|
||||
impl GraphsWindow {
|
||||
pub fn new() -> Self {
|
||||
Object::builder().property("vram_clock_ratio", 1.0).build()
|
||||
}
|
||||
|
||||
pub fn set_stats(&self, stats: &DeviceStats) {
|
||||
let imp = self.imp();
|
||||
|
||||
let mut temperature_plot = imp.temperature_plot.data_mut();
|
||||
let mut clockspeed_plot = imp.clockspeed_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];
|
||||
match &stats.throttle_info {
|
||||
Some(throttle_info) => {
|
||||
if throttle_info.is_empty() {
|
||||
for plot in throttling_plots {
|
||||
plot.push_throttling("No", false);
|
||||
}
|
||||
} else {
|
||||
let type_text: Vec<String> = throttle_info
|
||||
.iter()
|
||||
.map(|(throttle_type, details)| {
|
||||
format!("{throttle_type} ({})", details.join(", "))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let text = type_text.join(", ");
|
||||
|
||||
for plot in throttling_plots {
|
||||
plot.push_throttling(&text, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
for plot in throttling_plots {
|
||||
plot.push_throttling("Unknown", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (name, value) in &stats.temps {
|
||||
temperature_plot.push_line_series(name, value.current.unwrap_or(0.0) as f64);
|
||||
}
|
||||
|
||||
if let Some(average) = stats.power.average {
|
||||
power_plot.push_line_series("Average", average);
|
||||
}
|
||||
if let Some(current) = stats.power.current {
|
||||
power_plot.push_line_series("Current", current);
|
||||
}
|
||||
if let Some(limit) = stats.power.cap_current {
|
||||
power_plot.push_line_series("Limit", limit);
|
||||
}
|
||||
|
||||
if let Some(point) = stats.clockspeed.gpu_clockspeed {
|
||||
clockspeed_plot.push_line_series("GPU (Avg)", point as f64);
|
||||
}
|
||||
if let Some(point) = stats.clockspeed.current_gfxclk {
|
||||
clockspeed_plot.push_line_series("GPU (Trgt)", point as f64);
|
||||
}
|
||||
if let Some(point) = stats.clockspeed.vram_clockspeed {
|
||||
clockspeed_plot.push_line_series("VRAM", point as f64 * self.vram_clock_ratio());
|
||||
}
|
||||
|
||||
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);
|
||||
clockspeed_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.clockspeed_plot.queue_draw();
|
||||
imp.power_plot.queue_draw();
|
||||
imp.fan_plot.queue_draw();
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
let imp = self.imp();
|
||||
*imp.temperature_plot.data_mut() = PlotData::default();
|
||||
*imp.clockspeed_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.clockspeed_plot.queue_draw();
|
||||
imp.power_plot.queue_draw();
|
||||
imp.fan_plot.queue_draw();
|
||||
fn queue_plots_draw(widgets: &<Self as relm4::Component>::Widgets) {
|
||||
widgets.temperature_plot.queue_draw();
|
||||
widgets.clockspeed_plot.queue_draw();
|
||||
widgets.power_plot.queue_draw();
|
||||
widgets.fan_plot.queue_draw();
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GraphsWindow {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
mod imp {
|
||||
use super::plot::Plot;
|
||||
use gtk::{
|
||||
glib::{self, subclass::InitializingObject, Properties},
|
||||
prelude::*,
|
||||
subclass::{
|
||||
prelude::*,
|
||||
widget::{CompositeTemplateClass, WidgetImpl},
|
||||
},
|
||||
CompositeTemplate,
|
||||
};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(CompositeTemplate, Default, Properties)]
|
||||
#[properties(wrapper_type = super::GraphsWindow)]
|
||||
#[template(file = "ui/graphs_window.blp")]
|
||||
pub struct GraphsWindow {
|
||||
#[template_child]
|
||||
pub(super) temperature_plot: TemplateChild<Plot>,
|
||||
#[template_child]
|
||||
pub(super) clockspeed_plot: TemplateChild<Plot>,
|
||||
#[template_child]
|
||||
pub(super) power_plot: TemplateChild<Plot>,
|
||||
#[template_child]
|
||||
pub(super) fan_plot: TemplateChild<Plot>,
|
||||
|
||||
#[property(get, set)]
|
||||
pub vram_clock_ratio: Cell<f64>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for GraphsWindow {
|
||||
const NAME: &'static str = "GraphsWindow";
|
||||
type Type = super::GraphsWindow;
|
||||
type ParentType = gtk::Window;
|
||||
|
||||
fn class_init(class: &mut Self::Class) {
|
||||
Plot::ensure_type();
|
||||
|
||||
class.bind_template();
|
||||
}
|
||||
|
||||
fn instance_init(obj: &InitializingObject<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for GraphsWindow {}
|
||||
|
||||
impl WidgetImpl for GraphsWindow {}
|
||||
impl WindowImpl for GraphsWindow {}
|
||||
impl ApplicationWindowImpl for GraphsWindow {}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ pub struct Plot {
|
||||
pub(super) data: RefCell<PlotData>,
|
||||
pub(super) dirty: Cell<bool>,
|
||||
render_thread: RenderThread,
|
||||
#[property(get, set)]
|
||||
time_period_seconds: Cell<i64>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
@@ -74,6 +76,7 @@ impl WidgetImpl for Plot {
|
||||
.secondary_y_label_area_relative_size
|
||||
.get(),
|
||||
supersample_factor: 4,
|
||||
time_period_seconds: self.time_period_seconds.get(),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -7,13 +7,19 @@ use std::cell::RefMut;
|
||||
|
||||
pub use imp::PlotData;
|
||||
|
||||
use gtk::glib::{self, subclass::types::ObjectSubclassIsExt};
|
||||
use gtk::glib::{self, subclass::types::ObjectSubclassIsExt, Object};
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct Plot(ObjectSubclass<imp::Plot>)
|
||||
@extends gtk::Widget;
|
||||
}
|
||||
|
||||
impl Default for Plot {
|
||||
fn default() -> Self {
|
||||
Object::builder().build()
|
||||
}
|
||||
}
|
||||
|
||||
impl Plot {
|
||||
pub fn data_mut(&self) -> RefMut<'_, PlotData> {
|
||||
self.imp().dirty.set(true);
|
||||
|
||||
@@ -35,6 +35,8 @@ pub struct RenderRequest {
|
||||
pub height: u32,
|
||||
|
||||
pub supersample_factor: u32,
|
||||
|
||||
pub time_period_seconds: i64,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -259,11 +261,11 @@ impl RenderRequest {
|
||||
("sans-serif", RelativeSize::Smaller(0.08)),
|
||||
)
|
||||
.build_cartesian_2d(
|
||||
start_date..max(end_date, start_date + 60 * 1000),
|
||||
start_date..max(end_date, start_date + self.time_period_seconds * 1000),
|
||||
0f64..maximum_value,
|
||||
)?
|
||||
.set_secondary_coord(
|
||||
start_date..max(end_date, start_date + 60 * 1000),
|
||||
start_date..max(end_date, start_date + self.time_period_seconds * 1000),
|
||||
0.0..100.0,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
using Gtk 4.0;
|
||||
|
||||
template $GraphsWindow: Window {
|
||||
default-height: 400;
|
||||
default-width: 1200;
|
||||
title: "Historical data";
|
||||
hide-on-close: true;
|
||||
|
||||
Grid {
|
||||
margin-top: 10;
|
||||
margin-bottom: 10;
|
||||
margin-start: 10;
|
||||
margin-end: 10;
|
||||
row-spacing: 20;
|
||||
column-spacing: 20;
|
||||
|
||||
$Plot temperature_plot {
|
||||
title: "Temperature";
|
||||
hexpand: true;
|
||||
value-suffix: "°C";
|
||||
y-label-area-relative-size: 0.15;
|
||||
|
||||
layout {
|
||||
column: 0;
|
||||
row: 0;
|
||||
}
|
||||
}
|
||||
|
||||
$Plot fan_plot {
|
||||
title: "Fan speed";
|
||||
hexpand: true;
|
||||
value-suffix: "RPM";
|
||||
secondary-value-suffix: "%";
|
||||
y-label-area-relative-size: 0.25;
|
||||
secondary-y-label-area-relative-size: 0.15;
|
||||
|
||||
layout {
|
||||
column: 0;
|
||||
row: 1;
|
||||
}
|
||||
}
|
||||
|
||||
$Plot clockspeed_plot {
|
||||
title: "Clockspeed";
|
||||
hexpand: true;
|
||||
value-suffix: "MHz";
|
||||
y-label-area-relative-size: 0.3;
|
||||
|
||||
layout {
|
||||
column: 1;
|
||||
row: 0;
|
||||
}
|
||||
}
|
||||
|
||||
$Plot power_plot {
|
||||
title: "Power usage";
|
||||
hexpand: true;
|
||||
value-suffix: "W";
|
||||
y-label-area-relative-size: 0.2;
|
||||
|
||||
layout {
|
||||
column: 1;
|
||||
row: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user