Skip to content
Prev Previous commit
Next Next commit
separate gpu struct
  • Loading branch information
filippor committed Aug 29, 2025
commit 41f0ba8f93e108bfde01056fe41048b3fe02a87b
139 changes: 82 additions & 57 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,67 +26,37 @@ struct Config {
significant_change: u16,
small_change: u16,
up_thresh : f32,
down_thresh : f32,
down_thresh : f32,
min_freq : u16,
max_freq : u16,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {

let config : Config = parse_config(std::env::args()
.nth(1)
.map(std::fs::read_to_string)
.unwrap_or(Ok("".to_string())))?;
struct GPU{
info : libdrm_amdgpu_sys::AMDGPU::drm_amdgpu_info_device,
dev_handle : DeviceHandle,
pp_file : File,
}

let location = BUS_INFO {
domain: 0,
bus: 1,
dev: 0,
func: 0,
};
let sysfs_path = location.get_sysfs_path();
let vendor = std::fs::read_to_string(sysfs_path.join("vendor"))?;
let device = std::fs::read_to_string(sysfs_path.join("device"))?;
if !((vendor == "0x1002\n") && (device == "0x13fe\n")) {
Err(IoError::other(
"Cyan Skillfish GPU not found at expected PCI bus location",
))?;
}
let card = File::open(location.get_drm_render_path()?)?;
let (dev_handle, _, _) =
DeviceHandle::init(card.as_raw_fd()).map_err(IoError::from_raw_os_error)?;

let info = dev_handle
.device_info()
.map_err(IoError::from_raw_os_error)?;
// given in kHz, we need MHz
let min_engine_clock = info.min_engine_clock / 1000;
let max_engine_clock = info.max_engine_clock / 1000;
let mut min_freq = *config.safe_points.first_key_value().unwrap().0;
if u64::from(min_freq) < min_engine_clock {
eprintln!("GPU minimum frequency higher than lowest safe frequency, clamping");
min_freq = u16::try_from(min_engine_clock)?;
}
let mut max_freq = *config.safe_points.last_key_value().unwrap().0;
if u64::from(max_freq) > max_engine_clock {
eprintln!("GPU maximum frequency lower than highest safe frequency, clamping");
max_freq = u16::try_from(max_engine_clock)?;
}
let (min_freq, max_freq) = (min_freq, max_freq);

let mut pp_file = std::fs::OpenOptions::new().write(true).open(
dev_handle
.get_sysfs_path()
.map_err(IoError::from_raw_os_error)?
.join("pp_od_clk_voltage"),
)?;
let (send, mut recv) = watch::channel(min_freq);

fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut gpu = get_gpu()?;
let path = std::env::args()
.nth(1)
.map(std::fs::read_to_string)
.unwrap_or(Ok("".to_string()));
let config : Config = parse_config(path, &gpu)?;

let (send, mut recv) = watch::channel(config.min_freq);
let jh_gov: JoinHandle<Result<(), IoError>> = std::thread::spawn(move || {
let mut curr_freq = min_freq;
let mut target_freq = f32::from(min_freq);
let mut curr_freq = config.min_freq;
let mut target_freq = f32::from(config.min_freq);
let mut samples: u64 = 0;
let mut last_adjustment = Instant::now();
let mut last_finetune = Instant::now();
loop {
let res = dev_handle
let res = gpu.dev_handle
.read_mm_registers(GRBM_STATUS_REG)
.map_err(IoError::from_raw_os_error)?;
let gui_busy = (res & (1 << GPU_ACTIVE_BIT)) > 0;
Expand All @@ -109,13 +79,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} else if busy_frac < config.down_thresh {
target_freq -= config.ramp_rate * f32::from(config.sampling_interval) / 1000.0;
}
target_freq = target_freq.clamp(f32::from(min_freq), f32::from(max_freq));
target_freq = target_freq.clamp(f32::from(config.min_freq), f32::from(config.max_freq));

let adj_now = last_adjustment.elapsed() >= Duration::from_micros(config.adjustment_interval);
if adj_now || burst {
let target_freq = target_freq as u16;
let hit_bounds = target_freq != curr_freq
&& (target_freq == min_freq || target_freq == max_freq);
&& (target_freq == config.min_freq || target_freq == config.max_freq);
let big_change = curr_freq.abs_diff(target_freq) >= config.significant_change;
let finetune = (last_finetune.elapsed()
>= Duration::from_micros(config.finetune_interval))
Expand All @@ -142,8 +112,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
"tried to set a frequency beyond max safe point",
))?
.1;
pp_file.write_all(format!("vc 0 {freq} {vol}").as_bytes())?;
pp_file.write_all("c".as_bytes())?;
gpu.pp_file.write_all(format!("vc 0 {freq} {vol}").as_bytes())?;
gpu.pp_file.write_all("c".as_bytes())?;
}
});

Expand All @@ -152,7 +122,44 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}

fn parse_config(path : Result<String,std::io::Error>) -> Result<Config,Box<dyn std::error::Error>>{
fn get_gpu() -> Result<GPU, IoError>{
let location = BUS_INFO {
domain: 0,
bus: 1,
dev: 0,
func: 0,
};
let sysfs_path = location.get_sysfs_path();
let vendor = std::fs::read_to_string(sysfs_path.join("vendor"))?;
let device = std::fs::read_to_string(sysfs_path.join("device"))?;
if !((vendor == "0x1002\n") && (device == "0x13fe\n")) {
Err(IoError::other(
"Cyan Skillfish GPU not found at expected PCI bus location",
))?;
}
let card = File::open(location.get_drm_render_path()?)?;
let (dev_handle, _, _) =
DeviceHandle::init(card.as_raw_fd()).map_err(IoError::from_raw_os_error)?;

let info = dev_handle
.device_info()
.map_err(IoError::from_raw_os_error)?;

let pp_file = std::fs::OpenOptions::new().write(true).open(
dev_handle
.get_sysfs_path()
.map_err(IoError::from_raw_os_error)?
.join("pp_od_clk_voltage"),
)?;

Ok(GPU {
info: info,
dev_handle: dev_handle,
pp_file:pp_file,
})
}

fn parse_config(path : Result<String,std::io::Error>, gpu:&GPU) -> Result<Config,Box<dyn std::error::Error>>{
let config = path?.parse::<Table>()?;

let timing = config.get("timing").and_then(|t| t.as_table());
Expand Down Expand Up @@ -488,6 +495,21 @@ fn parse_config(path : Result<String,std::io::Error>) -> Result<Config,Box<dyn s
);
BTreeMap::from([(350, 700), (2000, 1000)])
};
// given in kHz, we need MHz
let min_engine_clock = gpu.info.min_engine_clock / 1000;
let max_engine_clock = gpu.info.max_engine_clock / 1000;
let mut min_freq = *safe_points.first_key_value().unwrap().0;
if u64::from(min_freq) < min_engine_clock {
eprintln!("GPU minimum frequency higher than lowest safe frequency, clamping");
min_freq = u16::try_from(min_engine_clock)?;
}
let mut max_freq = *safe_points.last_key_value().unwrap().0;
if u64::from(max_freq) > max_engine_clock {
eprintln!("GPU maximum frequency lower than highest safe frequency, clamping");
max_freq = u16::try_from(max_engine_clock)?;
}
let (min_freq, max_freq) = (min_freq, max_freq);

Ok(Config {
sampling_interval: sampling_interval,
ramp_rate: ramp_rate,
Expand All @@ -500,5 +522,8 @@ fn parse_config(path : Result<String,std::io::Error>) -> Result<Config,Box<dyn s
adjustment_interval : adjustment_interval,
significant_change : significant_change,
finetune_interval : finetune_interval,
min_freq : min_freq,
max_freq : max_freq,

})
}
}