mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
Feature/power profile modes (#112)
* feat: daemon implementation of power profile modes * feat: updated performance frame with manual mode support * feat: WIP UI for power modes * feat: setting power profile mode in UI * feat: show power profile modes info * fix: hide power profile modes when not available * feat: basic power profile modes table support * chore: use git amdgpu-sysfs source * fix: basic modes table gui offset * feat: use basic power profiles instead * fix: invalid lowest clocks performance level name * chore: remove git source
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -25,9 +25,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "amdgpu-sysfs"
|
||||
version = "0.9.7"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6667682d11c8face0277986d0cfc0862399febf666e0d9a9d8b12fa0362373ba"
|
||||
checksum = "47443bb84437d283c988cc988e28bac8f841530a855d7069cf272a691af61db0"
|
||||
dependencies = [
|
||||
"enum_dispatch",
|
||||
"serde",
|
||||
|
||||
@@ -6,8 +6,8 @@ pub use lact_schema as schema;
|
||||
use anyhow::{anyhow, Context};
|
||||
use nix::unistd::getuid;
|
||||
use schema::{
|
||||
request::SetClocksCommand, ClocksInfo, DeviceInfo, DeviceListEntry, DeviceStats, FanCurveMap,
|
||||
PerformanceLevel, Request, Response, SystemInfo,
|
||||
power_profile_mode::PowerProfileModesTable, request::SetClocksCommand, ClocksInfo, DeviceInfo,
|
||||
DeviceListEntry, DeviceStats, FanCurveMap, PerformanceLevel, Request, Response, SystemInfo,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use std::{
|
||||
@@ -90,6 +90,11 @@ impl DaemonClient {
|
||||
request_with_id!(get_device_info, DeviceInfo, DeviceInfo);
|
||||
request_with_id!(get_device_stats, DeviceStats, DeviceStats);
|
||||
request_with_id!(get_device_clocks_info, DeviceClocksInfo, ClocksInfo);
|
||||
request_with_id!(
|
||||
get_device_power_profile_modes,
|
||||
DevicePowerProfileModes,
|
||||
PowerProfileModesTable
|
||||
);
|
||||
|
||||
pub fn set_performance_level(
|
||||
&self,
|
||||
@@ -107,6 +112,11 @@ impl DaemonClient {
|
||||
self.make_request(Request::SetClocksValue { id, command })?
|
||||
.inner()
|
||||
}
|
||||
|
||||
pub fn set_power_profile_mode(&self, id: &str, index: Option<u16>) -> anyhow::Result<()> {
|
||||
self.make_request(Request::SetPowerProfileMode { id, index })?
|
||||
.inner()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_socket_path() -> Option<PathBuf> {
|
||||
|
||||
@@ -6,7 +6,7 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
amdgpu-sysfs = { version = "0.9.7", features = ["serde"] }
|
||||
amdgpu-sysfs = { version = "0.10.0", features = ["serde"] }
|
||||
anyhow = "1.0"
|
||||
bincode = "1.3"
|
||||
nix = "0.26"
|
||||
|
||||
@@ -42,6 +42,7 @@ pub struct Gpu {
|
||||
pub max_memory_clock: Option<u32>,
|
||||
pub max_voltage: Option<u32>,
|
||||
pub voltage_offset: Option<i32>,
|
||||
pub power_profile_mode_index: Option<u16>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
|
||||
@@ -341,6 +341,16 @@ impl GpuController {
|
||||
.set_power_force_performance_level(PerformanceLevel::Auto)?;
|
||||
}
|
||||
|
||||
if let Some(mode_index) = config.power_profile_mode_index {
|
||||
if config.performance_level != Some(PerformanceLevel::Manual) {
|
||||
return Err(anyhow!(
|
||||
"Performance level has to be set to `manual` to use power profile modes"
|
||||
));
|
||||
}
|
||||
|
||||
self.handle.set_active_power_profile_mode(mode_index)?;
|
||||
}
|
||||
|
||||
if config.max_core_clock.is_some()
|
||||
|| config.max_memory_clock.is_some()
|
||||
|| config.max_voltage.is_some()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use super::gpu_controller::{fan_control::FanCurve, GpuController};
|
||||
use crate::config::{self, Config, FanControlSettings};
|
||||
use amdgpu_sysfs::gpu_handle::power_profile_mode::PowerProfileModesTable;
|
||||
use anyhow::{anyhow, Context};
|
||||
use lact_schema::{
|
||||
request::SetClocksCommand, ClocksInfo, DeviceInfo, DeviceListEntry, DeviceStats, FanCurveMap,
|
||||
@@ -226,6 +227,21 @@ impl<'a> Handler {
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn get_power_profile_modes(&self, id: &str) -> anyhow::Result<PowerProfileModesTable> {
|
||||
let modes_table = self
|
||||
.controller_by_id(id)?
|
||||
.handle
|
||||
.get_power_profile_modes()?;
|
||||
Ok(modes_table)
|
||||
}
|
||||
|
||||
pub async fn set_power_profile_mode(&self, id: &str, index: Option<u16>) -> anyhow::Result<()> {
|
||||
self.edit_gpu_config(id.to_owned(), |gpu_config| {
|
||||
gpu_config.power_profile_mode_index = index;
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn cleanup(self) {
|
||||
for (id, controller) in self.gpu_controllers.iter() {
|
||||
if controller.handle.get_clocks_table().is_ok() {
|
||||
|
||||
@@ -84,6 +84,9 @@ async fn handle_request<'a>(request: Request<'a>, handler: &'a Handler) -> anyho
|
||||
Request::DeviceInfo { id } => ok_response(handler.get_device_info(id)?),
|
||||
Request::DeviceStats { id } => ok_response(handler.get_gpu_stats(id)?),
|
||||
Request::DeviceClocksInfo { id } => ok_response(handler.get_clocks_info(id)?),
|
||||
Request::DevicePowerProfileModes { id } => {
|
||||
ok_response(handler.get_power_profile_modes(id)?)
|
||||
}
|
||||
Request::SetFanControl { id, enabled, curve } => {
|
||||
ok_response(handler.set_fan_control(id, enabled, curve).await?)
|
||||
}
|
||||
@@ -95,6 +98,9 @@ async fn handle_request<'a>(request: Request<'a>, handler: &'a Handler) -> anyho
|
||||
Request::SetClocksValue { id, command } => {
|
||||
ok_response(handler.set_clocks_value(id, command).await?)
|
||||
}
|
||||
Request::SetPowerProfileMode { id, index } => {
|
||||
ok_response(handler.set_power_profile_mode(id, index).await?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -184,6 +184,24 @@ impl App {
|
||||
};
|
||||
self.root_stack.oc_page.set_clocks_table(maybe_clocks_table);
|
||||
|
||||
let maybe_modes_table = match self.daemon_client.get_device_power_profile_modes(gpu_id) {
|
||||
Ok(buf) => match buf.inner() {
|
||||
Ok(table) => Some(table),
|
||||
Err(err) => {
|
||||
debug!("Could not extract profile modes table: {err:?}");
|
||||
None
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
debug!("Could not get profile modes table: {err:?}");
|
||||
None
|
||||
}
|
||||
};
|
||||
self.root_stack
|
||||
.oc_page
|
||||
.performance_frame
|
||||
.set_power_profile_modes(maybe_modes_table);
|
||||
|
||||
// Show apply button on setting changes
|
||||
// This is done here because new widgets may appear after applying settings (like fan curve points) which should be connected
|
||||
let show_revealer = clone!(@strong self.apply_revealer as apply_revealer => move || {
|
||||
@@ -259,10 +277,24 @@ impl App {
|
||||
.context("Failed to set power cap")?;
|
||||
}
|
||||
|
||||
// Reset the power profile mode for switching to/from manual performance level
|
||||
self.daemon_client
|
||||
.set_power_profile_mode(&gpu_id, None)
|
||||
.context("Could not set default power profile mode")?;
|
||||
|
||||
if let Some(level) = self.root_stack.oc_page.get_performance_level() {
|
||||
self.daemon_client
|
||||
.set_performance_level(&gpu_id, level)
|
||||
.context("Failed to set power profile")?;
|
||||
|
||||
let mode_index = self
|
||||
.root_stack
|
||||
.oc_page
|
||||
.performance_frame
|
||||
.get_selected_power_profile_mode();
|
||||
self.daemon_client
|
||||
.set_power_profile_mode(&gpu_id, mode_index)
|
||||
.context("Could not set active power profile mode")?;
|
||||
}
|
||||
|
||||
if let Some(thermals_settings) = self.root_stack.thermals_page.get_thermals_settings() {
|
||||
|
||||
@@ -110,7 +110,6 @@ impl ClocksFrame {
|
||||
|
||||
if let ClocksTableGen::Vega20(table) = table {
|
||||
if let Some(offset) = table.voltage_offset {
|
||||
// TODO: check this
|
||||
self.voltage_offset_adjustment
|
||||
.set_lower(VOLTAGE_OFFSET_RANGE * -1.0);
|
||||
self.voltage_offset_adjustment
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mod clocks_frame;
|
||||
mod performance_level_frame;
|
||||
mod performance_frame;
|
||||
mod power_cap_frame;
|
||||
mod stats_frame;
|
||||
|
||||
@@ -7,7 +7,7 @@ use clocks_frame::ClocksFrame;
|
||||
use gtk::prelude::*;
|
||||
use gtk::*;
|
||||
use lact_client::schema::{ClocksTableGen, DeviceStats, PerformanceLevel, SystemInfo};
|
||||
use performance_level_frame::PerformanceLevelFrame;
|
||||
use performance_frame::PerformanceFrame;
|
||||
use power_cap_frame::PowerCapFrame;
|
||||
use stats_frame::StatsFrame;
|
||||
use tracing::warn;
|
||||
@@ -16,7 +16,7 @@ use tracing::warn;
|
||||
pub struct OcPage {
|
||||
pub container: Box,
|
||||
stats_frame: StatsFrame,
|
||||
performance_level_frame: PerformanceLevelFrame,
|
||||
pub performance_frame: PerformanceFrame,
|
||||
power_cap_frame: PowerCapFrame,
|
||||
pub clocks_frame: ClocksFrame,
|
||||
}
|
||||
@@ -37,7 +37,7 @@ impl OcPage {
|
||||
container.append(&stats_frame.container);
|
||||
|
||||
let power_cap_frame = PowerCapFrame::new();
|
||||
let performance_level_frame = PerformanceLevelFrame::new();
|
||||
let performance_level_frame = PerformanceFrame::new();
|
||||
let clocks_frame = ClocksFrame::new();
|
||||
|
||||
container.append(&power_cap_frame.container);
|
||||
@@ -47,7 +47,7 @@ impl OcPage {
|
||||
Self {
|
||||
container,
|
||||
stats_frame,
|
||||
performance_level_frame,
|
||||
performance_frame: performance_level_frame,
|
||||
clocks_frame,
|
||||
power_cap_frame,
|
||||
}
|
||||
@@ -83,8 +83,7 @@ impl OcPage {
|
||||
}
|
||||
|
||||
pub fn connect_settings_changed<F: Fn() + 'static + Clone>(&self, f: F) {
|
||||
self.performance_level_frame
|
||||
.connect_power_profile_changed(f.clone());
|
||||
self.performance_frame.connect_settings_changed(f.clone());
|
||||
self.power_cap_frame.connect_cap_changed(f.clone());
|
||||
self.clocks_frame.connect_clocks_changed(f);
|
||||
}
|
||||
@@ -92,18 +91,16 @@ impl OcPage {
|
||||
pub fn set_performance_level(&self, profile: Option<PerformanceLevel>) {
|
||||
match profile {
|
||||
Some(profile) => {
|
||||
self.performance_level_frame.show();
|
||||
self.performance_level_frame.set_active_profile(profile);
|
||||
self.performance_frame.show();
|
||||
self.performance_frame.set_active_level(profile);
|
||||
}
|
||||
None => self.performance_level_frame.hide(),
|
||||
None => self.performance_frame.hide(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_performance_level(&self) -> Option<PerformanceLevel> {
|
||||
if self.performance_level_frame.get_visibility() {
|
||||
let level = self
|
||||
.performance_level_frame
|
||||
.get_selected_performance_level();
|
||||
if self.performance_frame.get_visibility() {
|
||||
let level = self.performance_frame.get_selected_performance_level();
|
||||
Some(level)
|
||||
} else {
|
||||
None
|
||||
|
||||
189
lact-gui/src/app/root_stack/oc_page/performance_frame.rs
Normal file
189
lact-gui/src/app/root_stack/oc_page/performance_frame.rs
Normal file
@@ -0,0 +1,189 @@
|
||||
use crate::app::root_stack::section_box;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk::*;
|
||||
use lact_client::schema::{power_profile_mode::PowerProfileModesTable, PerformanceLevel};
|
||||
use std::{cell::RefCell, rc::Rc, str::FromStr};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PerformanceFrame {
|
||||
pub container: Box,
|
||||
level_drop_down: DropDown,
|
||||
mode_drop_down: DropDown,
|
||||
description_label: Label,
|
||||
manual_info_button: MenuButton,
|
||||
mode_box: Box,
|
||||
modes_table: Rc<RefCell<Option<PowerProfileModesTable>>>,
|
||||
}
|
||||
|
||||
impl PerformanceFrame {
|
||||
pub fn new() -> Self {
|
||||
let container = section_box("Performance");
|
||||
|
||||
let levels_model: StringList = ["Automatic", "Highest Clocks", "Lowest Clocks", "Manual"]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let level_box = Box::new(Orientation::Horizontal, 10);
|
||||
|
||||
let level_drop_down = DropDown::builder()
|
||||
.model(&levels_model)
|
||||
.sensitive(false)
|
||||
.build();
|
||||
let description_label = Label::builder().halign(Align::End).hexpand(true).build();
|
||||
let perfromance_title_label = Label::builder().label("Performance level:").build();
|
||||
|
||||
level_box.append(&perfromance_title_label);
|
||||
level_box.append(&description_label);
|
||||
level_box.append(&level_drop_down);
|
||||
|
||||
container.append(&level_box);
|
||||
|
||||
let mode_box = Box::new(Orientation::Horizontal, 10);
|
||||
|
||||
let mode_drop_down = DropDown::builder()
|
||||
.sensitive(false)
|
||||
.halign(Align::End)
|
||||
.build();
|
||||
|
||||
let unavailable_label = Label::new(Some(
|
||||
"Performance level has to be set to \"manual\" to use power profile modes",
|
||||
));
|
||||
let mode_info_popover = Popover::builder().child(&unavailable_label).build();
|
||||
let manual_info_button = MenuButton::builder()
|
||||
.icon_name("dialog-information-symbolic")
|
||||
.hexpand(true)
|
||||
.halign(Align::End)
|
||||
.popover(&mode_info_popover)
|
||||
.build();
|
||||
|
||||
let mode_title_label = Label::new(Some("Power level mode:"));
|
||||
mode_box.append(&mode_title_label);
|
||||
mode_box.append(&manual_info_button);
|
||||
mode_box.append(&mode_drop_down);
|
||||
|
||||
container.append(&mode_box);
|
||||
|
||||
let frame = Self {
|
||||
container,
|
||||
level_drop_down,
|
||||
mode_drop_down,
|
||||
description_label,
|
||||
manual_info_button,
|
||||
mode_box,
|
||||
modes_table: Rc::new(RefCell::new(None)),
|
||||
};
|
||||
|
||||
frame
|
||||
.level_drop_down
|
||||
.connect_selected_notify(clone!(@strong frame => move |_| {
|
||||
frame.update_from_selection();
|
||||
}));
|
||||
|
||||
frame
|
||||
.mode_drop_down
|
||||
.connect_selected_notify(clone!(@strong frame => move |_| {
|
||||
frame.update_from_selection();
|
||||
}));
|
||||
|
||||
frame
|
||||
}
|
||||
|
||||
pub fn set_active_level(&self, level: PerformanceLevel) {
|
||||
self.level_drop_down.set_sensitive(true);
|
||||
match level {
|
||||
PerformanceLevel::Auto => self.level_drop_down.set_selected(0),
|
||||
PerformanceLevel::High => self.level_drop_down.set_selected(1),
|
||||
PerformanceLevel::Low => self.level_drop_down.set_selected(2),
|
||||
PerformanceLevel::Manual => self.level_drop_down.set_selected(3),
|
||||
};
|
||||
self.update_from_selection();
|
||||
}
|
||||
|
||||
pub fn set_power_profile_modes(&self, table: Option<PowerProfileModesTable>) {
|
||||
self.mode_box.set_visible(table.is_some());
|
||||
|
||||
match &table {
|
||||
Some(table) => {
|
||||
let model: StringList = table.modes.values().cloned().collect();
|
||||
let active_pos = table
|
||||
.modes
|
||||
.keys()
|
||||
.position(|key| *key == table.active)
|
||||
.expect("No active mode") as u32;
|
||||
|
||||
self.mode_drop_down.set_model(Some(&model));
|
||||
self.mode_drop_down.set_selected(active_pos);
|
||||
|
||||
self.mode_drop_down.show();
|
||||
}
|
||||
None => {
|
||||
self.mode_drop_down.hide();
|
||||
}
|
||||
}
|
||||
self.modes_table.replace(table);
|
||||
}
|
||||
|
||||
pub fn connect_settings_changed<F: Fn() + 'static + Clone>(&self, f: F) {
|
||||
self.level_drop_down
|
||||
.connect_selected_notify(clone!(@strong f => move |_| f()));
|
||||
self.mode_drop_down.connect_selected_notify(move |_| f());
|
||||
}
|
||||
|
||||
pub fn get_selected_performance_level(&self) -> PerformanceLevel {
|
||||
let selected_item = self
|
||||
.level_drop_down
|
||||
.selected_item()
|
||||
.expect("No selected item");
|
||||
let string_object = selected_item.downcast_ref::<StringObject>().unwrap();
|
||||
PerformanceLevel::from_str(string_object.string().as_str())
|
||||
.expect("Unrecognized selected performance level")
|
||||
}
|
||||
|
||||
pub fn get_selected_power_profile_mode(&self) -> Option<u16> {
|
||||
if self.mode_drop_down.is_sensitive() {
|
||||
self.modes_table.borrow().as_ref().map(|table| {
|
||||
let selected_index = table
|
||||
.modes
|
||||
.keys()
|
||||
.nth(self.mode_drop_down.selected() as usize)
|
||||
.expect("Selected mode out of range");
|
||||
*selected_index
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn update_from_selection(&self) {
|
||||
let mut enable_mode_control = false;
|
||||
|
||||
let text = match self.level_drop_down.selected() {
|
||||
0 => "Automatically adjust GPU and VRAM clocks. (Default)",
|
||||
1 => "Always use the highest clockspeeds for GPU and VRAM.",
|
||||
2 => "Always use the lowest clockspeeds for GPU and VRAM.",
|
||||
3 => {
|
||||
enable_mode_control = true;
|
||||
"Manual performance control."
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.description_label.set_text(text);
|
||||
self.mode_drop_down.set_sensitive(enable_mode_control);
|
||||
|
||||
self.manual_info_button.set_visible(!enable_mode_control);
|
||||
self.mode_drop_down.set_hexpand(enable_mode_control);
|
||||
}
|
||||
|
||||
pub fn show(&self) {
|
||||
self.container.set_visible(true);
|
||||
}
|
||||
|
||||
pub fn hide(&self) {
|
||||
self.container.set_visible(false);
|
||||
}
|
||||
|
||||
pub fn get_visibility(&self) -> bool {
|
||||
self.container.get_visible()
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
use crate::app::root_stack::section_box;
|
||||
use gtk::prelude::*;
|
||||
use gtk::*;
|
||||
use lact_client::schema::PerformanceLevel;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PerformanceLevelFrame {
|
||||
pub container: Box,
|
||||
combo_box: ComboBoxText,
|
||||
}
|
||||
|
||||
impl PerformanceLevelFrame {
|
||||
pub fn new() -> Self {
|
||||
let container = section_box("Performance level");
|
||||
|
||||
let root_box = Box::new(Orientation::Horizontal, 5);
|
||||
|
||||
let combo_box = ComboBoxText::new();
|
||||
combo_box.set_sensitive(false);
|
||||
|
||||
combo_box.append(None, "Automatic");
|
||||
combo_box.append(None, "Highest clocks");
|
||||
combo_box.append(None, "Lowest clocks");
|
||||
|
||||
root_box.append(&combo_box);
|
||||
|
||||
let description_label = Label::new(None);
|
||||
|
||||
root_box.append(&description_label);
|
||||
|
||||
{
|
||||
combo_box.connect_changed(move |combobox| match combobox.active().unwrap() {
|
||||
0 => description_label
|
||||
.set_text("Automatically adjust GPU and VRAM clocks. (Default)"),
|
||||
1 => description_label
|
||||
.set_text("Always use the highest clockspeeds for GPU and VRAM."),
|
||||
2 => description_label
|
||||
.set_text("Always use the lowest clockspeeds for GPU and VRAM."),
|
||||
_ => unreachable!(),
|
||||
});
|
||||
}
|
||||
|
||||
container.append(&root_box);
|
||||
Self {
|
||||
container,
|
||||
combo_box,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_active_profile(&self, level: PerformanceLevel) {
|
||||
self.combo_box.set_sensitive(true);
|
||||
match level {
|
||||
PerformanceLevel::Auto => self.combo_box.set_active(Some(0)),
|
||||
PerformanceLevel::High => self.combo_box.set_active(Some(1)),
|
||||
PerformanceLevel::Low => self.combo_box.set_active(Some(2)),
|
||||
PerformanceLevel::Manual => todo!(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn connect_power_profile_changed<F: Fn() + 'static>(&self, f: F) {
|
||||
self.combo_box.connect_changed(move |_| {
|
||||
f();
|
||||
});
|
||||
}
|
||||
|
||||
pub fn get_selected_performance_level(&self) -> PerformanceLevel {
|
||||
match self.combo_box.active().unwrap() {
|
||||
0 => PerformanceLevel::Auto,
|
||||
1 => PerformanceLevel::High,
|
||||
2 => PerformanceLevel::Low,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show(&self) {
|
||||
self.container.set_visible(true);
|
||||
}
|
||||
|
||||
pub fn hide(&self) {
|
||||
self.container.set_visible(false);
|
||||
}
|
||||
|
||||
pub fn get_visibility(&self) -> bool {
|
||||
self.container.get_visible()
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ version = "0.3.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
amdgpu-sysfs = { version = "0.9.7", features = ["serde"] }
|
||||
amdgpu-sysfs = { version = "0.10.0", features = ["serde"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
indexmap = { version = "*", features = ["serde"] }
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ mod tests;
|
||||
pub use amdgpu_sysfs::{
|
||||
gpu_handle::{
|
||||
overdrive::{ClocksTable, ClocksTableGen, Range},
|
||||
PerformanceLevel, PowerLevels,
|
||||
power_profile_mode, PerformanceLevel, PowerLevels,
|
||||
},
|
||||
hw_mon::Temperature,
|
||||
};
|
||||
|
||||
@@ -17,6 +17,9 @@ pub enum Request<'a> {
|
||||
DeviceClocksInfo {
|
||||
id: &'a str,
|
||||
},
|
||||
DevicePowerProfileModes {
|
||||
id: &'a str,
|
||||
},
|
||||
SetFanControl {
|
||||
id: &'a str,
|
||||
enabled: bool,
|
||||
@@ -34,6 +37,10 @@ pub enum Request<'a> {
|
||||
id: &'a str,
|
||||
command: SetClocksCommand,
|
||||
},
|
||||
SetPowerProfileMode {
|
||||
id: &'a str,
|
||||
index: Option<u16>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
|
||||
Reference in New Issue
Block a user