mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
Implemented Power Profile management
This commit is contained in:
parent
cdb977fd54
commit
e58663f7a9
@ -48,6 +48,7 @@ fn main() {
|
||||
println!("GPU Model: {}", gpu_info.card_model);
|
||||
println!("Driver in use: {}", gpu_info.driver);
|
||||
print!("VBIOS Version: {}", gpu_info.vbios_version);
|
||||
println!("{:?}", gpu_info);
|
||||
},
|
||||
Opt::StartFanControl { gpu_id } => {
|
||||
println!("{:?}", d.start_fan_control(gpu_id));
|
||||
|
@ -1,6 +1,8 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::{BTreeMap, HashMap}, fs, io, path::PathBuf};
|
||||
|
||||
use crate::gpu_controller::PowerProfile;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ConfigError {
|
||||
IoError(io::Error),
|
||||
@ -38,6 +40,7 @@ pub struct GpuConfig {
|
||||
pub fan_control_enabled: bool,
|
||||
pub fan_curve: BTreeMap<i32, f64>,
|
||||
pub power_cap: i32,
|
||||
pub power_profile: PowerProfile,
|
||||
}
|
||||
|
||||
impl GpuConfig {
|
||||
@ -53,6 +56,7 @@ impl GpuConfig {
|
||||
fan_curve,
|
||||
fan_control_enabled: false,
|
||||
power_cap: -1,
|
||||
power_profile: PowerProfile::Auto,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{Action, DaemonError, DaemonResponse, SOCK_PATH, gpu_controller::GpuInfo, gpu_controller::{FanControlInfo, GpuStats}};
|
||||
use crate::{Action, DaemonError, DaemonResponse, gpu_controller::PowerProfile, SOCK_PATH, gpu_controller::GpuInfo, gpu_controller::{FanControlInfo, GpuStats}};
|
||||
use std::{collections::HashMap, os::unix::net::UnixStream}; use std::{ collections::BTreeMap, io::{Read, Write}, };
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
@ -181,6 +181,22 @@ impl DaemonConnection {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_power_profile(&self, gpu_id: u32, profile: PowerProfile) -> Result<(), DaemonError> {
|
||||
let mut s = UnixStream::connect(SOCK_PATH).unwrap();
|
||||
s.write_all(&bincode::serialize(&Action::SetPowerProfile(gpu_id, profile)).unwrap())
|
||||
.unwrap();
|
||||
s.shutdown(std::net::Shutdown::Write).expect("Could not shut down");
|
||||
let mut buffer = Vec::<u8>::new();
|
||||
s.read_to_end(&mut buffer).unwrap();
|
||||
|
||||
let result: Result<DaemonResponse, DaemonError> = bincode::deserialize(&buffer).unwrap();
|
||||
|
||||
match result {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_gpus(&self) -> Result<HashMap<u32, String>, DaemonError> {
|
||||
log::trace!("sending request");
|
||||
let mut s = UnixStream::connect(SOCK_PATH).unwrap();
|
||||
|
@ -5,6 +5,42 @@ use std::path::{Path, PathBuf};
|
||||
use std::{collections::BTreeMap, fs};
|
||||
use vulkano::instance::{Instance, InstanceExtensions, PhysicalDevice};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum GpuControllerError {
|
||||
NotSupported,
|
||||
ParseError,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub enum PowerProfile {
|
||||
Auto,
|
||||
Low,
|
||||
High,
|
||||
}
|
||||
|
||||
impl Default for PowerProfile {
|
||||
fn default() -> Self { PowerProfile::Auto }
|
||||
}
|
||||
|
||||
impl PowerProfile {
|
||||
pub fn from_str(profile: &str) -> Result<Self, GpuControllerError> {
|
||||
match profile {
|
||||
"auto" | "Automatic" => Ok(PowerProfile::Auto),
|
||||
"high" | "Highest Clocks" => Ok(PowerProfile::High),
|
||||
"low" | "Lowest Clocks" => Ok(PowerProfile::Low),
|
||||
_ => Err(GpuControllerError::ParseError),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
match self {
|
||||
PowerProfile::Auto => "auto".to_string(),
|
||||
PowerProfile::High => "high".to_string(),
|
||||
PowerProfile::Low => "low".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct GpuStats {
|
||||
pub mem_used: u64,
|
||||
@ -29,7 +65,7 @@ pub struct FanControlInfo {
|
||||
pub struct GpuController {
|
||||
pub hw_path: PathBuf,
|
||||
hw_mon: Option<HWMon>,
|
||||
pub gpu_info: GpuInfo,
|
||||
//pub gpu_info: GpuInfo,
|
||||
config: GpuConfig,
|
||||
}
|
||||
|
||||
@ -55,32 +91,19 @@ pub struct GpuInfo {
|
||||
pub link_width: u8,
|
||||
pub vulkan_info: VulkanInfo,
|
||||
pub pci_slot: String,
|
||||
pub power_profile: PowerProfile,
|
||||
}
|
||||
|
||||
impl GpuController {
|
||||
pub fn new(hw_path: PathBuf, config: GpuConfig) -> Self {
|
||||
let hw_mon = match fs::read_dir(&hw_path.join("hwmon")) {
|
||||
Ok(mut path) => {
|
||||
let path = path.next().unwrap().unwrap().path();
|
||||
let hw_mon = HWMon::new(
|
||||
&path,
|
||||
config.fan_control_enabled,
|
||||
config.fan_curve.clone(),
|
||||
config.power_cap,
|
||||
);
|
||||
Some(hw_mon)
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let mut controller = GpuController {
|
||||
hw_path: hw_path.clone(),
|
||||
hw_mon,
|
||||
gpu_info: Default::default(),
|
||||
config,
|
||||
hw_mon: None,
|
||||
config: GpuConfig::new(),
|
||||
};
|
||||
controller.gpu_info = controller.get_info();
|
||||
log::trace!("{:?}", controller.gpu_info);
|
||||
|
||||
controller.load_config(config);
|
||||
|
||||
controller
|
||||
}
|
||||
|
||||
@ -99,6 +122,7 @@ impl GpuController {
|
||||
_ => None,
|
||||
};
|
||||
|
||||
self.set_power_profile(config.power_profile).unwrap();
|
||||
}
|
||||
|
||||
pub fn get_config(&self) -> GpuConfig {
|
||||
@ -106,14 +130,15 @@ impl GpuController {
|
||||
}
|
||||
|
||||
pub fn get_identifier(&self) -> GpuIdentifier {
|
||||
GpuIdentifier { pci_id: self.gpu_info.pci_slot.clone(),
|
||||
card_model: self.gpu_info.card_model.clone(),
|
||||
gpu_model: self.gpu_info.gpu_model.clone(),
|
||||
let gpu_info = self.get_info();
|
||||
GpuIdentifier { pci_id: gpu_info.pci_slot.clone(),
|
||||
card_model: gpu_info.card_model.clone(),
|
||||
gpu_model: gpu_info.gpu_model.clone(),
|
||||
path: self.hw_path.clone() }
|
||||
|
||||
}
|
||||
|
||||
fn get_info(&self) -> GpuInfo {
|
||||
pub fn get_info(&self) -> GpuInfo {
|
||||
let uevent =
|
||||
fs::read_to_string(self.hw_path.join("uevent")).expect("Failed to read uevent");
|
||||
|
||||
@ -213,6 +238,11 @@ impl GpuController {
|
||||
|
||||
let vulkan_info = GpuController::get_vulkan_info(&model_id);
|
||||
|
||||
let power_profile = match self.get_power_profile() {
|
||||
Ok(p) => p,
|
||||
Err(_) => PowerProfile::Auto,
|
||||
};
|
||||
|
||||
GpuInfo {
|
||||
gpu_vendor: vendor,
|
||||
gpu_model: model,
|
||||
@ -227,6 +257,7 @@ impl GpuController {
|
||||
link_width,
|
||||
vulkan_info,
|
||||
pci_slot,
|
||||
power_profile,
|
||||
}
|
||||
}
|
||||
|
||||
@ -336,6 +367,25 @@ impl GpuController {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_power_profile(&self) -> Result<PowerProfile, GpuControllerError> {
|
||||
match fs::read_to_string(self.hw_path.join("power_dpm_force_performance_level")) {
|
||||
Ok(s) => {
|
||||
Ok(PowerProfile::from_str(&s.trim()).unwrap())
|
||||
},
|
||||
Err(_) => Err(GpuControllerError::NotSupported),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_power_profile(&mut self, profile: PowerProfile) -> Result<(), GpuControllerError> {
|
||||
match fs::write(self.hw_path.join("power_dpm_force_performance_level"), profile.to_string()) {
|
||||
Ok(_) => {
|
||||
self.config.power_profile = profile;
|
||||
Ok(())
|
||||
},
|
||||
Err(_) => Err(GpuControllerError::NotSupported),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_vulkan_info(pci_id: &str) -> VulkanInfo {
|
||||
let mut device_name = String::from("Not supported");
|
||||
let mut api_version = String::new();
|
||||
|
@ -4,6 +4,7 @@ pub mod gpu_controller;
|
||||
pub mod hw_mon;
|
||||
|
||||
use config::{Config, GpuConfig};
|
||||
use gpu_controller::PowerProfile;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::{BTreeMap, HashMap}, fs};
|
||||
use std::os::unix::net::{UnixListener, UnixStream};
|
||||
@ -37,6 +38,7 @@ pub enum Action {
|
||||
SetFanCurve(u32, BTreeMap<i32, f64>),
|
||||
SetPowerCap(u32, i32),
|
||||
GetPowerCap(u32),
|
||||
SetPowerProfile(u32, PowerProfile),
|
||||
Shutdown,
|
||||
}
|
||||
|
||||
@ -87,9 +89,10 @@ impl Daemon {
|
||||
log::info!("Initializing {:?}", entry.path());
|
||||
|
||||
let mut controller = GpuController::new(entry.path().join("device"), GpuConfig::new());
|
||||
let gpu_info = controller.get_info();
|
||||
|
||||
for (id, (gpu_identifier, gpu_config)) in &config.gpu_configs {
|
||||
if controller.gpu_info.pci_slot == gpu_identifier.pci_id && controller.gpu_info.card_model == gpu_identifier.card_model && controller.gpu_info.gpu_model == gpu_identifier.gpu_model {
|
||||
for (id, (gpu_identifier, gpu_config)) in &config.gpu_configs {
|
||||
if gpu_info.pci_slot == gpu_identifier.pci_id && gpu_info.card_model == gpu_identifier.card_model && gpu_info.gpu_model == gpu_identifier.gpu_model {
|
||||
controller.load_config(gpu_config.clone());
|
||||
gpu_controllers.insert(id.clone(), controller);
|
||||
log::info!("already known");
|
||||
@ -106,7 +109,9 @@ impl Daemon {
|
||||
}
|
||||
}
|
||||
}
|
||||
config.save().unwrap();
|
||||
if !unprivileged {
|
||||
config.save().unwrap();
|
||||
}
|
||||
|
||||
Daemon {
|
||||
listener,
|
||||
@ -149,8 +154,8 @@ impl Daemon {
|
||||
Action::CheckAlive => Ok(DaemonResponse::OK),
|
||||
Action::GetGpus => {
|
||||
let mut gpus: HashMap<u32, String> = HashMap::new();
|
||||
for controller in &self.gpu_controllers {
|
||||
gpus.insert(*controller.0, controller.1.gpu_info.gpu_model.clone());
|
||||
for (id, controller) in &self.gpu_controllers {
|
||||
gpus.insert(*id, controller.get_info().gpu_model.clone());
|
||||
}
|
||||
Ok(DaemonResponse::Gpus(gpus))
|
||||
},
|
||||
@ -159,7 +164,7 @@ impl Daemon {
|
||||
None => Err(DaemonError::InvalidID),
|
||||
},
|
||||
Action::GetInfo(i) => match self.gpu_controllers.get(&i) {
|
||||
Some(controller) => Ok(DaemonResponse::GpuInfo(controller.gpu_info.clone())),
|
||||
Some(controller) => Ok(DaemonResponse::GpuInfo(controller.get_info())),
|
||||
None => Err(DaemonError::InvalidID),
|
||||
},
|
||||
Action::StartFanControl(i) => match self.gpu_controllers.get_mut(&i) {
|
||||
@ -226,6 +231,19 @@ impl Daemon {
|
||||
}
|
||||
None => Err(DaemonError::InvalidID),
|
||||
}
|
||||
Action::SetPowerProfile(i, profile) => match self.gpu_controllers.get_mut(&i) {
|
||||
Some(controller) => {
|
||||
match controller.set_power_profile(profile) {
|
||||
Ok(_) => {
|
||||
self.config.gpu_configs.insert(i, (controller.get_identifier(), controller.get_config()));
|
||||
self.config.save().unwrap();
|
||||
Ok(DaemonResponse::OK)
|
||||
},
|
||||
Err(_) => Err(DaemonError::ControllerError)
|
||||
}
|
||||
},
|
||||
None => Err(DaemonError::InvalidID),
|
||||
}
|
||||
Action::Shutdown => {
|
||||
for (_, controller) in &mut self.gpu_controllers {
|
||||
controller.stop_fan_control().expect("Failed to stop fan control");
|
||||
@ -264,4 +282,5 @@ pub enum DaemonError {
|
||||
ConnectionFailed,
|
||||
InvalidID,
|
||||
HWMonError,
|
||||
ControllerError,
|
||||
}
|
||||
|
194
gui/src/main.rs
194
gui/src/main.rs
@ -2,14 +2,24 @@ extern crate gdk;
|
||||
extern crate gio;
|
||||
extern crate gtk;
|
||||
|
||||
use daemon::{Daemon, daemon_connection::DaemonConnection};
|
||||
use daemon::{daemon_connection::DaemonConnection, gpu_controller::PowerProfile, Daemon};
|
||||
use gio::prelude::*;
|
||||
use gtk::{Adjustment, Button, ButtonsType, ComboBoxText, DialogFlags, Frame, Label, LevelBar, MessageType, Switch, prelude::*};
|
||||
use gtk::{
|
||||
prelude::*, Adjustment, Button, ButtonsType, ComboBoxText, DialogFlags, Frame, Label, LevelBar,
|
||||
MessageType, Switch,
|
||||
};
|
||||
|
||||
use gtk::{Builder, MessageDialog, TextBuffer, Window};
|
||||
use pango::EllipsizeMode;
|
||||
|
||||
use std::{collections::BTreeMap, env::args, fs, sync::{Arc, RwLock}, thread, time::Duration};
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
env::args,
|
||||
fs,
|
||||
sync::{Arc, RwLock},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
fn build_ui(application: >k::Application) {
|
||||
let glade_src = include_str!("main_window.glade");
|
||||
@ -28,7 +38,8 @@ fn build_ui(application: >k::Application) {
|
||||
.get_object("vram_usage_label")
|
||||
.expect("Couldn't get label");
|
||||
|
||||
let gpu_select_comboboxtext: ComboBoxText = builder.get_object("gpu_select_comboboxtext").unwrap();
|
||||
let gpu_select_comboboxtext: ComboBoxText =
|
||||
builder.get_object("gpu_select_comboboxtext").unwrap();
|
||||
|
||||
let gpu_clock_text_buffer: TextBuffer = builder.get_object("gpu_clock_text_buffer").unwrap();
|
||||
|
||||
@ -43,14 +54,19 @@ fn build_ui(application: >k::Application) {
|
||||
let power_cap_label: Label = builder.get_object("power_cap_label").unwrap();
|
||||
|
||||
let apply_button: Button = builder.get_object("apply_button").unwrap();
|
||||
|
||||
|
||||
let automatic_fan_control_switch: Switch =
|
||||
builder.get_object("automatic_fan_control_switch").unwrap();
|
||||
|
||||
let fan_curve_frame: Frame = builder.get_object("fan_curve_frame").unwrap();
|
||||
|
||||
|
||||
let gpu_power_adjustment: Adjustment = builder.get_object("gpu_power_adjustment").unwrap();
|
||||
|
||||
let power_profile_select_comboboxtext: ComboBoxText = builder
|
||||
.get_object("power_profile_select_comboboxtext")
|
||||
.unwrap();
|
||||
|
||||
let power_profile_description_label: Label = builder.get_object("power_profile_description_label").unwrap();
|
||||
|
||||
let mut unpriviliged: bool = false;
|
||||
|
||||
@ -91,30 +107,103 @@ fn build_ui(application: >k::Application) {
|
||||
cell.set_property("ellipsize", &EllipsizeMode::End).unwrap();
|
||||
}
|
||||
|
||||
let current_gpu_id = Arc::new(RwLock::new(0u32));
|
||||
let current_gpu_id = Arc::new(RwLock::new(0u32));
|
||||
|
||||
let build = builder.clone();
|
||||
|
||||
let b = apply_button.clone();
|
||||
gpu_power_adjustment.connect_value_changed(move |adjustment| {
|
||||
println!("changed adjustment value to {}/{}", adjustment.get_value(), adjustment.get_upper());
|
||||
println!(
|
||||
"changed adjustment value to {}/{}",
|
||||
adjustment.get_value(),
|
||||
adjustment.get_upper()
|
||||
);
|
||||
b.set_sensitive(true);
|
||||
power_cap_label.set_text(&format!("{}/{}", adjustment.get_value().floor(), adjustment.get_upper()));
|
||||
power_cap_label.set_text(&format!(
|
||||
"{}/{}",
|
||||
adjustment.get_value().floor(),
|
||||
adjustment.get_upper()
|
||||
));
|
||||
});
|
||||
|
||||
let b = apply_button.clone();
|
||||
let description_label = power_profile_description_label.clone();
|
||||
|
||||
power_profile_select_comboboxtext.connect_changed(move |combobox| {
|
||||
println!("power profile selection changed");
|
||||
b.set_sensitive(true);
|
||||
match combobox.get_active().unwrap() {
|
||||
0 => description_label.set_text("Automatically adjust core and VRAM clocks. (Default)"),
|
||||
1 => description_label.set_text("Always run the on the highest clocks."),
|
||||
2 => description_label.set_text("Always run the on the lowest clocks."),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
});
|
||||
|
||||
let cur_id = current_gpu_id.clone();
|
||||
let b = apply_button.clone();
|
||||
|
||||
|
||||
gpu_select_comboboxtext.connect_changed(move |combobox| {
|
||||
let mut current_gpu_id = cur_id.write().unwrap();
|
||||
*current_gpu_id = combobox.get_active_id().unwrap().parse::<u32>().expect("invalid id");
|
||||
*current_gpu_id = combobox
|
||||
.get_active_id()
|
||||
.unwrap()
|
||||
.parse::<u32>()
|
||||
.expect("invalid id");
|
||||
println!("Set current gpu id to {}", current_gpu_id);
|
||||
|
||||
set_info(&build, d, current_gpu_id.clone());
|
||||
|
||||
b.set_sensitive(false);
|
||||
});
|
||||
|
||||
|
||||
let cur_id = current_gpu_id.clone();
|
||||
let auto_fan_control_switch = automatic_fan_control_switch.clone();
|
||||
|
||||
apply_button.connect_clicked(move |b| {
|
||||
let gpu_id = *cur_id.read().unwrap();
|
||||
|
||||
let mut curve: BTreeMap<i32, f64> = BTreeMap::new();
|
||||
|
||||
for i in 1..6 {
|
||||
let curve_temperature_adjustment: Adjustment = builder
|
||||
.get_object(&format!("curve_temperature_adjustment_{}", i))
|
||||
.unwrap();
|
||||
|
||||
curve.insert(20 * i, curve_temperature_adjustment.get_value());
|
||||
|
||||
}
|
||||
|
||||
println!("setting curve to {:?}", curve);
|
||||
d.set_fan_curve(gpu_id, curve).unwrap();
|
||||
b.set_sensitive(false);
|
||||
|
||||
match auto_fan_control_switch.get_active() {
|
||||
true => {
|
||||
d.stop_fan_control(gpu_id).unwrap();
|
||||
|
||||
let diag = MessageDialog::new(
|
||||
None::<&Window>,
|
||||
DialogFlags::empty(),
|
||||
MessageType::Error,
|
||||
ButtonsType::Ok,
|
||||
"WARNING: Due to a driver bug, the GPU fan may misbehave after switching to automatic control. You may need to reboot your system to avoid issues.",
|
||||
);
|
||||
diag.run();
|
||||
diag.hide();
|
||||
}
|
||||
false => {
|
||||
d.start_fan_control(gpu_id).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
let power_cap = gpu_power_adjustment.get_value().floor() as i32;
|
||||
d.set_power_cap(gpu_id, power_cap).unwrap();
|
||||
|
||||
d.set_power_profile(gpu_id, PowerProfile::from_str(&power_profile_select_comboboxtext.get_active_text().unwrap()).unwrap()).unwrap();
|
||||
|
||||
set_info(&builder, d, gpu_id);
|
||||
});
|
||||
|
||||
//gpu_select_comboboxtext.set_active_id(Some(¤t_gpu_id.to_string()));
|
||||
@ -159,7 +248,6 @@ fn build_ui(application: >k::Application) {
|
||||
(gpu_stats.fan_speed as f64 / gpu_stats.max_fan_speed as f64 * 100 as f64) as i32
|
||||
));
|
||||
|
||||
|
||||
glib::Continue(true)
|
||||
});
|
||||
|
||||
@ -179,8 +267,6 @@ fn build_ui(application: >k::Application) {
|
||||
b.set_sensitive(true);
|
||||
});
|
||||
|
||||
|
||||
|
||||
main_window.set_application(Some(application));
|
||||
|
||||
main_window.show();
|
||||
@ -190,7 +276,9 @@ fn set_info(builder: &Builder, d: DaemonConnection, gpu_id: u32) {
|
||||
let gpu_model_text_buffer: TextBuffer = builder
|
||||
.get_object("gpu_model_text_buffer")
|
||||
.expect("Couldn't get textbuffer");
|
||||
let vbios_version_text_buffer: TextBuffer = builder .get_object("vbios_version_text_buffer") .expect("Couldn't get textbuffer");
|
||||
let vbios_version_text_buffer: TextBuffer = builder
|
||||
.get_object("vbios_version_text_buffer")
|
||||
.expect("Couldn't get textbuffer");
|
||||
let driver_text_buffer: TextBuffer = builder
|
||||
.get_object("driver_text_buffer")
|
||||
.expect("Couldn't get textbuffer");
|
||||
@ -223,19 +311,23 @@ let vbios_version_text_buffer: TextBuffer = builder .get_object("vbios_version_t
|
||||
builder.get_object("automatic_fan_control_switch").unwrap();
|
||||
|
||||
let fan_curve_frame: Frame = builder.get_object("fan_curve_frame").unwrap();
|
||||
|
||||
|
||||
let gpu_power_adjustment: Adjustment = builder.get_object("gpu_power_adjustment").unwrap();
|
||||
|
||||
let apply_button: Button = builder.get_object("apply_button").unwrap();
|
||||
|
||||
let overclocking_info_frame: Frame = builder.get_object("overclocking_info_frame").unwrap();
|
||||
|
||||
let power_profile_select_comboboxtext: ComboBoxText = builder
|
||||
.get_object("power_profile_select_comboboxtext")
|
||||
.unwrap();
|
||||
|
||||
match fs::read_to_string("/proc/cmdline") {
|
||||
Ok(cmdline) => {
|
||||
if cmdline.contains("amdgpu.ppfeaturemask=") {
|
||||
overclocking_info_frame.set_visible(false);
|
||||
}
|
||||
},
|
||||
}
|
||||
Err(_) => (),
|
||||
}
|
||||
|
||||
@ -251,7 +343,15 @@ let vbios_version_text_buffer: TextBuffer = builder .get_object("vbios_version_t
|
||||
&gpu_info.link_speed, &gpu_info.link_width
|
||||
));
|
||||
|
||||
let vulkan_features = gpu_info.vulkan_info.features.replace(',', "\n").replace("Features", "").replace("{", "").replace("}", "").replace(" ", "").replace(":", ": ");
|
||||
let vulkan_features = gpu_info
|
||||
.vulkan_info
|
||||
.features
|
||||
.replace(',', "\n")
|
||||
.replace("Features", "")
|
||||
.replace("{", "")
|
||||
.replace("}", "")
|
||||
.replace(" ", "")
|
||||
.replace(":", ": ");
|
||||
|
||||
vulkan_device_name_text_buffer.set_text(&gpu_info.vulkan_info.device_name);
|
||||
vulkan_version_text_buffer.set_text(&gpu_info.vulkan_info.api_version);
|
||||
@ -262,9 +362,14 @@ let vbios_version_text_buffer: TextBuffer = builder .get_object("vbios_version_t
|
||||
gpu_power_adjustment.set_upper(power_cap_max as f64);
|
||||
gpu_power_adjustment.set_value(power_cap as f64);
|
||||
|
||||
|
||||
power_profile_select_comboboxtext.set_active(match &gpu_info.power_profile {
|
||||
PowerProfile::Auto => Some(0),
|
||||
PowerProfile::High => Some(1),
|
||||
PowerProfile::Low => Some(2),
|
||||
});
|
||||
|
||||
let fan_control = d.get_fan_control(gpu_id);
|
||||
|
||||
|
||||
match fan_control {
|
||||
Ok(ref fan_control) => {
|
||||
if fan_control.enabled {
|
||||
@ -276,73 +381,38 @@ let vbios_version_text_buffer: TextBuffer = builder .get_object("vbios_version_t
|
||||
automatic_fan_control_switch.set_active(true);
|
||||
fan_curve_frame.set_visible(false);
|
||||
}
|
||||
},
|
||||
}
|
||||
Err(_) => {
|
||||
automatic_fan_control_switch.set_sensitive(false);
|
||||
automatic_fan_control_switch.set_tooltip_text(Some("Unavailable"));
|
||||
|
||||
|
||||
fan_curve_frame.set_visible(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
match fan_control {
|
||||
Ok(fan_control) => {
|
||||
|
||||
let curve: Arc<RwLock<BTreeMap<i32, f64>>> = Arc::new(RwLock::new(fan_control.curve));
|
||||
//let curve: Arc<RwLock<BTreeMap<i32, f64>>> = Arc::new(RwLock::new(fan_control.curve));
|
||||
|
||||
for i in 1..6 {
|
||||
let curve_temperature_adjustment: Adjustment = builder
|
||||
.get_object(&format!("curve_temperature_adjustment_{}", i))
|
||||
.unwrap();
|
||||
|
||||
let value = *curve
|
||||
.read()
|
||||
.unwrap()
|
||||
let value = *fan_control.curve
|
||||
.get(&(i * 20))
|
||||
.expect("Could not get by index");
|
||||
println!("Setting value {} on adjustment {}", value, i);
|
||||
curve_temperature_adjustment.set_value(value);
|
||||
|
||||
let c = curve.clone();
|
||||
let b = apply_button.clone();
|
||||
|
||||
curve_temperature_adjustment.connect_value_changed(move |adj| {
|
||||
c.write().unwrap().insert(20 * i, adj.get_value());
|
||||
curve_temperature_adjustment.connect_value_changed(move |_| {
|
||||
b.set_sensitive(true);
|
||||
});
|
||||
}
|
||||
|
||||
apply_button.connect_clicked(move |b| {
|
||||
//let current_gpu_id = *current_gpu_id.read().unwrap();
|
||||
|
||||
let curve = curve.read().unwrap().clone();
|
||||
println!("setting curve to {:?}", curve);
|
||||
d.set_fan_curve(gpu_id, curve).unwrap();
|
||||
b.set_sensitive(false);
|
||||
|
||||
match automatic_fan_control_switch.get_active() {
|
||||
true => {
|
||||
d.stop_fan_control(gpu_id).unwrap();
|
||||
|
||||
let diag = MessageDialog::new(
|
||||
None::<&Window>,
|
||||
DialogFlags::empty(),
|
||||
MessageType::Error,
|
||||
ButtonsType::Ok,
|
||||
"WARNING: Due to a driver bug, the GPU fan may misbehave after switching to automatic control. You may need to reboot your system to avoid issues.",
|
||||
);
|
||||
diag.run();
|
||||
diag.hide();
|
||||
}
|
||||
false => {
|
||||
d.start_fan_control(gpu_id).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
let power_cap = gpu_power_adjustment.get_value().floor() as i32;
|
||||
d.set_power_cap(gpu_id, power_cap).unwrap();
|
||||
});
|
||||
},
|
||||
}
|
||||
Err(_) => (),
|
||||
}
|
||||
}
|
||||
|
@ -50,20 +50,6 @@
|
||||
<object class="GtkTextBuffer" id="gpu_temp_text_buffer">
|
||||
<property name="text" translatable="yes">100°C</property>
|
||||
</object>
|
||||
<object class="GtkListStore" id="gpus_list_store">
|
||||
<columns>
|
||||
<!-- column-name name -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
<data>
|
||||
<row>
|
||||
<col id="0" translatable="yes">test</col>
|
||||
</row>
|
||||
<row>
|
||||
<col id="0" translatable="yes">test1</col>
|
||||
</row>
|
||||
</data>
|
||||
</object>
|
||||
<object class="GtkTextBuffer" id="link_speed_text_buffer">
|
||||
<property name="text" translatable="yes">1.0 GT/s PCIe x1</property>
|
||||
</object>
|
||||
@ -521,116 +507,6 @@
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label" translatable="yes">Power Usage</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTextView">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">7</property>
|
||||
<property name="editable">False</property>
|
||||
<property name="cursor-visible">False</property>
|
||||
<property name="buffer">gpu_power_text_buffer</property>
|
||||
<property name="accepts-tab">False</property>
|
||||
<property name="monospace">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label-xalign">0.10000000149011612</property>
|
||||
<property name="shadow-type">none</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="power_cap_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">50/100</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScale" id="power_cap_scale">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="adjustment">gpu_power_adjustment</property>
|
||||
<property name="restrict-to-fill-level">False</property>
|
||||
<property name="fill-level">0</property>
|
||||
<property name="round-digits">0</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="draw-value">False</property>
|
||||
<property name="value-pos">left</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">Power Cap (Watts)</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="semibold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<!-- n-columns=2 n-rows=2 -->
|
||||
<object class="GtkGrid">
|
||||
@ -788,12 +664,189 @@
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label" translatable="yes">Power Usage</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTextView">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">7</property>
|
||||
<property name="editable">False</property>
|
||||
<property name="cursor-visible">False</property>
|
||||
<property name="buffer">gpu_power_text_buffer</property>
|
||||
<property name="accepts-tab">False</property>
|
||||
<property name="monospace">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="label-xalign">0.10000000149011612</property>
|
||||
<property name="shadow-type">none</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="power_cap_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">50/100</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScale" id="power_cap_scale">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="adjustment">gpu_power_adjustment</property>
|
||||
<property name="restrict-to-fill-level">False</property>
|
||||
<property name="fill-level">0</property>
|
||||
<property name="round-digits">0</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="draw-value">False</property>
|
||||
<property name="value-pos">left</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">Power Cap (Watts)</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="semibold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label-xalign">0.10000000149011612</property>
|
||||
<property name="shadow-type">none</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="power_profile_select_comboboxtext">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<items>
|
||||
<item translatable="yes">Automatic</item>
|
||||
<item translatable="yes">Highest Clocks</item>
|
||||
<item translatable="yes">Lowest Clocks</item>
|
||||
</items>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="power_profile_description_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="label" translatable="yes">Description of the selected power profile</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">Power Profile</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="semibold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
|
Loading…
Reference in New Issue
Block a user