|
1 | 1 | use crate::CliContext; |
2 | 2 | use anyhow::{Context, Result}; |
3 | | -use lact_schema::args::cli::{PowerLimitCmd, ProfileArgs, ProfileAutoSwitchArgs, SetProfileArgs}; |
| 3 | +use lact_schema::{ |
| 4 | + args::cli::{PowerLimitCmd, ProfileArgs, ProfileAutoSwitchArgs, SetProfileArgs}, |
| 5 | + FanControlMode, |
| 6 | +}; |
| 7 | +use std::fmt::Write; |
4 | 8 |
|
5 | 9 | const PROFILE_DEFAULT: &str = "Default"; |
6 | 10 |
|
@@ -39,6 +43,101 @@ pub async fn info(ctx: CliContext<'_>) -> Result<()> { |
39 | 43 | Ok(()) |
40 | 44 | } |
41 | 45 |
|
| 46 | +pub async fn stats(ctx: CliContext<'_>) -> Result<()> { |
| 47 | + let id = ctx.current_gpu_id().await?; |
| 48 | + |
| 49 | + let gpu_line = format!("GPU {id}:"); |
| 50 | + println!("{gpu_line}"); |
| 51 | + println!("{}", "=".repeat(gpu_line.len())); |
| 52 | + |
| 53 | + // let info = ctx.client.get_device_info(&id).await?; |
| 54 | + let stats = ctx.client.get_device_stats(&id).await?; |
| 55 | + |
| 56 | + if let Some(gpu_clock) = stats.clockspeed.gpu_clockspeed { |
| 57 | + println!("GPU Clockspeed: {gpu_clock} MHz"); |
| 58 | + } |
| 59 | + |
| 60 | + if let Some(vram_clock) = stats.clockspeed.vram_clockspeed { |
| 61 | + println!("VRAM Clockspeed: {vram_clock} MHz"); |
| 62 | + } |
| 63 | + |
| 64 | + if let Some(gpu_voltage) = stats.voltage.gpu { |
| 65 | + println!("GPU Voltage: {gpu_voltage} mV"); |
| 66 | + } |
| 67 | + |
| 68 | + if let (Some(power_usage), Some(power_cap)) = (stats.power.current, stats.power.cap_current) { |
| 69 | + println!("Power Usage: {power_usage:.1}/{power_cap} W"); |
| 70 | + } |
| 71 | + |
| 72 | + if !stats.temps.is_empty() { |
| 73 | + print!("Temperatures: "); |
| 74 | + for (i, (name, value)) in stats.temps.iter().enumerate() { |
| 75 | + if i > 0 { |
| 76 | + print!(", "); |
| 77 | + } |
| 78 | + if let Some(value) = value.current { |
| 79 | + print!("{name}: {value}°C"); |
| 80 | + } |
| 81 | + } |
| 82 | + println!(); |
| 83 | + } |
| 84 | + |
| 85 | + if let (Some(vram_current), Some(vram_total)) = (stats.vram.used, stats.vram.total) { |
| 86 | + println!( |
| 87 | + "VRAM Usage: {}/{} MiB", |
| 88 | + vram_current / 1024 / 1024, |
| 89 | + vram_total / 1024 / 1024 |
| 90 | + ); |
| 91 | + } |
| 92 | + |
| 93 | + if let Some(throttle_info) = stats.throttle_info { |
| 94 | + let type_text: Vec<String> = throttle_info |
| 95 | + .iter() |
| 96 | + .map(|(throttle_type, details)| { |
| 97 | + let mut out = throttle_type.to_string(); |
| 98 | + if !details.is_empty() { |
| 99 | + let _ = write!(out, "({})", details.join(", ")); |
| 100 | + } |
| 101 | + out |
| 102 | + }) |
| 103 | + .collect(); |
| 104 | + |
| 105 | + println!( |
| 106 | + "Throttling: {}", |
| 107 | + if type_text.is_empty() { |
| 108 | + "No".to_owned() |
| 109 | + } else { |
| 110 | + type_text.join(", ") |
| 111 | + } |
| 112 | + ); |
| 113 | + } |
| 114 | + |
| 115 | + if let Some(pwm) = stats.fan.pwm_current { |
| 116 | + print!("Fan Speed: {:.0}%", pwm as f64 / 255.0 * 100.0); |
| 117 | + |
| 118 | + if let Some(rpm) = stats.fan.speed_current { |
| 119 | + print!(" ({rpm} RPM)"); |
| 120 | + } |
| 121 | + |
| 122 | + println!(); |
| 123 | + } |
| 124 | + |
| 125 | + println!( |
| 126 | + "Fan Control Mode: {}", |
| 127 | + if stats.fan.control_enabled { |
| 128 | + match stats.fan.control_mode { |
| 129 | + Some(FanControlMode::Curve) => "Curve", |
| 130 | + Some(FanControlMode::Static) => "Static", |
| 131 | + None => panic!("Invalid fan control config"), |
| 132 | + } |
| 133 | + } else { |
| 134 | + "Automatic" |
| 135 | + } |
| 136 | + ); |
| 137 | + |
| 138 | + Ok(()) |
| 139 | +} |
| 140 | + |
42 | 141 | pub async fn snapshot(ctx: CliContext<'_>) -> Result<()> { |
43 | 142 | let path = ctx.client.generate_debug_snapshot().await?; |
44 | 143 | println!("Generated debug snapshot in {path}"); |
|
0 commit comments