use std::collections::VecDeque;
use std::sync::{Arc, Mutex, RwLock};
use super::{GpuDeviceInfo, GpuMemoryMetrics, GpuMetrics, MonitorConfig, MonitorError};
pub struct GpuMonitor {
device_info: GpuDeviceInfo,
config: MonitorConfig,
history: Arc<RwLock<VecDeque<GpuMetrics>>>,
#[cfg(feature = "gpu")]
_background_handle: Option<std::thread::JoinHandle<()>>,
stop_signal: Arc<Mutex<bool>>,
}
impl GpuMonitor {
#[cfg(all(feature = "gpu", not(target_arch = "wasm32")))]
pub fn new(device_index: u32, config: MonitorConfig) -> Result<Self, MonitorError> {
let device_info = GpuDeviceInfo::query_device(device_index)?;
let history = Arc::new(RwLock::new(VecDeque::with_capacity(config.history_size)));
let stop_signal = Arc::new(Mutex::new(false));
let monitor = Self { device_info, config, history, _background_handle: None, stop_signal };
Ok(monitor)
}
#[cfg(not(feature = "gpu"))]
pub fn new(_device_index: u32, _config: MonitorConfig) -> Result<Self, MonitorError> {
Err(MonitorError::NotAvailable("GPU feature not enabled".to_string()))
}
#[must_use]
pub fn mock(device_info: GpuDeviceInfo, config: MonitorConfig) -> Self {
Self {
device_info,
config,
history: Arc::new(RwLock::new(VecDeque::with_capacity(16))),
#[cfg(feature = "gpu")]
_background_handle: None,
stop_signal: Arc::new(Mutex::new(false)),
}
}
#[must_use]
pub fn device_info(&self) -> &GpuDeviceInfo {
&self.device_info
}
#[must_use]
pub fn config(&self) -> &MonitorConfig {
&self.config
}
pub fn collect(&self) -> Result<GpuMetrics, MonitorError> {
let memory = GpuMemoryMetrics::new(
self.device_info.vram_total,
0, self.device_info.vram_total,
);
let metrics = GpuMetrics::new(self.device_info.index, memory);
if let Ok(mut history) = self.history.write() {
if history.len() >= self.config.history_size {
history.pop_front();
}
history.push_back(metrics.clone());
}
Ok(metrics)
}
pub fn latest(&self) -> Result<GpuMetrics, MonitorError> {
self.history
.read()
.ok()
.and_then(|h| h.back().cloned())
.ok_or(MonitorError::QueryFailed("No metrics available".to_string()))
}
#[must_use]
pub fn history(&self) -> Vec<GpuMetrics> {
self.history.read().map(|h| h.iter().cloned().collect()).unwrap_or_default()
}
#[must_use]
pub fn sample_count(&self) -> usize {
self.history.read().map(|h| h.len()).unwrap_or(0)
}
pub fn clear_history(&self) {
if let Ok(mut history) = self.history.write() {
history.clear();
}
}
#[must_use]
pub fn is_collecting(&self) -> bool {
#[cfg(feature = "gpu")]
{
self._background_handle.is_some()
}
#[cfg(not(feature = "gpu"))]
{
false
}
}
pub fn stop(&self) {
if let Ok(mut stop) = self.stop_signal.lock() {
*stop = true;
}
}
}
impl Drop for GpuMonitor {
fn drop(&mut self) {
self.stop();
}
}