mirror of
https://github.com/RGBCube/superfreq
synced 2025-07-27 17:07:44 +00:00
daemon: less verbosity by default; fine-tune via config
This commit is contained in:
parent
48bf7508aa
commit
4bf4ab5673
6 changed files with 371 additions and 33 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -126,15 +126,6 @@ dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "daemonize"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ab8bfdaacb3c887a54d41bdf48d3af8873b3f5566469f8ba21b92057509f116e"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
version = "6.0.0"
|
version = "6.0.0"
|
||||||
|
@ -333,7 +324,6 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"ctrlc",
|
"ctrlc",
|
||||||
"daemonize",
|
|
||||||
"dirs",
|
"dirs",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
124
src/config.rs
124
src/config.rs
|
@ -1,7 +1,7 @@
|
||||||
use crate::core::{OperationalMode, TurboSetting};
|
use crate::core::TurboSetting;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::PathBuf;
|
||||||
|
|
||||||
// Structs for configuration using serde::Deserialize
|
// Structs for configuration using serde::Deserialize
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
|
@ -41,6 +41,8 @@ pub struct AppConfig {
|
||||||
pub ignored_power_supplies: Option<Vec<String>>,
|
pub ignored_power_supplies: Option<Vec<String>>,
|
||||||
#[serde(default = "default_poll_interval_sec")]
|
#[serde(default = "default_poll_interval_sec")]
|
||||||
pub poll_interval_sec: u64,
|
pub poll_interval_sec: u64,
|
||||||
|
#[serde(default)]
|
||||||
|
pub daemon: DaemonConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_poll_interval_sec() -> u64 {
|
fn default_poll_interval_sec() -> u64 {
|
||||||
|
@ -116,6 +118,19 @@ pub fn load_config() -> Result<AppConfig, ConfigError> {
|
||||||
.battery_charge_thresholds,
|
.battery_charge_thresholds,
|
||||||
ignored_power_supplies: toml_app_config.ignored_power_supplies,
|
ignored_power_supplies: toml_app_config.ignored_power_supplies,
|
||||||
poll_interval_sec: toml_app_config.poll_interval_sec,
|
poll_interval_sec: toml_app_config.poll_interval_sec,
|
||||||
|
daemon: DaemonConfig {
|
||||||
|
poll_interval_sec: toml_app_config.daemon.poll_interval_sec,
|
||||||
|
adaptive_interval: toml_app_config.daemon.adaptive_interval,
|
||||||
|
min_poll_interval_sec: toml_app_config
|
||||||
|
.daemon
|
||||||
|
.min_poll_interval_sec,
|
||||||
|
max_poll_interval_sec: toml_app_config
|
||||||
|
.daemon
|
||||||
|
.max_poll_interval_sec,
|
||||||
|
throttle_on_battery: toml_app_config.daemon.throttle_on_battery,
|
||||||
|
log_level: toml_app_config.daemon.log_level.clone(),
|
||||||
|
stats_file_path: toml_app_config.daemon.stats_file_path.clone(),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
return Ok(app_config);
|
return Ok(app_config);
|
||||||
}
|
}
|
||||||
|
@ -140,6 +155,7 @@ pub fn load_config() -> Result<AppConfig, ConfigError> {
|
||||||
battery_charge_thresholds: default_toml_config.battery_charge_thresholds,
|
battery_charge_thresholds: default_toml_config.battery_charge_thresholds,
|
||||||
ignored_power_supplies: default_toml_config.ignored_power_supplies,
|
ignored_power_supplies: default_toml_config.ignored_power_supplies,
|
||||||
poll_interval_sec: default_toml_config.poll_interval_sec,
|
poll_interval_sec: default_toml_config.poll_interval_sec,
|
||||||
|
daemon: DaemonConfig::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,6 +181,8 @@ pub struct AppConfigToml {
|
||||||
pub ignored_power_supplies: Option<Vec<String>>,
|
pub ignored_power_supplies: Option<Vec<String>>,
|
||||||
#[serde(default = "default_poll_interval_sec")]
|
#[serde(default = "default_poll_interval_sec")]
|
||||||
pub poll_interval_sec: u64,
|
pub poll_interval_sec: u64,
|
||||||
|
#[serde(default)]
|
||||||
|
pub daemon: DaemonConfigToml,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ProfileConfigToml {
|
impl Default for ProfileConfigToml {
|
||||||
|
@ -192,9 +210,9 @@ pub struct TurboAutoSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default thresholds for Auto turbo mode
|
// Default thresholds for Auto turbo mode
|
||||||
pub const DEFAULT_LOAD_THRESHOLD_HIGH: f32 = 70.0; // Enable turbo if load is above this
|
pub const DEFAULT_LOAD_THRESHOLD_HIGH: f32 = 70.0; // enable turbo if load is above this
|
||||||
pub const DEFAULT_LOAD_THRESHOLD_LOW: f32 = 30.0; // Disable turbo if load is below this
|
pub const DEFAULT_LOAD_THRESHOLD_LOW: f32 = 30.0; // disable turbo if load is below this
|
||||||
pub const DEFAULT_TEMP_THRESHOLD_HIGH: f32 = 75.0; // Disable turbo if temperature is above this
|
pub const DEFAULT_TEMP_THRESHOLD_HIGH: f32 = 75.0; // disable turbo if temperature is above this
|
||||||
|
|
||||||
fn default_load_threshold_high() -> f32 {
|
fn default_load_threshold_high() -> f32 {
|
||||||
DEFAULT_LOAD_THRESHOLD_HIGH
|
DEFAULT_LOAD_THRESHOLD_HIGH
|
||||||
|
@ -237,3 +255,99 @@ impl From<ProfileConfigToml> for ProfileConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
|
pub struct DaemonConfig {
|
||||||
|
#[serde(default = "default_poll_interval_sec")]
|
||||||
|
pub poll_interval_sec: u64,
|
||||||
|
#[serde(default = "default_adaptive_interval")]
|
||||||
|
pub adaptive_interval: bool,
|
||||||
|
#[serde(default = "default_min_poll_interval_sec")]
|
||||||
|
pub min_poll_interval_sec: u64,
|
||||||
|
#[serde(default = "default_max_poll_interval_sec")]
|
||||||
|
pub max_poll_interval_sec: u64,
|
||||||
|
#[serde(default = "default_throttle_on_battery")]
|
||||||
|
pub throttle_on_battery: bool,
|
||||||
|
#[serde(default = "default_log_level")]
|
||||||
|
pub log_level: LogLevel,
|
||||||
|
#[serde(default = "default_stats_file_path")]
|
||||||
|
pub stats_file_path: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, Clone, PartialEq)]
|
||||||
|
pub enum LogLevel {
|
||||||
|
Error,
|
||||||
|
Warning,
|
||||||
|
Info,
|
||||||
|
Debug,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DaemonConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
poll_interval_sec: default_poll_interval_sec(),
|
||||||
|
adaptive_interval: default_adaptive_interval(),
|
||||||
|
min_poll_interval_sec: default_min_poll_interval_sec(),
|
||||||
|
max_poll_interval_sec: default_max_poll_interval_sec(),
|
||||||
|
throttle_on_battery: default_throttle_on_battery(),
|
||||||
|
log_level: default_log_level(),
|
||||||
|
stats_file_path: default_stats_file_path(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_adaptive_interval() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_min_poll_interval_sec() -> u64 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_max_poll_interval_sec() -> u64 {
|
||||||
|
30
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_throttle_on_battery() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_log_level() -> LogLevel {
|
||||||
|
LogLevel::Info
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_stats_file_path() -> Option<String> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
|
pub struct DaemonConfigToml {
|
||||||
|
#[serde(default = "default_poll_interval_sec")]
|
||||||
|
pub poll_interval_sec: u64,
|
||||||
|
#[serde(default = "default_adaptive_interval")]
|
||||||
|
pub adaptive_interval: bool,
|
||||||
|
#[serde(default = "default_min_poll_interval_sec")]
|
||||||
|
pub min_poll_interval_sec: u64,
|
||||||
|
#[serde(default = "default_max_poll_interval_sec")]
|
||||||
|
pub max_poll_interval_sec: u64,
|
||||||
|
#[serde(default = "default_throttle_on_battery")]
|
||||||
|
pub throttle_on_battery: bool,
|
||||||
|
#[serde(default = "default_log_level")]
|
||||||
|
pub log_level: LogLevel,
|
||||||
|
#[serde(default = "default_stats_file_path")]
|
||||||
|
pub stats_file_path: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DaemonConfigToml {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
poll_interval_sec: default_poll_interval_sec(),
|
||||||
|
adaptive_interval: default_adaptive_interval(),
|
||||||
|
min_poll_interval_sec: default_min_poll_interval_sec(),
|
||||||
|
max_poll_interval_sec: default_max_poll_interval_sec(),
|
||||||
|
throttle_on_battery: default_throttle_on_battery(),
|
||||||
|
log_level: default_log_level(),
|
||||||
|
stats_file_path: default_stats_file_path(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
259
src/daemon.rs
259
src/daemon.rs
|
@ -1,13 +1,27 @@
|
||||||
use crate::config::AppConfig;
|
use crate::config::{AppConfig, LogLevel};
|
||||||
|
use crate::core::SystemReport;
|
||||||
use crate::engine;
|
use crate::engine;
|
||||||
use crate::monitor;
|
use crate::monitor;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
/// Run the daemon in foreground mode
|
/// Run the daemon
|
||||||
pub fn run_background(config: AppConfig) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn run_daemon(config: AppConfig, verbose: bool) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
println!("Starting superfreq daemon in foreground mode...");
|
// Set effective log level based on config and verbose flag
|
||||||
|
let effective_log_level = if verbose {
|
||||||
|
LogLevel::Debug
|
||||||
|
} else {
|
||||||
|
config.daemon.log_level.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
log_message(
|
||||||
|
&effective_log_level,
|
||||||
|
LogLevel::Info,
|
||||||
|
"Starting superfreq daemon...",
|
||||||
|
);
|
||||||
|
|
||||||
// Create a flag that will be set to true when a signal is received
|
// Create a flag that will be set to true when a signal is received
|
||||||
let running = Arc::new(AtomicBool::new(true));
|
let running = Arc::new(AtomicBool::new(true));
|
||||||
|
@ -20,42 +34,259 @@ pub fn run_background(config: AppConfig) -> Result<(), Box<dyn std::error::Error
|
||||||
})
|
})
|
||||||
.expect("Error setting Ctrl-C handler");
|
.expect("Error setting Ctrl-C handler");
|
||||||
|
|
||||||
println!(
|
log_message(
|
||||||
"Daemon initialized with poll interval: {}s",
|
&effective_log_level,
|
||||||
config.poll_interval_sec
|
LogLevel::Info,
|
||||||
|
&format!(
|
||||||
|
"Daemon initialized with poll interval: {}s",
|
||||||
|
config.daemon.poll_interval_sec
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Set up stats file if configured
|
||||||
|
if let Some(stats_path) = &config.daemon.stats_file_path {
|
||||||
|
log_message(
|
||||||
|
&effective_log_level,
|
||||||
|
LogLevel::Info,
|
||||||
|
&format!("Stats will be written to: {}", stats_path),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variables for adaptive polling
|
||||||
|
let mut current_poll_interval = config.daemon.poll_interval_sec;
|
||||||
|
let mut last_settings_change = Instant::now();
|
||||||
|
let mut last_system_state = SystemState::Unknown;
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
while running.load(Ordering::SeqCst) {
|
while running.load(Ordering::SeqCst) {
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
|
|
||||||
match monitor::collect_system_report(&config) {
|
match monitor::collect_system_report(&config) {
|
||||||
Ok(report) => {
|
Ok(report) => {
|
||||||
println!("Collected system report, applying settings...");
|
log_message(
|
||||||
|
&effective_log_level,
|
||||||
|
LogLevel::Debug,
|
||||||
|
"Collected system report, applying settings...",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Determine current system state
|
||||||
|
let current_state = determine_system_state(&report);
|
||||||
|
|
||||||
|
// Update the stats file if configured
|
||||||
|
if let Some(stats_path) = &config.daemon.stats_file_path {
|
||||||
|
if let Err(e) = write_stats_file(stats_path, &report) {
|
||||||
|
log_message(
|
||||||
|
&effective_log_level,
|
||||||
|
LogLevel::Error,
|
||||||
|
&format!("Failed to write stats file: {}", e),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match engine::determine_and_apply_settings(&report, &config, None) {
|
match engine::determine_and_apply_settings(&report, &config, None) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
println!("Successfully applied system settings");
|
log_message(
|
||||||
|
&effective_log_level,
|
||||||
|
LogLevel::Debug,
|
||||||
|
"Successfully applied system settings",
|
||||||
|
);
|
||||||
|
|
||||||
|
// If system state changed or settings were applied differently, record the time
|
||||||
|
if current_state != last_system_state {
|
||||||
|
last_settings_change = Instant::now();
|
||||||
|
last_system_state = current_state.clone();
|
||||||
|
|
||||||
|
log_message(
|
||||||
|
&effective_log_level,
|
||||||
|
LogLevel::Info,
|
||||||
|
&format!("System state changed to: {:?}", current_state),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error applying system settings: {}", e);
|
log_message(
|
||||||
|
&effective_log_level,
|
||||||
|
LogLevel::Error,
|
||||||
|
&format!("Error applying system settings: {}", e),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adjust poll interval if adaptive polling is enabled
|
||||||
|
if config.daemon.adaptive_interval {
|
||||||
|
let time_since_change = last_settings_change.elapsed().as_secs();
|
||||||
|
|
||||||
|
// If we've been stable for a while, increase the interval (up to max)
|
||||||
|
if time_since_change > 60 {
|
||||||
|
current_poll_interval =
|
||||||
|
(current_poll_interval * 2).min(config.daemon.max_poll_interval_sec);
|
||||||
|
|
||||||
|
log_message(
|
||||||
|
&effective_log_level,
|
||||||
|
LogLevel::Debug,
|
||||||
|
&format!(
|
||||||
|
"Adaptive polling: increasing interval to {}s",
|
||||||
|
current_poll_interval
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if time_since_change < 10 {
|
||||||
|
// If we've had recent changes, decrease the interval (down to min)
|
||||||
|
current_poll_interval =
|
||||||
|
(current_poll_interval / 2).max(config.daemon.min_poll_interval_sec);
|
||||||
|
|
||||||
|
log_message(
|
||||||
|
&effective_log_level,
|
||||||
|
LogLevel::Debug,
|
||||||
|
&format!(
|
||||||
|
"Adaptive polling: decreasing interval to {}s",
|
||||||
|
current_poll_interval
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If not adaptive, use the configured poll interval
|
||||||
|
current_poll_interval = config.daemon.poll_interval_sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If on battery and throttling is enabled, lengthen the poll interval to save power
|
||||||
|
if config.daemon.throttle_on_battery
|
||||||
|
&& !report.batteries.is_empty()
|
||||||
|
&& report.batteries.first().map_or(false, |b| !b.ac_connected)
|
||||||
|
{
|
||||||
|
let battery_multiplier = 2; // Poll half as often on battery
|
||||||
|
current_poll_interval = (current_poll_interval * battery_multiplier)
|
||||||
|
.min(config.daemon.max_poll_interval_sec);
|
||||||
|
|
||||||
|
log_message(
|
||||||
|
&effective_log_level,
|
||||||
|
LogLevel::Debug,
|
||||||
|
"On battery power, increasing poll interval to save energy",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error collecting system report: {}", e);
|
log_message(
|
||||||
|
&effective_log_level,
|
||||||
|
LogLevel::Error,
|
||||||
|
&format!("Error collecting system report: {}", e),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sleep for the remaining time in the poll interval
|
// Sleep for the remaining time in the poll interval
|
||||||
let elapsed = start_time.elapsed();
|
let elapsed = start_time.elapsed();
|
||||||
let poll_duration = Duration::from_secs(config.poll_interval_sec);
|
let poll_duration = Duration::from_secs(current_poll_interval);
|
||||||
if elapsed < poll_duration {
|
if elapsed < poll_duration {
|
||||||
let sleep_time = poll_duration - elapsed;
|
let sleep_time = poll_duration - elapsed;
|
||||||
println!("Sleeping for {}s until next cycle", sleep_time.as_secs());
|
log_message(
|
||||||
|
&effective_log_level,
|
||||||
|
LogLevel::Debug,
|
||||||
|
&format!("Sleeping for {}s until next cycle", sleep_time.as_secs()),
|
||||||
|
);
|
||||||
std::thread::sleep(sleep_time);
|
std::thread::sleep(sleep_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Daemon stopped");
|
log_message(&effective_log_level, LogLevel::Info, "Daemon stopped");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Log a message based on the current log level
|
||||||
|
fn log_message(effective_level: &LogLevel, msg_level: LogLevel, message: &str) {
|
||||||
|
// Only log messages at or above the effective log level
|
||||||
|
let should_log = match effective_level {
|
||||||
|
LogLevel::Error => matches!(msg_level, LogLevel::Error),
|
||||||
|
LogLevel::Warning => matches!(msg_level, LogLevel::Error | LogLevel::Warning),
|
||||||
|
LogLevel::Info => matches!(
|
||||||
|
msg_level,
|
||||||
|
LogLevel::Error | LogLevel::Warning | LogLevel::Info
|
||||||
|
),
|
||||||
|
LogLevel::Debug => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if should_log {
|
||||||
|
match msg_level {
|
||||||
|
LogLevel::Error => eprintln!("ERROR: {}", message),
|
||||||
|
LogLevel::Warning => eprintln!("WARNING: {}", message),
|
||||||
|
LogLevel::Info => println!("INFO: {}", message),
|
||||||
|
LogLevel::Debug => println!("DEBUG: {}", message),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write current system stats to a file for --stats to read
|
||||||
|
fn write_stats_file(path: &str, report: &SystemReport) -> Result<(), std::io::Error> {
|
||||||
|
let mut file = File::create(path)?;
|
||||||
|
|
||||||
|
writeln!(file, "timestamp={:?}", report.timestamp)?;
|
||||||
|
|
||||||
|
// CPU info
|
||||||
|
writeln!(file, "governor={:?}", report.cpu_global.current_governor)?;
|
||||||
|
writeln!(file, "turbo={:?}", report.cpu_global.turbo_status)?;
|
||||||
|
|
||||||
|
if let Some(temp) = report.cpu_global.average_temperature_celsius {
|
||||||
|
writeln!(file, "cpu_temp={:.1}", temp)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Battery info
|
||||||
|
if !report.batteries.is_empty() {
|
||||||
|
let battery = &report.batteries[0];
|
||||||
|
writeln!(file, "ac_power={}", battery.ac_connected)?;
|
||||||
|
if let Some(cap) = battery.capacity_percent {
|
||||||
|
writeln!(file, "battery_percent={}", cap)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// System load
|
||||||
|
writeln!(file, "load_1m={:.2}", report.system_load.load_avg_1min)?;
|
||||||
|
writeln!(file, "load_5m={:.2}", report.system_load.load_avg_5min)?;
|
||||||
|
writeln!(file, "load_15m={:.2}", report.system_load.load_avg_15min)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Simplified system state used for determining when to adjust polling interval
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
enum SystemState {
|
||||||
|
Unknown,
|
||||||
|
OnAC,
|
||||||
|
OnBattery,
|
||||||
|
HighLoad,
|
||||||
|
LowLoad,
|
||||||
|
HighTemp,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determine the current system state for adaptive polling
|
||||||
|
fn determine_system_state(report: &SystemReport) -> SystemState {
|
||||||
|
// Check power state first
|
||||||
|
if !report.batteries.is_empty() {
|
||||||
|
if let Some(battery) = report.batteries.first() {
|
||||||
|
if battery.ac_connected {
|
||||||
|
return SystemState::OnAC;
|
||||||
|
} else {
|
||||||
|
return SystemState::OnBattery;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No batteries means desktop, so always AC
|
||||||
|
return SystemState::OnAC;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check temperature
|
||||||
|
if let Some(temp) = report.cpu_global.average_temperature_celsius {
|
||||||
|
if temp > 80.0 {
|
||||||
|
return SystemState::HighTemp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check load
|
||||||
|
let avg_load = report.system_load.load_avg_1min;
|
||||||
|
if avg_load > 3.0 {
|
||||||
|
return SystemState::HighLoad;
|
||||||
|
} else if avg_load < 0.5 {
|
||||||
|
return SystemState::LowLoad;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default case
|
||||||
|
SystemState::Unknown
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::config::{AppConfig, ProfileConfig, TurboAutoSettings};
|
use crate::config::{AppConfig, ProfileConfig};
|
||||||
use crate::core::{OperationalMode, SystemReport, TurboSetting};
|
use crate::core::{OperationalMode, SystemReport, TurboSetting};
|
||||||
use crate::cpu::{self, ControlError};
|
use crate::cpu::{self, ControlError};
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,10 @@ enum Commands {
|
||||||
/// Display current system information
|
/// Display current system information
|
||||||
Info,
|
Info,
|
||||||
/// Run as a daemon in the background
|
/// Run as a daemon in the background
|
||||||
Daemon,
|
Daemon {
|
||||||
|
#[clap(long)]
|
||||||
|
verbose: bool,
|
||||||
|
},
|
||||||
/// Set CPU governor
|
/// Set CPU governor
|
||||||
SetGovernor {
|
SetGovernor {
|
||||||
governor: String,
|
governor: String,
|
||||||
|
@ -186,7 +189,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
Some(Commands::SetPlatformProfile { profile }) => cpu::set_platform_profile(&profile)
|
Some(Commands::SetPlatformProfile { profile }) => cpu::set_platform_profile(&profile)
|
||||||
.map_err(|e| Box::new(e) as Box<dyn std::error::Error>),
|
.map_err(|e| Box::new(e) as Box<dyn std::error::Error>),
|
||||||
Some(Commands::Daemon) => daemon::run_background(config),
|
Some(Commands::Daemon { verbose }) => daemon::run_daemon(config, verbose),
|
||||||
None => {
|
None => {
|
||||||
println!("Welcome to superfreq! Use --help for commands.");
|
println!("Welcome to superfreq! Use --help for commands.");
|
||||||
println!("Current effective configuration: {:?}", config);
|
println!("Current effective configuration: {:?}", config);
|
||||||
|
|
|
@ -578,7 +578,7 @@ pub fn get_battery_info(config: &AppConfig) -> Result<Vec<BatteryInfo>> {
|
||||||
let mut batteries = Vec::new();
|
let mut batteries = Vec::new();
|
||||||
let power_supply_path = Path::new("/sys/class/power_supply");
|
let power_supply_path = Path::new("/sys/class/power_supply");
|
||||||
|
|
||||||
if (!power_supply_path.exists()) {
|
if !power_supply_path.exists() {
|
||||||
return Ok(batteries); // no power supply directory
|
return Ok(batteries); // no power supply directory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue