1use anyhow::Result;
2use sysinfo::{DiskExt, CpuExt, System, SystemExt};
3use nvml_wrapper::Nvml;
4use nvml_wrapper::enum_wrappers::device::TemperatureSensor;
5use log::{debug, info};
6use crate::model::{SystemInfo, Processor, Disk, GraphicCard, GraphicsUsage, GraphicsProcessUtilization, SystemStatus, Process, Camera, NvidiaInfo};
7use crate::monitor::Monitor;
8use std::path::Path;
9
10#[cfg(feature = "v4l")]
11use crate::camera::list_cameras;
12
13#[cfg(not(feature = "v4l"))]
14fn list_cameras() -> Vec<Camera> {
15 vec![]
16}
17
18pub struct Machine {
21 monitor: Monitor,
22 nvml: Option<nvml_wrapper::Nvml>,
23}
24
25
26impl Machine {
27 pub fn new() -> Machine{
34 let nvml = match Nvml::init() {
35 Ok(nvml) => {
36 info!("Nvidia driver loaded");
37 Some(nvml)
38 },
39 Err(error) => {
40 debug!("Nvidia not available because {}", error);
41 None
42 }
43 };
44 Machine{
45 monitor: Monitor::new(),
46 nvml: nvml
47 }
48 }
49
50 pub fn system_info(& mut self) -> SystemInfo {
58 let sys = System::new_all();
59 let processor = sys.global_cpu_info();
61 let processor = Processor{
62 frequency: processor.frequency(),
63 vendor: processor.vendor_id().to_string(),
64 brand: processor.brand().to_string()
65 };
66
67
68 let mut disks = Vec::new();
69 for disk in sys.disks() {
70 disks.push(Disk{
71 name: disk.name().to_str().unwrap().to_string(),
72 fs: String::from_utf8(disk.file_system().to_vec()).unwrap(),
73 storage_type: match disk.type_() {
74 sysinfo::DiskType::HDD => "HDD".to_string(),
75 sysinfo::DiskType::SSD => "SSD".to_string(),
76 _ => "Unknown".to_string()
77 },
78 available: disk.available_space(),
79 size: disk.total_space(),
80 mount_point: disk.mount_point().to_str().unwrap().to_string()
81 })
82 }
83
84 let mut cards = Vec::new();
85 let nvidia = if let Some(nvml) = &self.nvml {
86 for n in 0..nvml.device_count().unwrap() {
87 let device = nvml.device_by_index(n).unwrap();
88 cards.push(GraphicCard{
89 id: device.uuid().unwrap(),
90 name: device.name().unwrap(),
91 brand: match device.brand().unwrap() {
92 nvml_wrapper::enum_wrappers::device::Brand::GeForce => "GeForce".to_string(),
93 nvml_wrapper::enum_wrappers::device::Brand::Quadro => "Quadro".to_string(),
94 nvml_wrapper::enum_wrappers::device::Brand::Tesla => "Tesla".to_string(),
95 nvml_wrapper::enum_wrappers::device::Brand::Titan => "Titan".to_string(),
96 nvml_wrapper::enum_wrappers::device::Brand::NVS => "NVS".to_string(),
97 nvml_wrapper::enum_wrappers::device::Brand::GRID => "GRID".to_string(),
98 nvml_wrapper::enum_wrappers::device::Brand::Unknown => "Unknown".to_string(),
99 },
100 memory: device.memory_info().unwrap().total,
101 temperature: device.temperature(nvml_wrapper::enum_wrappers::device::TemperatureSensor::Gpu).unwrap()
102 });
103 }
104 Some(NvidiaInfo {
105 driver_version: nvml.sys_driver_version().unwrap(),
106 nvml_version: nvml.sys_nvml_version().unwrap(),
107 cuda_version: nvml.sys_cuda_driver_version().unwrap()
108 })
109 } else {
110 None
111 };
112
113 let model_path = Path::new("/sys/firmware/devicetree/base/model");
115 let model = if model_path.exists() {
116 Some(std::fs::read_to_string(model_path).unwrap())
117 } else {
118 None
119 };
120
121 let vaapi = Path::new("/dev/dri/renderD128").exists();
122
123 SystemInfo {
124 os_name: sys.name().unwrap(),
125 kernel_version: sys.kernel_version().unwrap(),
126 os_version: sys.os_version().unwrap(),
127 distribution: sys.distribution_id(),
128 hostname: sys.host_name().unwrap(),
129 memory: sys.total_memory(),
130 nvidia,
131 vaapi,
132 processor,
133 total_processors: sys.cpus().len(),
134 graphics: cards,
135 disks,
136 cameras: list_cameras(),
137 model
138 }
139 }
140
141 pub fn graphics_status(&self) -> Vec<GraphicsUsage> {
159 let mut cards = Vec::new();
160 if let Some(nvml) = &self.nvml {
161 for n in 0..nvml.device_count().unwrap() {
162 let device = nvml.device_by_index(n).unwrap();
163 let mut processes = Vec::new();
164 for p in device.process_utilization_stats(None).unwrap() {
165 processes.push(GraphicsProcessUtilization{
166 pid: p.pid,
167 gpu: p.sm_util,
168 memory: p.mem_util,
169 encoder: p.enc_util,
170 decoder: p.dec_util
171 });
172 }
173
174 cards.push(GraphicsUsage {
175 id: device.uuid().unwrap(),
176 memory_used: device.memory_info().unwrap().used,
177 encoder: device.encoder_utilization().unwrap().utilization,
178 decoder: device.decoder_utilization().unwrap().utilization,
179 gpu: device.utilization_rates().unwrap().gpu,
180 memory_usage: device.utilization_rates().unwrap().memory,
181 temperature: device.temperature(TemperatureSensor::Gpu).unwrap(),
182 processes
183 });
184 }
185 }
186
187 cards
188
189 }
190
191
192 pub fn track_process(&mut self, pid: i32) -> Result<()>{
202 self.monitor.track_process(pid)
203 }
204
205 pub fn untrack_process(&mut self, pid: i32) {
216 self.monitor.untrack_process(pid);
217 }
218
219 pub fn processes_status(& mut self) -> Vec<Process> {
237 self.monitor.next_processes().iter().map(|(pid, cpu)| Process{pid:*pid, cpu:*cpu}).collect::<Vec<Process>>()
238 }
239
240 pub fn system_status(& mut self) -> Result<SystemStatus> {
258 let (cpu, memory) = self.monitor.next()?;
259 Ok(SystemStatus {
260 memory,
261 cpu,
262 })
263 }
264
265}