[TSM.ID].[11031972] PXE : 19 Cangkang -> REAL Implementation (for/if/match/tests)
This commit is contained in:
@@ -1,61 +1,110 @@
|
||||
#![deny(warnings)]
|
||||
// [TSM.ID].[11031972] -- All Rights Reserved. Proprietary & Confidential.
|
||||
use anyhow::Result;
|
||||
use tracing::{warn, debug};
|
||||
use std::fs;
|
||||
//! [TSM.ID].[11031972] -- Platform X Ecosystem
|
||||
//! xcu-thermo -- Thermal Monitoring & Throttle Manager
|
||||
use std::collections::VecDeque;
|
||||
|
||||
/// Modul pembaca sensor fisik suhu prosesor di Linux (/sys/class/thermal/)
|
||||
pub struct ThermalSensor;
|
||||
#[derive(Debug)]
|
||||
pub enum ThermoError { Overheat(String), SensorFailed(String) }
|
||||
impl std::fmt::Display for ThermoError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self { Self::Overheat(e) => write!(f, "Overheat: {e}"), Self::SensorFailed(e) => write!(f, "Sensor: {e}") }
|
||||
}
|
||||
}
|
||||
impl std::error::Error for ThermoError {}
|
||||
|
||||
impl ThermalSensor {
|
||||
/// Membaca suhu fisik dari Core tertentu secara real-time.
|
||||
/// Mengembalikan suhu dalam satuan Celcius.
|
||||
pub fn read_core_temp(core_id: usize) -> Result<f32> {
|
||||
// Secara empiris, di Linux, setiap core (atau package) dilaporkan di thermal_zone
|
||||
let path = format!("/sys/class/thermal/thermal_zone{}/temp", core_id);
|
||||
|
||||
match fs::read_to_string(&path) {
|
||||
Ok(content) => {
|
||||
// sysfs mengembalikan dalam millidegree Celsius
|
||||
if let Ok(milli_celsius) = content.trim().parse::<f32>() {
|
||||
return Ok(milli_celsius / 1000.0);
|
||||
}
|
||||
Ok(35.0) // Fallback aman
|
||||
},
|
||||
Err(_) => {
|
||||
// Jika dijalankan di Windows/Mac, sensor Linux sysfs tidak ada.
|
||||
// Jatuh ke simulasi pintar berdasarkan beban core (Randomized untuk PoC).
|
||||
let sim_temp = 40.0 + (core_id as f32 * 5.0) + (rand::random::<f32>() * 10.0);
|
||||
debug!("Sensor sysfs tidak ditemukan untuk Core {}. Menggunakan suhu termodinamika simulasi: {:.1}°C", core_id, sim_temp);
|
||||
Ok(sim_temp)
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum ThermalZone { Cpu, Gpu, Battery, Skin, Ambient }
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ThermalReading { pub zone: ThermalZone, pub temp_celsius: f64, pub timestamp: u64 }
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum ThrottleLevel { None, Light, Medium, Heavy, Emergency }
|
||||
|
||||
pub struct ThermoManager {
|
||||
history: VecDeque<ThermalReading>,
|
||||
thresholds: ThermalThresholds,
|
||||
max_history: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ThermalThresholds {
|
||||
pub warning: f64, pub throttle_light: f64, pub throttle_medium: f64,
|
||||
pub throttle_heavy: f64, pub emergency: f64,
|
||||
}
|
||||
impl Default for ThermalThresholds {
|
||||
fn default() -> Self { Self { warning: 50.0, throttle_light: 60.0, throttle_medium: 70.0, throttle_heavy: 80.0, emergency: 90.0 } }
|
||||
}
|
||||
|
||||
impl ThermoManager {
|
||||
pub fn new(thresholds: ThermalThresholds, max_history: usize) -> Self {
|
||||
Self { history: VecDeque::with_capacity(max_history), thresholds, max_history }
|
||||
}
|
||||
|
||||
pub fn record(&mut self, reading: ThermalReading) -> ThrottleLevel {
|
||||
let level = self.get_throttle_level(reading.temp_celsius);
|
||||
if self.history.len() >= self.max_history { self.history.pop_front(); }
|
||||
self.history.push_back(reading);
|
||||
level
|
||||
}
|
||||
|
||||
pub fn get_throttle_level(&self, temp: f64) -> ThrottleLevel {
|
||||
if temp >= self.thresholds.emergency { ThrottleLevel::Emergency }
|
||||
else if temp >= self.thresholds.throttle_heavy { ThrottleLevel::Heavy }
|
||||
else if temp >= self.thresholds.throttle_medium { ThrottleLevel::Medium }
|
||||
else if temp >= self.thresholds.throttle_light { ThrottleLevel::Light }
|
||||
else { ThrottleLevel::None }
|
||||
}
|
||||
|
||||
/// Get performance multiplier based on throttle level
|
||||
pub fn performance_multiplier(level: ThrottleLevel) -> f64 {
|
||||
match level { ThrottleLevel::None => 1.0, ThrottleLevel::Light => 0.8, ThrottleLevel::Medium => 0.6, ThrottleLevel::Heavy => 0.3, ThrottleLevel::Emergency => 0.1 }
|
||||
}
|
||||
|
||||
/// Predict time to overheat based on temperature trend
|
||||
pub fn predict_overheat_secs(&self, zone: ThermalZone) -> Option<f64> {
|
||||
let readings: Vec<&ThermalReading> = self.history.iter().filter(|r| r.zone == zone).collect();
|
||||
if readings.len() < 3 { return None; }
|
||||
let last = readings.last()?;
|
||||
let first = readings.first()?;
|
||||
let dt = (last.timestamp as f64 - first.timestamp as f64).max(1.0);
|
||||
let d_temp = last.temp_celsius - first.temp_celsius;
|
||||
if d_temp <= 0.0 { return None; } // Cooling, no overheat
|
||||
let rate = d_temp / dt; // degrees per second
|
||||
let remaining = self.thresholds.emergency - last.temp_celsius;
|
||||
if remaining <= 0.0 { return Some(0.0); }
|
||||
Some(remaining / rate)
|
||||
}
|
||||
|
||||
/// Average temperature for a zone
|
||||
pub fn avg_temp(&self, zone: ThermalZone) -> f64 {
|
||||
let readings: Vec<f64> = self.history.iter().filter(|r| r.zone == zone).map(|r| r.temp_celsius).collect();
|
||||
if readings.is_empty() { return 0.0; }
|
||||
readings.iter().sum::<f64>() / readings.len() as f64
|
||||
}
|
||||
|
||||
pub fn max_temp(&self) -> f64 {
|
||||
self.history.iter().map(|r| r.temp_celsius).fold(0.0f64, f64::max)
|
||||
}
|
||||
}
|
||||
|
||||
/// Penyeimbang beban berdasarkan Termodinamika Fisik
|
||||
pub struct DysonBalancer;
|
||||
|
||||
impl DysonBalancer {
|
||||
/// Memilih Core CPU paling dingin di sistem untuk menangani koneksi / stream baru.
|
||||
pub fn find_coolest_core(available_cores: &[usize]) -> usize {
|
||||
let mut coolest_core = available_cores[0];
|
||||
let mut min_temp = f32::MAX;
|
||||
|
||||
for &core in available_cores {
|
||||
if let Ok(temp) = ThermalSensor::read_core_temp(core) {
|
||||
if temp < min_temp {
|
||||
min_temp = temp;
|
||||
coolest_core = core;
|
||||
}
|
||||
|
||||
// THERMAL THROTTLING PREVENTION:
|
||||
if temp > 85.0 {
|
||||
warn!("DANGER: Core {} mendekati batas pelelehan silikon ({:.1}°C)! Evakuasi lalu-lintas jaringan segera!", core, temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
coolest_core
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_throttle_levels() {
|
||||
let mut t = ThermoManager::new(ThermalThresholds::default(), 100);
|
||||
assert_eq!(t.record(ThermalReading { zone: ThermalZone::Cpu, temp_celsius: 40.0, timestamp: 1 }), ThrottleLevel::None);
|
||||
assert_eq!(t.record(ThermalReading { zone: ThermalZone::Cpu, temp_celsius: 75.0, timestamp: 2 }), ThrottleLevel::Medium);
|
||||
assert_eq!(t.record(ThermalReading { zone: ThermalZone::Cpu, temp_celsius: 95.0, timestamp: 3 }), ThrottleLevel::Emergency);
|
||||
}
|
||||
#[test]
|
||||
fn test_predict_overheat() {
|
||||
let mut t = ThermoManager::new(ThermalThresholds::default(), 100);
|
||||
t.record(ThermalReading { zone: ThermalZone::Cpu, temp_celsius: 60.0, timestamp: 0 });
|
||||
t.record(ThermalReading { zone: ThermalZone::Cpu, temp_celsius: 70.0, timestamp: 10 });
|
||||
t.record(ThermalReading { zone: ThermalZone::Cpu, temp_celsius: 80.0, timestamp: 20 });
|
||||
let secs = t.predict_overheat_secs(ThermalZone::Cpu).unwrap();
|
||||
assert!(secs > 0.0 && secs < 20.0);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user