116 lines
4.3 KiB
Rust
116 lines
4.3 KiB
Rust
//! System Service Integration (Agent Integrator)
|
|
//!
|
|
//! This module translates the mathematical optimums defined by the Analyst
|
|
//! into actionable, real-world Linux/OS service configurations.
|
|
//! It generates templates for fan daemons (i8kmon, thinkfan) and handles
|
|
//! resolution strategies for overlapping daemons.
|
|
|
|
use anyhow::Result;
|
|
use std::path::Path;
|
|
use std::fs;
|
|
use crate::agent_analyst::OptimizationMatrix;
|
|
|
|
pub struct ServiceIntegrator;
|
|
|
|
impl ServiceIntegrator {
|
|
/// Generates and saves an i8kmon configuration based on the balanced profile.
|
|
pub fn generate_i8kmon_config(matrix: &OptimizationMatrix, output_path: &Path) -> Result<()> {
|
|
let profile = &matrix.balanced;
|
|
|
|
let mut conf = String::new();
|
|
conf.push_str("# Auto-generated by ember-tune Integrator
|
|
");
|
|
conf.push_str(&format!("# Profile: {}
|
|
|
|
", profile.name));
|
|
|
|
for (i, p) in profile.fan_curve.iter().enumerate() {
|
|
// i8kmon syntax: set config(state) {left_fan right_fan temp_on temp_off}
|
|
// State 0, 1, 2, 3 correspond to BIOS fan states (off, low, high)
|
|
|
|
let state = match p.pwm_percent {
|
|
0..=20 => 0,
|
|
21..=50 => 1,
|
|
51..=100 => 2,
|
|
_ => 2,
|
|
};
|
|
|
|
let off = if i == 0 { "-".to_string() } else { format!("{}", p.temp_off) };
|
|
conf.push_str(&format!("set config({}) {{{} {} {} {}}}
|
|
", i, state, state, p.temp_on, off));
|
|
}
|
|
|
|
fs::write(output_path, conf)?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Generates a thinkfan configuration.
|
|
pub fn generate_thinkfan_config(matrix: &OptimizationMatrix, output_path: &Path) -> Result<()> {
|
|
let profile = &matrix.balanced;
|
|
|
|
let mut conf = String::new();
|
|
conf.push_str("# Auto-generated by ember-tune Integrator
|
|
");
|
|
conf.push_str("sensors:
|
|
- hwmon: /sys/class/hwmon/hwmon0/temp1_input
|
|
|
|
");
|
|
conf.push_str("levels:
|
|
");
|
|
|
|
for (i, p) in profile.fan_curve.iter().enumerate() {
|
|
// thinkfan syntax: - [level, temp_down, temp_up]
|
|
let level = match p.pwm_percent {
|
|
0..=20 => 0,
|
|
21..=40 => 1,
|
|
41..=60 => 3,
|
|
61..=80 => 5,
|
|
_ => 7,
|
|
};
|
|
|
|
let down = if i == 0 { 0.0 } else { p.temp_off };
|
|
conf.push_str(&format!(" - [{}, {}, {}]
|
|
", level, down, p.temp_on));
|
|
}
|
|
|
|
fs::write(output_path, conf)?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Generates a resolution checklist/script for daemons.
|
|
pub fn generate_conflict_resolution_script(output_path: &Path) -> Result<()> {
|
|
let script = r#"#!/bin/bash
|
|
# ember-tune Daemon Neutralization Script
|
|
|
|
# 1. Mask power-profiles-daemon (Prevent ACPI overrides)
|
|
systemctl mask power-profiles-daemon
|
|
|
|
# 2. Filter TLP (Prevent CPU governor fights while keeping PCIe saving)
|
|
sed -i 's/^CPU_SCALING_GOVERNOR_ON_AC=.*/CPU_SCALING_GOVERNOR_ON_AC=""/' /etc/tlp.conf
|
|
sed -i 's/^CPU_BOOST_ON_AC=.*/CPU_BOOST_ON_AC=""/' /etc/tlp.conf
|
|
systemctl restart tlp
|
|
|
|
# 3. Thermald Delegate (We provide the trips, it handles the rest)
|
|
# (Ensure your custom thermal-conf.xml is in /etc/thermald/)
|
|
systemctl restart thermald
|
|
"#;
|
|
fs::write(output_path, script)?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Generates a thermald configuration XML.
|
|
pub fn generate_thermald_config(matrix: &OptimizationMatrix, output_path: &Path) -> Result<()> {
|
|
let profile = &matrix.balanced;
|
|
let mut xml = String::new();
|
|
xml.push_str("<?xml version=\"1.0\"?>\n<ThermalConfiguration>\n <Platform>\n <Name>ember-tune Balanced</Name>\n <ProductName>Generic</ProductName>\n <Preference>balanced</Preference>\n <ThermalZones>\n <ThermalZone>\n <Type>cpu</Type>\n <TripPoints>\n");
|
|
|
|
for (i, p) in profile.fan_curve.iter().enumerate() {
|
|
xml.push_str(&format!(" <TripPoint>\n <SensorType>cpu</SensorType>\n <Temperature>{}</Temperature>\n <Type>Passive</Type>\n <ControlId>{}</ControlId>\n </TripPoint>\n", p.temp_on * 1000.0, i));
|
|
}
|
|
|
|
xml.push_str(" </TripPoints>\n </ThermalZone>\n </ThermalZones>\n </Platform>\n</ThermalConfiguration>\n");
|
|
fs::write(output_path, xml)?;
|
|
Ok(())
|
|
}
|
|
}
|