#![allow(unused)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
use std::sync::{
atomic::{AtomicBool, AtomicU64, Ordering},
Arc,
};
use e_utils::once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use std::time::{Duration, Instant};
use strum::*;
pub static LOAD_CONTROLLER: Lazy<LoadController> = Lazy::new(|| LoadController::new(50));
pub const EXTEND1: i32 = 0x1;
#[doc(hidden)]
#[derive(Debug)]
pub enum Inner {
#[cfg(all(feature = "lhm", target_os = "windows"))]
LHM(crate::lhm::LHM),
#[cfg(all(feature = "ohm", target_os = "windows"))]
OHM(crate::ohm::OHM),
#[cfg(all(feature = "aida64", target_os = "windows"))]
AIDA64(crate::aida64::AIDA64),
#[cfg(feature = "os")]
OS(crate::os::OS),
OSMore,
Drive,
FileInfo,
OSSystem,
OSOffice,
Disk,
#[cfg(all(feature = "core-temp", target_os = "windows"))]
CoreTemp(crate::core_temp::CoreTemp),
}
impl Inner {
#[cfg(feature = "cli")]
pub fn from_api(api: crate::OptsApi) -> e_utils::AnyResult<Self> {
use crate::{wmic::HardwareMonitor as _, OptsApi};
match api {
#[cfg(all(feature = "lhm", target_os = "windows"))]
OptsApi::LHM => Ok(Self::LHM(crate::lhm::LHM::new()?)),
#[cfg(not(all(feature = "lhm", target_os = "windows")))]
OptsApi::LHM => Err("LHM not supported".into()),
#[cfg(all(feature = "ohm", target_os = "windows"))]
OptsApi::OHM => Ok(Self::OHM(crate::ohm::OHM::new()?)),
#[cfg(not(all(feature = "ohm", target_os = "windows")))]
OptsApi::OHM => Err("OHM not supported".into()),
#[cfg(all(feature = "aida64", target_os = "windows"))]
OptsApi::AIDA64 => Ok(Self::AIDA64(crate::aida64::AIDA64::new()?)),
#[cfg(not(all(feature = "aida64", target_os = "windows")))]
OptsApi::AIDA64 => Err("AIDA64 not supported".into()),
#[cfg(feature = "os")]
OptsApi::OS => Ok(Self::OS(crate::os::OS::new())),
#[cfg(not(feature = "os"))]
OptsApi::OS => Err("OS not supported".into()),
OptsApi::OSMore => Ok(Self::OSMore),
OptsApi::Drive => Ok(Self::Drive),
OptsApi::FileInfo => Ok(Self::FileInfo),
OptsApi::OSSystem => Ok(Self::OSSystem),
OptsApi::OSOffice => Ok(Self::OSOffice),
OptsApi::Disk => Ok(Self::Disk),
#[cfg(all(feature = "core-temp", target_os = "windows"))]
OptsApi::CoreTemp => Ok(Self::CoreTemp(crate::core_temp::CoreTemp::new()?)),
#[cfg(not(all(feature = "core-temp", target_os = "windows")))]
OptsApi::CoreTemp => Err("CoreTemp not supported".into()),
}
}
}
impl Inner {
#[cfg(feature = "system")]
pub async fn get_cpu_core_count(&self) -> e_utils::AnyResult<usize> {
let mut sys = sysinfo::System::new();
sys.refresh_cpu_specifics(sysinfo::CpuRefreshKind::nothing().with_frequency());
Ok(sys.cpus().len())
}
#[cfg(feature = "system")]
pub async fn get_global_cpu_usage(&self) -> f32 {
let mut sys = sysinfo::System::new();
sys.refresh_cpu_specifics(sysinfo::CpuRefreshKind::nothing().with_cpu_usage());
sys.global_cpu_usage()
}
}
#[derive(Debug, Clone)]
pub struct LoadController {
pub loaded: Arc<AtomicU64>,
pub current_load: Arc<AtomicU64>,
pub current_iterations: Arc<AtomicU64>,
pub running: Arc<AtomicBool>,
pub total_iterations: Arc<AtomicU64>,
}
impl LoadController {
pub fn new(load: u64) -> Self {
let load = load.clamp(0, 100);
Self {
loaded: Arc::new(AtomicU64::new(load)),
current_load: Arc::new(AtomicU64::new(0)),
current_iterations: Arc::new(AtomicU64::new(100_000)),
running: Arc::new(AtomicBool::new(false)),
total_iterations: Arc::new(AtomicU64::new(0)),
}
}
pub fn set_loaded(&self, load: f64) {
let load = load.clamp(0.0, 100.0) as u64;
self.loaded.store(load, Ordering::Release);
}
pub fn get_iterations(&self) -> u64 {
self.current_iterations.load(Ordering::Acquire)
}
pub fn auto_fix_load(&self, load: f64) {
let current = load.clamp(0.0, 100.0) as u64;
self.current_load.store(current, Ordering::Release);
if load == 100.0 {
return;
}
let target = self.loaded.load(Ordering::Acquire);
if (target as i64 - current as i64).abs() > 5 {
let current_iters = self.current_iterations.load(Ordering::Acquire);
let new_iters = if current < target {
(current_iters as f64 * 1.1) as u64
} else {
(current_iters as f64 * 0.9) as u64
};
let new_iters = new_iters.clamp(u64::MIN, u64::MAX);
self.current_iterations.store(new_iters, Ordering::Release);
}
}
}
impl LoadController {
pub fn start_running(&self) {
crate::dp("启动负载");
self.running.store(true, Ordering::SeqCst);
}
pub fn stop_running(&self) {
crate::dp("关闭负载");
self.running.store(false, Ordering::SeqCst);
}
#[cfg(feature = "system")]
pub fn spawn_load(core_count: usize, hw_type: &HardwareType, s_type: &SensorType, loaded: f64) -> e_utils::Result<Vec<std::thread::JoinHandle<()>>> {
LOAD_CONTROLLER.set_loaded(loaded);
if matches!(
(hw_type, s_type),
(HardwareType::CPU, SensorType::Load | SensorType::Clock | SensorType::ClockAverage)
) {
if loaded == 0.0 {
return Err(
format!(
"Skipping load generation for hw_type: {:?}, sensor_type: {:?}, Load cannot be 0",
hw_type, s_type
)
.into(),
);
}
crate::dp(&format!("硬件:{} 传感器:{} 内核:{} 标准负载:{}% 启动负载", hw_type, s_type, core_count, loaded));
LOAD_CONTROLLER.start_running();
Ok(spawn_cpu_load(core_count))
} else {
Ok(vec![])
}
}
}
#[cfg(feature = "system")]
fn spawn_cpu_load(core_count: usize) -> Vec<std::thread::JoinHandle<()>> {
const ADJUST_INTERVAL: Duration = Duration::from_millis(100);
const MIN_SLEEP_DURATION: Duration = Duration::from_millis(100);
(0..core_count)
.map(|core_id| {
let running = LOAD_CONTROLLER.running.clone();
let total_iterations = LOAD_CONTROLLER.total_iterations.clone();
crate::dp(format!("核心 {} - 初始化", core_id));
std::thread::Builder::new()
.name(format!("cpu-load-{}", core_id)) .spawn(move || {
let mut sys = sysinfo::System::new();
let mut last_adjust = Instant::now();
while running.load(Ordering::Relaxed) {
let start_time = Instant::now();
let iterations = LOAD_CONTROLLER.get_iterations();
perform_cpu_work(iterations, &total_iterations);
if start_time.duration_since(last_adjust) >= ADJUST_INTERVAL {
adjust_load(&mut sys);
last_adjust = Instant::now(); }
if let Some(sleep_time) = MIN_SLEEP_DURATION.checked_sub(start_time.elapsed()) {
std::thread::sleep(sleep_time);
}
}
crate::dp(format!("核心 {} - 线程结束", core_id));
})
.expect("线程创建失败")
})
.collect()
}
#[cfg(feature = "system")]
fn adjust_load(sys: &mut sysinfo::System) {
sys.refresh_cpu_specifics(sysinfo::CpuRefreshKind::nothing().with_cpu_usage());
let cpu_load = (sys.global_cpu_usage() as f64).round().clamp(0.0, 100.0); LOAD_CONTROLLER.auto_fix_load(cpu_load);
}
#[inline(never)]
fn perform_cpu_work(iterations: u64, total_iterations: &AtomicU64) {
const MAX_X: f64 = f64::MAX; let mut x = std::hint::black_box(0.0_f64);
let mut overflow_check = 0;
for i in 0..iterations {
x = std::hint::black_box({
let new_x = (x.sin() + 1.0).sqrt() + (i as f64).cos() * std::f64::consts::PI;
if new_x.is_finite() && new_x.abs() < MAX_X {
new_x
} else {
overflow_check += 1;
0.0
}
});
if overflow_check > iterations / 2 {
crate::wp("CPU负载检测到过多的数值溢出");
break;
}
std::sync::atomic::fence(Ordering::Release);
}
total_iterations.fetch_add(iterations, Ordering::Relaxed);
}
#[derive(Clone, Serialize, Deserialize, Default)]
pub struct TestLoadResult {
pub min: f64,
pub max: f64,
pub avg: f64,
pub total: f64,
pub status: Vec<(String, f64)>,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct TestResults {
pub api: String,
pub hw_type: HardwareType,
pub sensor_type: SensorType,
pub res: String,
pub data: String,
pub min: f64,
pub max: f64,
pub avg: f64,
pub total: f64,
pub samples: usize,
pub test_secs: usize,
pub error_count: usize,
pub load: TestLoadResult,
pub status: Vec<(String, f64)>,
}
impl TestResults {
pub fn new() -> Self {
TestResults {
api: String::new(),
hw_type: HardwareType::default(),
sensor_type: SensorType::default(),
res: String::new(),
data: String::new(),
min: 0.0,
max: 0.0,
avg: 0.0,
total: 0.0,
samples: 0,
test_secs: 0,
error_count: 0,
load: TestLoadResult::default(),
status: Vec::new(),
}
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct TestParams {
pub test_secs: usize,
pub v1: f64,
pub v2: f64,
pub v3: f64,
}
impl TestResults {
pub fn update(&mut self, value: f64) {
self.min = if self.min == 0.0 { value } else { self.min.min(value) };
self.max = self.max.max(value);
self.total += value;
self.samples += 1;
self.status.push((String::new(), value));
self.avg = (self.total / self.samples as f64).round();
let load = LOAD_CONTROLLER.current_load.load(Ordering::SeqCst) as f64;
self.load.total += load;
self.load.avg = load;
}
pub fn std_deviation(&self) -> f64 {
if self.samples < 2 {
return 0.0;
}
let mean = self.avg;
let variance = self.status.iter().map(|x| (x.1 - mean).powi(2)).sum::<f64>() / (self.samples - 1) as f64;
variance.sqrt()
}
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Display, EnumString, EnumMessage, Default, VariantArray)]
pub enum HardwareType {
#[default]
#[strum(message = "所有硬件")]
ALL,
#[strum(message = "主板")]
Mainboard,
#[strum(message = "Super I/O 芯片")]
SuperIO,
#[strum(message = "中央处理器")]
CPU,
#[strum(message = "NVIDIA 图形处理器")]
GpuNvidia,
#[strum(message = "AMD/ATI 图形处理器")]
GpuAti,
#[strum(message = "T-Balancer 设备")]
TBalancer,
#[strum(message = "Heatmaster 设备")]
Heatmaster,
#[strum(message = "硬盘驱动器")]
HDD,
#[strum(message = "内存")]
RAM,
#[strum(message = "未知")]
Unknown,
}
impl HardwareType {
pub fn all(self) -> Vec<HardwareType> {
if self == HardwareType::ALL {
HardwareType::VARIANTS.iter().filter(|v| *v != &HardwareType::ALL).cloned().collect()
} else {
vec![self]
}
}
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Display, EnumString, EnumMessage, Default, VariantArray)]
pub enum SensorType {
#[default]
#[strum(message = "所有传感器")]
ALL,
#[strum(message = "电压")]
Voltage,
#[strum(message = "频率")]
Clock,
#[strum(message = "温度")]
Temperature,
#[strum(message = "负载")]
Load,
#[strum(message = "风扇")]
Fan,
#[strum(message = "流量")]
Flow,
#[strum(message = "控制")]
Control,
#[strum(message = "等级")]
Level,
#[strum(message = "功率")]
Power,
#[strum(message = "数据")]
Data,
#[strum(message = "GB数据")]
GBData,
#[strum(message = "吞吐量")]
Throughput,
#[strum(message = "数据速率")]
DataRate,
#[strum(message = "小数据包")]
SmallData,
#[strum(message = "GB小数据包")]
GBSmallData,
#[strum(message = "前端总线")]
FSB,
#[strum(message = "多路复用器")]
Multiplexer,
#[strum(message = "平均频率")]
ClockAverage,
#[strum(message = "未知")]
Unknown,
}
impl SensorType {
pub fn all(self) -> Vec<SensorType> {
if self == SensorType::ALL {
SensorType::VARIANTS.iter().filter(|v| *v != &SensorType::ALL).cloned().collect()
} else {
vec![self]
}
}
pub fn unit(&self) -> &'static str {
match self {
SensorType::Voltage => "V",
SensorType::ClockAverage | SensorType::Clock | SensorType::FSB | SensorType::Multiplexer => "MHz",
SensorType::Temperature => "°C",
SensorType::Load => "%",
SensorType::Fan => "RPM",
SensorType::Flow => "L/h",
SensorType::Control => "%",
SensorType::Level => "%",
SensorType::Power => "W",
SensorType::Data => "B",
SensorType::GBData | SensorType::GBSmallData => "GB",
SensorType::Throughput => "B/s",
SensorType::DataRate => "B/s",
SensorType::SmallData => "SB",
SensorType::ALL => "*",
SensorType::Unknown => "*",
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct Sensor {
pub Name: String,
pub Identifier: String,
#[serde(rename = "SensorType")]
pub _SensorType: String,
#[serde(skip)]
pub SensorType: SensorType,
pub Parent: String,
pub Value: f64,
pub Min: f64,
pub Max: f64,
pub Index: i32,
#[serde(skip)]
pub data: String,
}
impl Sensor {
pub fn sensor_unit(&self) -> String {
format!("{}({})", self.SensorType.unit(), self.SensorType.get_message().unwrap_or_default())
}
}