Merge branch 'oc' into master

This commit is contained in:
Ilya Zlobintsev 2020-11-14 09:12:07 +02:00
commit bcbb87e74c
6 changed files with 189 additions and 12 deletions

View File

@ -148,6 +148,22 @@ impl DaemonConnection {
}
}
pub fn set_power_cap(&self, gpu_id: u32, cap: i32) -> Result<(), DaemonError> {
let mut s = UnixStream::connect(SOCK_PATH).unwrap();
s.write_all(&bincode::serialize(&Action::SetPowerCap(gpu_id, cap)).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();

View File

@ -1,4 +1,4 @@
use crate::config::{Config, GpuConfig, GpuIdentifier};
use crate::config::{GpuConfig, GpuIdentifier};
use crate::hw_mon::{HWMon, HWMonError};
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
@ -13,7 +13,8 @@ pub struct GpuStats {
pub gpu_freq: i32,
pub gpu_temp: i32,
pub power_avg: i32,
pub power_max: i32,
pub power_cap: i32,
pub power_cap_max: i32,
pub fan_speed: i32,
pub max_fan_speed: i32,
}
@ -54,6 +55,8 @@ pub struct GpuInfo {
pub link_width: u8,
pub vulkan_info: VulkanInfo,
pub pci_slot: String,
pub power_cap: i32,
pub power_cap_max: i32,
}
impl GpuController {
@ -210,6 +213,11 @@ impl GpuController {
let vulkan_info = GpuController::get_vulkan_info(&model_id);
let (power_cap, power_cap_max) = match &self.hw_mon {
Some(hw_mon) => (hw_mon.get_power_cap(), hw_mon.get_power_cap_max()),
None => (0, 0),
};
GpuInfo {
gpu_vendor: vendor,
gpu_model: model,
@ -224,6 +232,8 @@ impl GpuController {
link_width,
vulkan_info,
pci_slot,
power_cap,
power_cap_max,
}
}
@ -238,9 +248,9 @@ impl GpuController {
Err(_) => 0,
};
let (mem_freq, gpu_freq, gpu_temp, power_avg, power_max, fan_speed, max_fan_speed) = match &self.hw_mon {
Some(hw_mon) => (hw_mon.get_mem_freq(), hw_mon.get_gpu_freq(), hw_mon.get_gpu_temp(), hw_mon.get_power_avg(), hw_mon.get_power_cap(), hw_mon.get_fan_speed(), hw_mon.fan_max_speed),
None => (0, 0, 0, 0, 0, 0, 0),
let (mem_freq, gpu_freq, gpu_temp, power_avg, power_cap, power_cap_max, fan_speed, max_fan_speed) = match &self.hw_mon {
Some(hw_mon) => (hw_mon.get_mem_freq(), hw_mon.get_gpu_freq(), hw_mon.get_gpu_temp(), hw_mon.get_power_avg(), hw_mon.get_power_cap(), hw_mon.get_power_cap_max(), hw_mon.get_fan_speed(), hw_mon.fan_max_speed),
None => (0, 0, 0, 0, 0, 0, 0, 0),
};
GpuStats {
@ -250,7 +260,8 @@ impl GpuController {
gpu_freq,
gpu_temp,
power_avg,
power_max,
power_cap,
power_cap_max,
fan_speed,
max_fan_speed,
}
@ -312,6 +323,17 @@ impl GpuController {
}
}
pub fn set_power_cap(&mut self, cap: i32) -> Result<(), HWMonError> {
match &mut self.hw_mon {
Some(hw_mon) => {
hw_mon.set_power_cap(cap).unwrap();
self.gpu_info.power_cap = cap;
Ok(())
},
None => Err(HWMonError::NoHWMon),
}
}
fn get_vulkan_info(pci_id: &str) -> VulkanInfo {
let mut device_name = String::from("Not supported");
let mut api_version = String::new();

View File

@ -15,6 +15,7 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
pub enum HWMonError {
PermissionDenied,
InvalidValue,
NoHWMon,
}
@ -24,6 +25,7 @@ pub struct HWMon {
pub fan_max_speed: i32,
fan_control: Arc<AtomicBool>,
fan_curve: Arc<RwLock<BTreeMap<i32, f64>>>,
power_cap: i32,
}
impl HWMon {
@ -37,16 +39,18 @@ impl HWMon {
Err(_) => 0,
};
let mon = HWMon {
let mut mon = HWMon {
hwmon_path: hwmon_path.clone(),
fan_max_speed,
fan_control: Arc::new(AtomicBool::new(false)),
fan_curve: Arc::new(RwLock::new(fan_curve)),
power_cap: 0,
};
if fan_control_enabled {
mon.start_fan_control().unwrap();
}
mon.power_cap = mon.get_power_cap();
mon
}
@ -115,6 +119,19 @@ impl HWMon {
}
}
pub fn get_power_cap_max(&self) -> i32 {
let filename = self.hwmon_path.join("power1_cap_max");
match fs::read_to_string(filename) {
Ok(a) => a
.trim()
.parse::<i32>()
.unwrap()
/ 1000000,
_ => 0,
}
}
pub fn get_power_cap(&self) -> i32 {
let filename = self.hwmon_path.join("power1_cap");
@ -128,6 +145,24 @@ impl HWMon {
}
}
pub fn set_power_cap(&mut self, cap: i32) -> Result<(), HWMonError> {
if cap > self.get_power_cap_max() {
return Err(HWMonError::InvalidValue);
}
let cap = cap * 1000000;
log::trace!("setting power cap to {}", cap);
match fs::write(self.hwmon_path.join("power1_cap"), cap.to_string()) {
Ok(_) => {
self.power_cap = cap;
Ok(())
},
Err(_) => Err(HWMonError::PermissionDenied),
}
}
pub fn get_power_avg(&self) -> i32 {
let filename = self.hwmon_path.join("power1_average");

View File

@ -3,7 +3,7 @@ pub mod daemon_connection;
pub mod gpu_controller;
pub mod hw_mon;
use config::{Config, GpuConfig, GpuIdentifier};
use config::{Config, GpuConfig};
use serde::{Deserialize, Serialize};
use std::{collections::{BTreeMap, HashMap}, fs};
use std::os::unix::net::{UnixListener, UnixStream};
@ -35,6 +35,7 @@ pub enum Action {
StopFanControl(u32),
GetFanControl(u32),
SetFanCurve(u32, BTreeMap<i32, f64>),
SetPowerCap(u32, i32),
Shutdown,
}
@ -191,9 +192,6 @@ impl Daemon {
}
Action::SetFanCurve(i, curve) => match self.gpu_controllers.get_mut(&i) {
Some(controller) => {
let mut buffer = Vec::new();
stream.read_to_end(&mut buffer).unwrap();
match controller.set_fan_curve(curve) {
Ok(_) => {
@ -207,6 +205,17 @@ impl Daemon {
},
None => Err(DaemonError::InvalidID),
}
Action::SetPowerCap(i, cap) => match self.gpu_controllers.get_mut(&i) {
Some(controller) => {
match controller.set_power_cap(cap) {
Ok(_) => {
Ok(DaemonResponse::OK)
},
Err(_) => Err(DaemonError::HWMonError),
}
},
None => Err(DaemonError::InvalidID),
}
Action::Shutdown => std::process::exit(0),
};

View File

@ -40,12 +40,16 @@ fn build_ui(application: &gtk::Application) {
let fan_speed_text_buffer: TextBuffer = builder.get_object("fan_speed_text_buffer").unwrap();
let power_cap_label: Label = builder.get_object("power_cap_label").unwrap();
let automatic_fan_control_switch: Switch =
builder.get_object("automatic_fan_control_switch").unwrap();
let apply_button: Button = builder.get_object("apply_button").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 mut unpriviliged: bool = false;
@ -94,8 +98,15 @@ fn build_ui(application: &gtk::Application) {
let fan_curv_frm = fan_curve_frame.clone();
let auto_fan_ctrl_swtch = automatic_fan_control_switch.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());
b.set_sensitive(true);
power_cap_label.set_text(&format!("{}/{}", adjustment.get_value().floor(), adjustment.get_upper()));
});
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");
@ -166,7 +177,7 @@ fn build_ui(application: &gtk::Application) {
gpu_temp_text_buffer.set_text(&format!("{}°C", gpu_stats.gpu_temp));
gpu_power_text_buffer
.set_text(&format!("{}/{}W", gpu_stats.power_avg, gpu_stats.power_max));
.set_text(&format!("{}/{}W", gpu_stats.power_avg, gpu_stats.power_cap));
fan_speed_text_buffer.set_text(&format!(
"{}RPM({}%)",
@ -174,6 +185,7 @@ fn build_ui(application: &gtk::Application) {
(gpu_stats.fan_speed as f64 / gpu_stats.max_fan_speed as f64 * 100 as f64) as i32
));
glib::Continue(true)
});
@ -268,6 +280,9 @@ fn build_ui(application: &gtk::Application) {
d.start_fan_control(current_gpu_id).unwrap();
}
}
let power_cap = gpu_power_adjustment.get_value().floor() as i32;
d.set_power_cap(current_gpu_id, power_cap).unwrap();
});
},
Err(_) => (),
@ -316,6 +331,11 @@ fn set_info(builder: &Builder, gpu_info: &GpuInfo) {
.get_object("vulkan_features_text_buffer")
.expect("Couldn't get textbuffer");
let power_cap_label: Label = builder.get_object("power_cap_label").unwrap();
let gpu_power_adjustment: Adjustment = builder.get_object("gpu_power_adjustment").unwrap();
//let power_cap_scale: Scale = builder.get_object("power_cap_scale").unwrap();
gpu_model_text_buffer.set_text(&gpu_info.card_model);
manufacturer_text_buffer.set_text(&gpu_info.card_vendor);
vbios_version_text_buffer.set_text(&gpu_info.vbios_version);
@ -330,6 +350,10 @@ fn set_info(builder: &Builder, gpu_info: &GpuInfo) {
vulkan_version_text_buffer.set_text(&gpu_info.vulkan_info.api_version);
vulkan_features_text_buffer.set_text(&gpu_info.vulkan_info.features);
power_cap_label.set_text(&format!("{}/{}", gpu_info.power_cap, gpu_info.power_cap_max));
gpu_power_adjustment.set_upper(gpu_info.power_cap_max as f64);
gpu_power_adjustment.set_value(gpu_info.power_cap as f64);
}
fn main() {

View File

@ -39,6 +39,11 @@
<object class="GtkTextBuffer" id="gpu_model_text_buffer">
<property name="text">gpu_model</property>
</object>
<object class="GtkAdjustment" id="gpu_power_adjustment">
<property name="upper">100</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
<object class="GtkTextBuffer" id="gpu_power_text_buffer">
<property name="text" translatable="yes">50W/100W</property>
</object>
@ -65,6 +70,9 @@
<object class="GtkTextBuffer" id="manufacturer_text_buffer">
<property name="text" translatable="yes">Manufacturer</property>
</object>
<object class="GtkTextBuffer" id="power_cap_text_buffer">
<property name="text" translatable="yes">50/100</property>
</object>
<object class="GtkTextBuffer" id="vbios_version_text_buffer">
<property name="text" translatable="yes">vbios_version</property>
</object>
@ -85,6 +93,7 @@
</object>
<object class="GtkWindow" id="main_window">
<property name="can-focus">False</property>
<property name="title" translatable="yes">LACT</property>
<property name="default-width">350</property>
<property name="default-height">500</property>
<child>
@ -672,6 +681,68 @@
<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>
</object>
<packing>
<property name="position">1</property>