sysinfo/common/system.rs
1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::collections::{HashMap, HashSet};
4use std::ffi::{OsStr, OsString};
5use std::fmt;
6use std::path::Path;
7use std::process::ExitStatus;
8use std::str::FromStr;
9
10use crate::common::DiskUsage;
11use crate::common::impl_get_set::impl_get_set;
12use crate::{CpuInner, Gid, MotherboardInner, ProcessInner, ProductInner, SystemInner, Uid};
13
14/// Type containing system's information such as processes, memory and CPU.
15///
16/// ⚠️ On newer Android versions, there are restrictions on which system information
17/// a non-system application has access to. So CPU information might not be available.
18///
19/// ```
20/// use sysinfo::System;
21///
22/// if sysinfo::IS_SUPPORTED_SYSTEM {
23/// println!("System: {:?}", System::new_all());
24/// } else {
25/// println!("This OS isn't supported (yet?).");
26/// }
27/// ```
28pub struct System {
29 pub(crate) inner: SystemInner,
30}
31
32impl Default for System {
33 fn default() -> System {
34 System::new()
35 }
36}
37
38impl System {
39 /// Creates a new [`System`] instance with nothing loaded.
40 ///
41 /// Use one of the refresh methods (like [`refresh_all`]) to update its internal information.
42 ///
43 /// [`System`]: crate::System
44 /// [`refresh_all`]: #method.refresh_all
45 ///
46 /// ```no_run
47 /// use sysinfo::System;
48 ///
49 /// let s = System::new();
50 /// ```
51 pub fn new() -> Self {
52 Self::new_with_specifics(RefreshKind::nothing())
53 }
54
55 /// Creates a new [`System`] instance with everything loaded.
56 ///
57 /// It is an equivalent of [`System::new_with_specifics`]`(`[`RefreshKind::everything`]`())`.
58 ///
59 /// [`System`]: crate::System
60 ///
61 /// ```no_run
62 /// use sysinfo::System;
63 ///
64 /// let s = System::new_all();
65 /// ```
66 pub fn new_all() -> Self {
67 Self::new_with_specifics(RefreshKind::everything())
68 }
69
70 /// Creates a new [`System`] instance and refresh the data corresponding to the
71 /// given [`RefreshKind`].
72 ///
73 /// [`System`]: crate::System
74 ///
75 /// ```
76 /// use sysinfo::{ProcessRefreshKind, RefreshKind, System};
77 ///
78 /// // We want to only refresh processes.
79 /// let mut system = System::new_with_specifics(
80 /// RefreshKind::nothing().with_processes(ProcessRefreshKind::everything()),
81 /// );
82 ///
83 /// # if sysinfo::IS_SUPPORTED_SYSTEM && !cfg!(feature = "apple-sandbox") {
84 /// assert!(!system.processes().is_empty());
85 /// # }
86 /// ```
87 pub fn new_with_specifics(refreshes: RefreshKind) -> Self {
88 let mut s = Self {
89 inner: SystemInner::new(),
90 };
91 s.refresh_specifics(refreshes);
92 s
93 }
94
95 /// Refreshes according to the given [`RefreshKind`]. It calls the corresponding
96 /// "refresh_" methods.
97 ///
98 /// It will remove dead processes if [`RefreshKind::processes`] returns `Some`.
99 /// If you want to keep dead processes, use [`System::refresh_processes_specifics`]
100 /// directly.
101 ///
102 /// ```
103 /// use sysinfo::{ProcessRefreshKind, RefreshKind, System};
104 ///
105 /// let mut s = System::new_all();
106 ///
107 /// // Let's just update processes:
108 /// s.refresh_specifics(
109 /// RefreshKind::nothing().with_processes(ProcessRefreshKind::everything()),
110 /// );
111 /// ```
112 pub fn refresh_specifics(&mut self, refreshes: RefreshKind) {
113 if let Some(kind) = refreshes.memory() {
114 self.refresh_memory_specifics(kind);
115 }
116 if let Some(kind) = refreshes.cpu() {
117 self.refresh_cpu_specifics(kind);
118 }
119 if let Some(kind) = refreshes.processes() {
120 self.refresh_processes_specifics(ProcessesToUpdate::All, true, kind);
121 }
122 }
123
124 /// Refreshes all system and processes information.
125 ///
126 /// It is the same as calling `system.refresh_specifics(RefreshKind::everything())`.
127 ///
128 /// Don't forget to take a look at [`ProcessRefreshKind::everything`] method to see what it
129 /// will update for processes more in details.
130 ///
131 /// It will remove dead processes. If you want to keep dead processes, use
132 /// [`System::refresh_processes_specifics`] directly.
133 ///
134 /// ```no_run
135 /// use sysinfo::System;
136 ///
137 /// let mut s = System::new();
138 /// s.refresh_all();
139 /// ```
140 pub fn refresh_all(&mut self) {
141 self.refresh_specifics(RefreshKind::everything());
142 }
143
144 /// Refreshes RAM and SWAP usage.
145 ///
146 /// It is the same as calling `system.refresh_memory_specifics(MemoryRefreshKind::everything())`.
147 ///
148 /// If you don't want to refresh both, take a look at [`System::refresh_memory_specifics`].
149 ///
150 /// ```no_run
151 /// use sysinfo::System;
152 ///
153 /// let mut s = System::new();
154 /// s.refresh_memory();
155 /// ```
156 pub fn refresh_memory(&mut self) {
157 self.refresh_memory_specifics(MemoryRefreshKind::everything())
158 }
159
160 /// Refreshes system memory specific information.
161 ///
162 /// ```no_run
163 /// use sysinfo::{MemoryRefreshKind, System};
164 ///
165 /// let mut s = System::new();
166 /// s.refresh_memory_specifics(MemoryRefreshKind::nothing().with_ram());
167 /// ```
168 pub fn refresh_memory_specifics(&mut self, refresh_kind: MemoryRefreshKind) {
169 self.inner.refresh_memory_specifics(refresh_kind)
170 }
171
172 /// Refreshes CPUs usage.
173 ///
174 /// ⚠️ Please note that the result will very likely be inaccurate at the first call.
175 /// You need to call this method at least twice (with a bit of time between each call, like
176 /// 200 ms, take a look at [`MINIMUM_CPU_UPDATE_INTERVAL`] for more information)
177 /// to get accurate value as it uses previous results to compute the next value.
178 ///
179 /// Calling this method is the same as calling
180 /// `system.refresh_cpu_specifics(CpuRefreshKind::nothing().with_cpu_usage())`.
181 ///
182 /// ```no_run
183 /// use sysinfo::System;
184 ///
185 /// let mut s = System::new_all();
186 /// // Wait a bit because CPU usage is based on diff.
187 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
188 /// // Refresh CPUs again.
189 /// s.refresh_cpu_usage();
190 /// ```
191 ///
192 /// [`MINIMUM_CPU_UPDATE_INTERVAL`]: crate::MINIMUM_CPU_UPDATE_INTERVAL
193 pub fn refresh_cpu_usage(&mut self) {
194 self.refresh_cpu_specifics(CpuRefreshKind::nothing().with_cpu_usage())
195 }
196
197 /// Refreshes CPUs frequency information.
198 ///
199 /// Calling this method is the same as calling
200 /// `system.refresh_cpu_specifics(CpuRefreshKind::nothing().with_frequency())`.
201 ///
202 /// ```no_run
203 /// use sysinfo::System;
204 ///
205 /// let mut s = System::new_all();
206 /// s.refresh_cpu_frequency();
207 /// ```
208 pub fn refresh_cpu_frequency(&mut self) {
209 self.refresh_cpu_specifics(CpuRefreshKind::nothing().with_frequency())
210 }
211
212 /// Refreshes the list of CPU.
213 ///
214 /// Normally, this should almost never be needed as it's pretty rare for a computer
215 /// to add a CPU while running, but it's possible on some computers which shutdown
216 /// CPU if the load is low enough.
217 ///
218 /// The `refresh_kind` argument tells what information you want to be retrieved
219 /// for each CPU.
220 ///
221 /// ```no_run
222 /// use sysinfo::{CpuRefreshKind, System};
223 ///
224 /// let mut s = System::new_all();
225 /// // We already have the list of CPU filled, but we want to recompute it
226 /// // in case new CPUs were added.
227 /// s.refresh_cpu_list(CpuRefreshKind::everything());
228 /// ```
229 pub fn refresh_cpu_list(&mut self, refresh_kind: CpuRefreshKind) {
230 self.inner.refresh_cpu_list(refresh_kind);
231 }
232
233 /// Refreshes all information related to CPUs information. It does not refresh the CPU list.
234 /// If you want to refresh the CPU list, use [`System::refresh_cpu_list`] instead.
235 ///
236 /// If you only want the CPU usage, use [`System::refresh_cpu_usage`] instead.
237 ///
238 /// ⚠️ Please note that the result will be inaccurate at the first call.
239 /// You need to call this method at least twice (with a bit of time between each call, like
240 /// 200 ms, take a look at [`MINIMUM_CPU_UPDATE_INTERVAL`] for more information)
241 /// to get accurate value as it uses previous results to compute the next value.
242 ///
243 /// Calling this method is the same as calling
244 /// `system.refresh_cpu_specifics(CpuRefreshKind::everything())`.
245 ///
246 /// ```no_run
247 /// use sysinfo::System;
248 ///
249 /// let mut s = System::new_all();
250 /// s.refresh_cpu_all();
251 /// ```
252 ///
253 /// [`MINIMUM_CPU_UPDATE_INTERVAL`]: crate::MINIMUM_CPU_UPDATE_INTERVAL
254 pub fn refresh_cpu_all(&mut self) {
255 self.refresh_cpu_specifics(CpuRefreshKind::everything())
256 }
257
258 /// Refreshes CPUs specific information. It does not refresh the CPU list.
259 /// If you want to refresh the CPU list, use [`System::refresh_cpu_list`] instead.
260 ///
261 /// ```no_run
262 /// use sysinfo::{System, CpuRefreshKind};
263 ///
264 /// let mut s = System::new_all();
265 /// s.refresh_cpu_specifics(CpuRefreshKind::everything());
266 /// ```
267 pub fn refresh_cpu_specifics(&mut self, refresh_kind: CpuRefreshKind) {
268 self.inner.refresh_cpu_specifics(refresh_kind)
269 }
270
271 /// Gets all processes and updates their information, along with all the tasks each process has.
272 ///
273 /// It does the same as:
274 ///
275 /// ```no_run
276 /// # use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System, UpdateKind};
277 /// # let mut system = System::new();
278 /// system.refresh_processes_specifics(
279 /// ProcessesToUpdate::All,
280 /// true,
281 /// ProcessRefreshKind::nothing()
282 /// .with_memory()
283 /// .with_cpu()
284 /// .with_disk_usage()
285 /// .with_exe(UpdateKind::OnlyIfNotSet)
286 /// );
287 /// ```
288 ///
289 /// ⚠️ `remove_dead_processes` works as follows: if an updated process is dead, then it is
290 /// removed. So if you refresh pids 1, 2 and 3. If 2 and 7 are dead, only 2 will be removed
291 /// since 7 is not part of the update.
292 ///
293 /// ⚠️ On Linux, `sysinfo` keeps the `stat` files open by default. You can change this behaviour
294 /// by using [`set_open_files_limit`][crate::set_open_files_limit].
295 ///
296 /// ⚠️ On Linux, if you dont need the tasks of each process, you can use
297 /// `refresh_processes_specifics` with `ProcessRefreshKind::everything().without_tasks()`.
298 /// Refreshing all processes and their tasks can be quite expensive. For more information
299 /// see [`ProcessRefreshKind`].
300 ///
301 /// Example:
302 ///
303 /// ```no_run
304 /// use sysinfo::{ProcessesToUpdate, System};
305 ///
306 /// let mut s = System::new_all();
307 /// s.refresh_processes(ProcessesToUpdate::All, true);
308 /// ```
309 pub fn refresh_processes(
310 &mut self,
311 processes_to_update: ProcessesToUpdate<'_>,
312 remove_dead_processes: bool,
313 ) -> usize {
314 self.refresh_processes_specifics(
315 processes_to_update,
316 remove_dead_processes,
317 ProcessRefreshKind::nothing()
318 .with_memory()
319 .with_cpu()
320 .with_disk_usage()
321 .with_exe(UpdateKind::OnlyIfNotSet)
322 .with_tasks(),
323 )
324 }
325
326 /// Gets all processes and updates the specified information.
327 ///
328 /// Returns the number of updated processes.
329 ///
330 /// ⚠️ `remove_dead_processes` works as follows: if an updated process is dead, then it is
331 /// removed. So if you refresh pids 1, 2 and 3. If 2 and 7 are dead, only 2 will be removed
332 /// since 7 is not part of the update.
333 ///
334 /// ⚠️ On Linux, `sysinfo` keeps the `stat` files open by default. You can change this behaviour
335 /// by using [`set_open_files_limit`][crate::set_open_files_limit].
336 ///
337 /// ```no_run
338 /// use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System};
339 ///
340 /// let mut s = System::new_all();
341 /// s.refresh_processes_specifics(
342 /// ProcessesToUpdate::All,
343 /// true,
344 /// ProcessRefreshKind::everything(),
345 /// );
346 /// ```
347 pub fn refresh_processes_specifics(
348 &mut self,
349 processes_to_update: ProcessesToUpdate<'_>,
350 remove_dead_processes: bool,
351 refresh_kind: ProcessRefreshKind,
352 ) -> usize {
353 fn update_and_remove(pid: &Pid, processes: &mut HashMap<Pid, Process>) {
354 let updated = if let Some(proc) = processes.get_mut(pid) {
355 proc.inner.switch_updated()
356 } else {
357 return;
358 };
359 if !updated {
360 processes.remove(pid);
361 }
362 }
363 fn update(pid: &Pid, processes: &mut HashMap<Pid, Process>) {
364 if let Some(proc) = processes.get_mut(pid)
365 && !proc.inner.switch_updated()
366 {
367 proc.inner.set_nonexistent();
368 }
369 }
370
371 let nb_updated = self
372 .inner
373 .refresh_processes_specifics(processes_to_update, refresh_kind);
374 let processes = self.inner.processes_mut();
375 match processes_to_update {
376 ProcessesToUpdate::All => {
377 if remove_dead_processes {
378 processes.retain(|_, v| v.inner.switch_updated());
379 } else {
380 for proc in processes.values_mut() {
381 proc.inner.switch_updated();
382 }
383 }
384 }
385 ProcessesToUpdate::Some(pids) => {
386 let call = if remove_dead_processes {
387 update_and_remove
388 } else {
389 update
390 };
391 for pid in pids {
392 call(pid, processes);
393 }
394 }
395 }
396 nb_updated
397 }
398
399 /// Returns the process list.
400 ///
401 /// ```no_run
402 /// use sysinfo::System;
403 ///
404 /// let s = System::new_all();
405 /// for (pid, process) in s.processes() {
406 /// println!("{} {:?}", pid, process.name());
407 /// }
408 /// ```
409 pub fn processes(&self) -> &HashMap<Pid, Process> {
410 self.inner.processes()
411 }
412
413 /// Returns the process corresponding to the given `pid` or `None` if no such process exists.
414 ///
415 /// ```no_run
416 /// use sysinfo::{Pid, System};
417 ///
418 /// let s = System::new_all();
419 /// if let Some(process) = s.process(Pid::from(1337)) {
420 /// println!("{:?}", process.name());
421 /// }
422 /// ```
423 pub fn process(&self, pid: Pid) -> Option<&Process> {
424 self.inner.process(pid)
425 }
426
427 /// Returns an iterator of process containing the given `name`.
428 ///
429 /// If you want only the processes with exactly the given `name`, take a look at
430 /// [`System::processes_by_exact_name`].
431 ///
432 /// **⚠️ Important ⚠️**
433 ///
434 /// On **Linux**, there are two things to know about processes' name:
435 /// 1. It is limited to 15 characters.
436 /// 2. It is not always the exe name.
437 ///
438 /// ```no_run
439 /// use sysinfo::System;
440 ///
441 /// let s = System::new_all();
442 /// for process in s.processes_by_name("htop".as_ref()) {
443 /// println!("{} {:?}", process.pid(), process.name());
444 /// }
445 /// ```
446 pub fn processes_by_name<'a: 'b, 'b>(
447 &'a self,
448 name: &'b OsStr,
449 ) -> impl Iterator<Item = &'a Process> + 'b {
450 let finder = memchr::memmem::Finder::new(name.as_encoded_bytes());
451 self.processes()
452 .values()
453 .filter(move |val: &&Process| finder.find(val.name().as_encoded_bytes()).is_some())
454 }
455
456 /// Returns an iterator of processes with exactly the given `name`.
457 ///
458 /// If you instead want the processes containing `name`, take a look at
459 /// [`System::processes_by_name`].
460 ///
461 /// **⚠️ Important ⚠️**
462 ///
463 /// On **Linux**, there are two things to know about processes' name:
464 /// 1. It is limited to 15 characters.
465 /// 2. It is not always the exe name.
466 ///
467 /// ```no_run
468 /// use sysinfo::System;
469 ///
470 /// let s = System::new_all();
471 /// for process in s.processes_by_exact_name("htop".as_ref()) {
472 /// println!("{} {:?}", process.pid(), process.name());
473 /// }
474 /// ```
475 pub fn processes_by_exact_name<'a: 'b, 'b>(
476 &'a self,
477 name: &'b OsStr,
478 ) -> impl Iterator<Item = &'a Process> + 'b {
479 self.processes()
480 .values()
481 .filter(move |val: &&Process| val.name() == name)
482 }
483
484 /// Returns "global" CPUs usage (aka the addition of all the CPUs).
485 ///
486 /// To have up-to-date information, you need to call [`System::refresh_cpu_specifics`] or
487 /// [`System::refresh_specifics`] with `cpu` enabled.
488 ///
489 /// ```no_run
490 /// use sysinfo::{CpuRefreshKind, RefreshKind, System};
491 ///
492 /// let mut s = System::new_with_specifics(
493 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
494 /// );
495 /// // Wait a bit because CPU usage is based on diff.
496 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
497 /// // Refresh CPUs again to get actual value.
498 /// s.refresh_cpu_usage();
499 /// println!("{}%", s.global_cpu_usage());
500 /// ```
501 pub fn global_cpu_usage(&self) -> f32 {
502 self.inner.global_cpu_usage()
503 }
504
505 /// Returns the list of the CPUs.
506 ///
507 /// By default, the list of CPUs is empty until you call [`System::refresh_cpu_specifics`] or
508 /// [`System::refresh_specifics`] with `cpu` enabled.
509 ///
510 /// ```no_run
511 /// use sysinfo::{CpuRefreshKind, RefreshKind, System};
512 ///
513 /// let mut s = System::new_with_specifics(
514 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
515 /// );
516 /// // Wait a bit because CPU usage is based on diff.
517 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
518 /// // Refresh CPUs again to get actual value.
519 /// s.refresh_cpu_usage();
520 /// for cpu in s.cpus() {
521 /// println!("{}%", cpu.cpu_usage());
522 /// }
523 /// ```
524 pub fn cpus(&self) -> &[Cpu] {
525 self.inner.cpus()
526 }
527
528 /// Returns the RAM size in bytes.
529 ///
530 /// ```no_run
531 /// use sysinfo::System;
532 ///
533 /// let s = System::new_all();
534 /// println!("{} bytes", s.total_memory());
535 /// ```
536 ///
537 /// On Linux, if you want to see this information with the limit of your cgroup, take a look
538 /// at [`cgroup_limits`](System::cgroup_limits).
539 pub fn total_memory(&self) -> u64 {
540 self.inner.total_memory()
541 }
542
543 /// Returns the amount of free RAM in bytes.
544 ///
545 /// Generally, "free" memory refers to unallocated memory whereas "available" memory refers to
546 /// memory that is available for (re)use.
547 ///
548 /// Side note: Windows doesn't report "free" memory so this method returns the same value
549 /// as [`available_memory`](System::available_memory).
550 ///
551 /// ```no_run
552 /// use sysinfo::System;
553 ///
554 /// let s = System::new_all();
555 /// println!("{} bytes", s.free_memory());
556 /// ```
557 pub fn free_memory(&self) -> u64 {
558 self.inner.free_memory()
559 }
560
561 /// Returns the amount of available RAM in bytes.
562 ///
563 /// Generally, "free" memory refers to unallocated memory whereas "available" memory refers to
564 /// memory that is available for (re)use.
565 ///
566 /// ⚠️ Windows and FreeBSD don't report "available" memory so [`System::free_memory`]
567 /// returns the same value as this method.
568 ///
569 /// ```no_run
570 /// use sysinfo::System;
571 ///
572 /// let s = System::new_all();
573 /// println!("{} bytes", s.available_memory());
574 /// ```
575 pub fn available_memory(&self) -> u64 {
576 self.inner.available_memory()
577 }
578
579 /// Returns the amount of used RAM in bytes.
580 ///
581 /// ```no_run
582 /// use sysinfo::System;
583 ///
584 /// let s = System::new_all();
585 /// println!("{} bytes", s.used_memory());
586 /// ```
587 pub fn used_memory(&self) -> u64 {
588 self.inner.used_memory()
589 }
590
591 /// Returns the SWAP size in bytes.
592 ///
593 /// ```no_run
594 /// use sysinfo::System;
595 ///
596 /// let s = System::new_all();
597 /// println!("{} bytes", s.total_swap());
598 /// ```
599 pub fn total_swap(&self) -> u64 {
600 self.inner.total_swap()
601 }
602
603 /// Returns the amount of free SWAP in bytes.
604 ///
605 /// ```no_run
606 /// use sysinfo::System;
607 ///
608 /// let s = System::new_all();
609 /// println!("{} bytes", s.free_swap());
610 /// ```
611 pub fn free_swap(&self) -> u64 {
612 self.inner.free_swap()
613 }
614
615 /// Returns the amount of used SWAP in bytes.
616 ///
617 /// ```no_run
618 /// use sysinfo::System;
619 ///
620 /// let s = System::new_all();
621 /// println!("{} bytes", s.used_swap());
622 /// ```
623 pub fn used_swap(&self) -> u64 {
624 self.inner.used_swap()
625 }
626
627 /// Retrieves the limits for the root cgroup (if any), otherwise it returns `None`.
628 ///
629 /// This information is computed every time the method is called.
630 ///
631 /// ⚠️ This method is only implemented for Linux. It always returns `None` for all other
632 /// systems.
633 ///
634 /// ```no_run
635 /// use sysinfo::System;
636 ///
637 /// let s = System::new_all();
638 /// println!("limits: {:?}", s.cgroup_limits());
639 /// ```
640 pub fn cgroup_limits(&self) -> Option<CGroupLimits> {
641 self.inner.cgroup_limits()
642 }
643
644 /// Returns system uptime (in seconds).
645 ///
646 /// **Important**: this information is computed every time this function is called.
647 ///
648 /// ```no_run
649 /// use sysinfo::System;
650 ///
651 /// println!("System running since {} seconds", System::uptime());
652 /// ```
653 pub fn uptime() -> u64 {
654 SystemInner::uptime()
655 }
656
657 /// Returns the time (in seconds) when the system booted since UNIX epoch.
658 ///
659 /// **Important**: this information is computed every time this function is called.
660 ///
661 /// ```no_run
662 /// use sysinfo::System;
663 ///
664 /// println!("System booted at {} seconds", System::boot_time());
665 /// ```
666 pub fn boot_time() -> u64 {
667 SystemInner::boot_time()
668 }
669
670 /// Returns the system load average value.
671 ///
672 /// **Important**: this information is computed every time this function is called.
673 ///
674 /// ⚠️ This is currently not working on **Windows**.
675 ///
676 /// ```no_run
677 /// use sysinfo::System;
678 ///
679 /// let load_avg = System::load_average();
680 /// println!(
681 /// "one minute: {}%, five minutes: {}%, fifteen minutes: {}%",
682 /// load_avg.one,
683 /// load_avg.five,
684 /// load_avg.fifteen,
685 /// );
686 /// ```
687 pub fn load_average() -> LoadAvg {
688 SystemInner::load_average()
689 }
690
691 /// Returns the system name.
692 ///
693 /// | example platform | value of `System::name()` |
694 /// |---|---|
695 /// | linux laptop | "Ubuntu" |
696 /// | android phone | "Pixel 9 Pro" |
697 /// | apple laptop | "Darwin" |
698 /// | windows server | "Windows" |
699 ///
700 /// **Important**: this information is computed every time this function is called.
701 ///
702 /// ```no_run
703 /// use sysinfo::System;
704 ///
705 /// println!("OS: {:?}", System::name());
706 /// ```
707 pub fn name() -> Option<String> {
708 SystemInner::name()
709 }
710
711 /// Returns the system's kernel version.
712 ///
713 /// | example platform | value of `System::kernel_version()` |
714 /// |---|---|
715 /// | linux laptop | "6.8.0-48-generic" |
716 /// | android phone | "6.1.84-android14-11" |
717 /// | apple laptop | "24.1.0" |
718 /// | windows server | "20348" |
719 ///
720 /// **Important**: this information is computed every time this function is called.
721 ///
722 /// ```no_run
723 /// use sysinfo::System;
724 ///
725 /// println!("kernel version: {:?}", System::kernel_version());
726 /// ```
727 pub fn kernel_version() -> Option<String> {
728 SystemInner::kernel_version()
729 }
730
731 /// Returns the system version (e.g. for macOS this will return 15.1 rather than the kernel
732 /// version).
733 ///
734 /// | example platform | value of `System::os_version()` |
735 /// |---|---|
736 /// | linux laptop | "24.04" |
737 /// | android phone | "15" |
738 /// | apple laptop | "15.1.1" |
739 /// | windows server | "10 (20348)" |
740 ///
741 /// **Important**: this information is computed every time this function is called.
742 ///
743 /// ```no_run
744 /// use sysinfo::System;
745 ///
746 /// println!("OS version: {:?}", System::os_version());
747 /// ```
748 pub fn os_version() -> Option<String> {
749 SystemInner::os_version()
750 }
751
752 /// Returns the system long os version.
753 ///
754 /// | example platform | value of `System::long_os_version()` |
755 /// |---|---|
756 /// | linux laptop | "Linux (Ubuntu 24.04)" |
757 /// | android phone | "Android 15 on Pixel 9 Pro" |
758 /// | apple laptop | "macOS 15.1.1 Sequoia" |
759 /// | windows server | "Windows Server 2022 Datacenter" |
760 ///
761 /// **Important**: this information is computed every time this function is called.
762 ///
763 /// ```no_run
764 /// use sysinfo::System;
765 ///
766 /// println!("Long OS Version: {:?}", System::long_os_version());
767 /// ```
768 pub fn long_os_version() -> Option<String> {
769 SystemInner::long_os_version()
770 }
771
772 /// Returns the distribution id as defined by os-release,
773 /// or [`std::env::consts::OS`].
774 ///
775 /// See also
776 /// - <https://www.freedesktop.org/software/systemd/man/os-release.html#ID=>
777 /// - <https://doc.rust-lang.org/std/env/consts/constant.OS.html>
778 ///
779 /// | example platform | value of `System::distribution_id()` |
780 /// |---|---|
781 /// | linux laptop | "ubuntu" |
782 /// | android phone | "android" |
783 /// | apple laptop | "macos" |
784 /// | windows server | "windows" |
785 ///
786 /// **Important**: this information is computed every time this function is called.
787 ///
788 /// ```no_run
789 /// use sysinfo::System;
790 ///
791 /// println!("Distribution ID: {:?}", System::distribution_id());
792 /// ```
793 pub fn distribution_id() -> String {
794 SystemInner::distribution_id()
795 }
796
797 /// Returns the distribution ids of operating systems that are closely
798 /// related to the local operating system in regards to packaging and
799 /// programming interfaces, for example listing one or more OS identifiers
800 /// the local OS is a derivative from.
801 ///
802 /// See also
803 /// - <https://www.freedesktop.org/software/systemd/man/latest/os-release.html#ID_LIKE=>
804 ///
805 /// | example platform | value of `System::distribution_id_like()` |
806 /// |---|---|
807 /// | android phone | [] |
808 /// | archlinux laptop | [] |
809 /// | centos server | ["rhel", "fedora"] |
810 /// | ubuntu laptop | ["debian"] |
811 /// | windows laptop | [] |
812 ///
813 /// **Important**: this information is computed every time this function is called.
814 ///
815 /// ```no_run
816 /// use sysinfo::System;
817 ///
818 /// println!("Distribution ID_LIKE: {:?}", System::distribution_id_like());
819 /// ```
820 pub fn distribution_id_like() -> Vec<String> {
821 SystemInner::distribution_id_like()
822 }
823
824 /// Provides kernel version following this string format:
825 ///
826 /// | Platform | Result |
827 /// |-|-|
828 /// | Windows | Windows OS Build 20348.2227 |
829 /// | Linux | Linux 6.12.13-200.fc41.x86_64 |
830 /// | Android | Android 612.13-200 |
831 /// | MacOS | Darwin 21.6.0 |
832 /// | FreeBSD | FreeBSD 199506 |
833 ///
834 /// If any of the information is not available, it will be replaced with "unknown".
835 ///
836 /// **Important**: this information is computed every time this function is called.
837 ///
838 /// ```no_run
839 /// use sysinfo::System;
840 ///
841 /// println!("Kernel long version: {}", System::kernel_long_version());
842 /// ```
843 ///
844 /// [distribution_id]: System::distribution_id
845 /// [kernel_version]: System::kernel_version
846 pub fn kernel_long_version() -> String {
847 let kernel_version = match System::kernel_version() {
848 None => "unknown".to_string(),
849 Some(s) => s,
850 };
851 let kernel_name = SystemInner::kernel_name().unwrap_or("Unknown");
852 if cfg!(windows) {
853 format!("{kernel_name} OS Build {kernel_version}")
854 } else {
855 format!("{kernel_name} {kernel_version}")
856 }
857 }
858
859 /// Returns the system hostname based off DNS.
860 ///
861 /// **Important**: this information is computed every time this function is called.
862 ///
863 /// ```no_run
864 /// use sysinfo::System;
865 ///
866 /// println!("Hostname: {:?}", System::host_name());
867 /// ```
868 pub fn host_name() -> Option<String> {
869 SystemInner::host_name()
870 }
871
872 /// Returns the CPU architecture (eg. x86, amd64, aarch64, ...).
873 ///
874 /// **Important**: this information is computed every time this function is called.
875 ///
876 /// ```no_run
877 /// use sysinfo::System;
878 ///
879 /// println!("CPU Architecture: {:?}", System::cpu_arch());
880 /// ```
881 pub fn cpu_arch() -> String {
882 SystemInner::cpu_arch().unwrap_or_else(|| std::env::consts::ARCH.to_owned())
883 }
884
885 /// Returns the number of physical cores on the CPU or `None` if it couldn't get it.
886 ///
887 /// In case there are multiple CPUs, it will combine the physical core count of all the CPUs.
888 ///
889 /// **Important**: this information is computed every time this function is called.
890 ///
891 /// ```no_run
892 /// use sysinfo::System;
893 ///
894 /// let s = System::new();
895 /// println!("{:?}", System::physical_core_count());
896 /// ```
897 pub fn physical_core_count() -> Option<usize> {
898 SystemInner::physical_core_count()
899 }
900
901 /// Returns the (default) maximum number of open files for a process.
902 ///
903 /// Returns `None` if it failed retrieving the information or if the current system is not
904 /// supported.
905 ///
906 /// **Important**: this information is computed every time this function is called.
907 ///
908 /// ```no_run
909 /// use sysinfo::System;
910 ///
911 /// println!("Max open files: {:?}", System::open_files_limit());
912 /// ```
913 pub fn open_files_limit() -> Option<usize> {
914 SystemInner::open_files_limit()
915 }
916}
917
918/// This type allows to retrieve motherboard-related information.
919///
920/// ⚠️ Not implemented on NetBSD.
921///
922/// ```
923/// use sysinfo::Motherboard;
924///
925/// if let Some(m) = Motherboard::new() {
926/// println!("{m:?}");
927/// }
928/// ```
929pub struct Motherboard {
930 pub(crate) inner: MotherboardInner,
931}
932
933impl Motherboard {
934 /// Creates a new instance of the `Motherboard` type.
935 ///
936 /// ```
937 /// use sysinfo::Motherboard;
938 ///
939 /// if let Some(m) = Motherboard::new() {
940 /// println!("{m:?}");
941 /// }
942 /// ```
943 pub fn new() -> Option<Self> {
944 Some(Self {
945 inner: MotherboardInner::new()?,
946 })
947 }
948
949 /// Returns the motherboard name.
950 ///
951 /// This corresponds to the model identifier assigned by the motherboard's
952 /// manufacturer (e.g. "20BE0061MC").
953 /// This information isn't available on ARM-based macOS systems.
954 ///
955 /// **Important**: this information is computed every time this function is called.
956 ///
957 /// ```no_run
958 /// use sysinfo::Motherboard;
959 ///
960 /// if let Some(m) = Motherboard::new() {
961 /// println!("Motherboard name: {:?}", m.name());
962 /// }
963 /// ```
964 pub fn name(&self) -> Option<String> {
965 self.inner.name()
966 }
967
968 /// Returns the motherboard vendor name.
969 ///
970 /// This corresponds to the name of the motherboard's manufacturer (e.g. "LENOVO").
971 ///
972 /// **Important**: this information is computed every time this function is called.
973 ///
974 /// ```no_run
975 /// use sysinfo::Motherboard;
976 ///
977 /// if let Some(m) = Motherboard::new() {
978 /// println!("Motherboard vendor: {:?}", m.vendor_name());
979 /// }
980 /// ```
981 pub fn vendor_name(&self) -> Option<String> {
982 self.inner.vendor_name()
983 }
984
985 /// Returns the motherboard version.
986 ///
987 /// This corresponds to the version or model number assigned by the motherboard's
988 /// manufacturer (e.g. "0B98401 Pro").
989 /// This information isn't available on ARM-based macOS systems.
990 ///
991 /// **Important**: this information is computed every time this function is called.
992 ///
993 /// ```no_run
994 /// use sysinfo::Motherboard;
995 ///
996 /// if let Some(m) = Motherboard::new() {
997 /// println!("Motherboard version: {:?}", m.version());
998 /// }
999 /// ```
1000 pub fn version(&self) -> Option<String> {
1001 self.inner.version()
1002 }
1003
1004 /// Returns the motherboard serial number.
1005 ///
1006 /// This corresponds to the serial number assigned by the motherboard's
1007 /// manufacturer (e.g. "W1KS427111E").
1008 ///
1009 /// **Important**: this information is computed every time this function is called.
1010 ///
1011 /// ```no_run
1012 /// use sysinfo::Motherboard;
1013 ///
1014 /// if let Some(m) = Motherboard::new() {
1015 /// println!("Motherboard serial number: {:?}", m.serial_number());
1016 /// }
1017 /// ```
1018 pub fn serial_number(&self) -> Option<String> {
1019 self.inner.serial_number()
1020 }
1021
1022 /// Returns the motherboard asset tag.
1023 ///
1024 /// This corresponds to the identifier assigned by the motherboard's
1025 /// manufacturer to track the physical device for inventory purposes.
1026 ///
1027 /// **Important**: this information is computed every time this function is called.
1028 ///
1029 /// ⚠️ Not supported on macOS/iOS.
1030 ///
1031 /// ```no_run
1032 /// use sysinfo::Motherboard;
1033 ///
1034 /// if let Some(m) = Motherboard::new() {
1035 /// println!("Motherboard asset tag: {:?}", m.asset_tag());
1036 /// }
1037 /// ```
1038 pub fn asset_tag(&self) -> Option<String> {
1039 self.inner.asset_tag()
1040 }
1041}
1042
1043/// This type allows to retrieve product-related information.
1044///
1045/// ⚠️ Not implemented on NetBSD.
1046///
1047/// ```
1048/// use sysinfo::Product;
1049///
1050/// println!("{:?}", Product);
1051/// ```
1052pub struct Product;
1053
1054impl Product {
1055 /// Returns the product name.
1056 ///
1057 /// This corresponds to the product name assigned by the hardware
1058 /// manufacturer (e.g. "20AN").
1059 ///
1060 /// **Important**: this information is computed every time this function is called.
1061 ///
1062 /// ```no_run
1063 /// use sysinfo::Product;
1064 ///
1065 /// println!("Product name: {:?}", Product::name());
1066 /// ```
1067 pub fn name() -> Option<String> {
1068 ProductInner::name()
1069 }
1070
1071 /// Returns the product family identifier.
1072 ///
1073 /// This corresponds to the product family assigned by the hardware
1074 /// manufacturer (e.g. "T440p").
1075 ///
1076 /// **Important**: this information is computed every time this function is called.
1077 ///
1078 /// ```no_run
1079 /// use sysinfo::Product;
1080 ///
1081 /// println!("Product family: {:?}", Product::family());
1082 /// ```
1083 pub fn family() -> Option<String> {
1084 ProductInner::family()
1085 }
1086
1087 /// Returns the product serial number.
1088 ///
1089 /// This corresponds to the serial identifier assigned by the hardware
1090 /// manufacturer (e.g. "W1KS427111E").
1091 ///
1092 /// **Important**: this information is computed every time this function is called.
1093 ///
1094 /// ```no_run
1095 /// use sysinfo::Product;
1096 ///
1097 /// println!("Product serial: {:?}", Product::serial_number());
1098 /// ```
1099 pub fn serial_number() -> Option<String> {
1100 ProductInner::serial_number()
1101 }
1102
1103 /// Returns the product Stock Keeping Unit (SKU).
1104 ///
1105 /// This corresponds to the Stock Keeping Unit assigned by the hardware
1106 /// manufacturer (e.g. "LENOVO_MT_20AN") which identifies a specific
1107 /// model or configuration.
1108 ///
1109 /// **Important**: this information is computed every time this function is called.
1110 ///
1111 /// ⚠️ Not supported on macOS/iOS.
1112 ///
1113 /// ```no_run
1114 /// use sysinfo::Product;
1115 ///
1116 /// println!("Product sku: {:?}", Product::stock_keeping_unit());
1117 /// ```
1118 #[doc(alias = "sku")]
1119 pub fn stock_keeping_unit() -> Option<String> {
1120 ProductInner::stock_keeping_unit()
1121 }
1122
1123 /// Returns the product UUID.
1124 ///
1125 /// This corresponds to the unique identifier assigned by the hardware
1126 /// manufacturer (e.g. "407488fe-960a-43b5-a265-8fd0e9200b8f") which uniquely
1127 /// identifies the physical system.
1128 ///
1129 /// **Important**: this information is computed every time this function is called.
1130 ///
1131 /// ```no_run
1132 /// use sysinfo::Product;
1133 ///
1134 /// println!("Product UUID: {:?}", Product::uuid());
1135 /// ```
1136 pub fn uuid() -> Option<String> {
1137 ProductInner::uuid()
1138 }
1139
1140 /// Returns the product version.
1141 ///
1142 /// This corresponds to the version assigned by the hardware
1143 /// manufacturer (e.g. "Lenovo ThinkPad T440p") which identifies
1144 /// the specific version or revision of the product.
1145 ///
1146 /// **Important**: this information is computed every time this function is called.
1147 ///
1148 /// ```no_run
1149 /// use sysinfo::Product;
1150 ///
1151 /// println!("Product version: {:?}", Product::version());
1152 /// ```
1153 pub fn version() -> Option<String> {
1154 ProductInner::version()
1155 }
1156
1157 /// Returns the product vendor name.
1158 ///
1159 /// This corresponds to the vendor name assigned by the hardware
1160 /// manufacturer (e.g. "LENOVO").
1161 ///
1162 /// **Important**: this information is computed every time this function is called.
1163 ///
1164 /// ```no_run
1165 /// use sysinfo::Product;
1166 ///
1167 /// println!("Vendor name: {:?}", Product::vendor_name());
1168 /// ```
1169 pub fn vendor_name() -> Option<String> {
1170 ProductInner::vendor_name()
1171 }
1172}
1173
1174/// A struct representing system load average value.
1175///
1176/// It is returned by [`System::load_average`][crate::System::load_average].
1177///
1178/// ```no_run
1179/// use sysinfo::System;
1180///
1181/// let load_avg = System::load_average();
1182/// println!(
1183/// "one minute: {}%, five minutes: {}%, fifteen minutes: {}%",
1184/// load_avg.one,
1185/// load_avg.five,
1186/// load_avg.fifteen,
1187/// );
1188/// ```
1189#[repr(C)]
1190#[derive(Default, Debug, Clone)]
1191pub struct LoadAvg {
1192 /// Average load within one minute.
1193 pub one: f64,
1194 /// Average load within five minutes.
1195 pub five: f64,
1196 /// Average load within fifteen minutes.
1197 pub fifteen: f64,
1198}
1199
1200/// An enum representing signals on UNIX-like systems.
1201///
1202/// On non-unix systems, this enum is mostly useless and is only there to keep coherency between
1203/// the different OSes.
1204///
1205/// If you want the list of the supported signals on the current system, use
1206/// [`SUPPORTED_SIGNALS`][crate::SUPPORTED_SIGNALS].
1207#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
1208#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
1209pub enum Signal {
1210 /// Hangup detected on controlling terminal or death of controlling process.
1211 Hangup,
1212 /// Interrupt from keyboard.
1213 Interrupt,
1214 /// Quit from keyboard.
1215 Quit,
1216 /// Illegal instruction.
1217 Illegal,
1218 /// Trace/breakpoint trap.
1219 Trap,
1220 /// Abort signal from C abort function.
1221 Abort,
1222 /// IOT trap. A synonym for SIGABRT.
1223 IOT,
1224 /// Bus error (bad memory access).
1225 Bus,
1226 /// Floating point exception.
1227 FloatingPointException,
1228 /// Kill signal.
1229 Kill,
1230 /// User-defined signal 1.
1231 User1,
1232 /// Invalid memory reference.
1233 Segv,
1234 /// User-defined signal 2.
1235 User2,
1236 /// Broken pipe: write to pipe with no readers.
1237 Pipe,
1238 /// Timer signal from C alarm function.
1239 Alarm,
1240 /// Termination signal.
1241 Term,
1242 /// Child stopped or terminated.
1243 Child,
1244 /// Continue if stopped.
1245 Continue,
1246 /// Stop process.
1247 Stop,
1248 /// Stop typed at terminal.
1249 TSTP,
1250 /// Terminal input for background process.
1251 TTIN,
1252 /// Terminal output for background process.
1253 TTOU,
1254 /// Urgent condition on socket.
1255 Urgent,
1256 /// CPU time limit exceeded.
1257 XCPU,
1258 /// File size limit exceeded.
1259 XFSZ,
1260 /// Virtual alarm clock.
1261 VirtualAlarm,
1262 /// Profiling time expired.
1263 Profiling,
1264 /// Windows resize signal.
1265 Winch,
1266 /// I/O now possible.
1267 IO,
1268 /// Pollable event (Sys V). Synonym for IO
1269 Poll,
1270 /// Power failure (System V).
1271 ///
1272 /// Doesn't exist on apple systems so will be ignored.
1273 Power,
1274 /// Bad argument to routine (SVr4).
1275 Sys,
1276}
1277
1278impl std::fmt::Display for Signal {
1279 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1280 let s = match *self {
1281 Self::Hangup => "Hangup",
1282 Self::Interrupt => "Interrupt",
1283 Self::Quit => "Quit",
1284 Self::Illegal => "Illegal",
1285 Self::Trap => "Trap",
1286 Self::Abort => "Abort",
1287 Self::IOT => "IOT",
1288 Self::Bus => "Bus",
1289 Self::FloatingPointException => "FloatingPointException",
1290 Self::Kill => "Kill",
1291 Self::User1 => "User1",
1292 Self::Segv => "Segv",
1293 Self::User2 => "User2",
1294 Self::Pipe => "Pipe",
1295 Self::Alarm => "Alarm",
1296 Self::Term => "Term",
1297 Self::Child => "Child",
1298 Self::Continue => "Continue",
1299 Self::Stop => "Stop",
1300 Self::TSTP => "TSTP",
1301 Self::TTIN => "TTIN",
1302 Self::TTOU => "TTOU",
1303 Self::Urgent => "Urgent",
1304 Self::XCPU => "XCPU",
1305 Self::XFSZ => "XFSZ",
1306 Self::VirtualAlarm => "VirtualAlarm",
1307 Self::Profiling => "Profiling",
1308 Self::Winch => "Winch",
1309 Self::IO => "IO",
1310 Self::Poll => "Poll",
1311 Self::Power => "Power",
1312 Self::Sys => "Sys",
1313 };
1314 f.write_str(s)
1315 }
1316}
1317
1318/// Contains memory limits for a cgroup.
1319#[derive(Default, Debug, Clone)]
1320pub struct CGroupLimits {
1321 /// Total memory (in bytes) for the cgroup.
1322 pub total_memory: u64,
1323 /// Free memory (in bytes) for the cgroup.
1324 pub free_memory: u64,
1325 /// Free swap (in bytes) for the cgroup.
1326 pub free_swap: u64,
1327 /// Resident Set Size (RSS) (in bytes) for the cgroup.
1328 pub rss: u64,
1329}
1330
1331/// Enum describing the different status of a process.
1332#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
1333#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
1334pub enum ProcessStatus {
1335 /// ## Linux
1336 ///
1337 /// Idle kernel thread.
1338 ///
1339 /// ## macOs/FreeBSD
1340 ///
1341 /// Process being created by fork.
1342 ///
1343 /// ## Other OS
1344 ///
1345 /// Not available.
1346 Idle,
1347 /// Running.
1348 Run,
1349 /// ## Linux
1350 ///
1351 /// Sleeping in an interruptible waiting.
1352 ///
1353 /// ## macOS/FreeBSD
1354 ///
1355 /// Sleeping on an address.
1356 ///
1357 /// ## Other OS
1358 ///
1359 /// Not available.
1360 Sleep,
1361 /// ## Linux
1362 ///
1363 /// Stopped (on a signal) or (before Linux 2.6.33) trace stopped.
1364 ///
1365 /// ## macOS/FreeBSD
1366 ///
1367 /// Process debugging or suspension.
1368 ///
1369 /// ## Other OS
1370 ///
1371 /// Not available.
1372 Stop,
1373 /// ## Linux/FreeBSD/macOS
1374 ///
1375 /// Zombie process. Terminated but not reaped by its parent.
1376 ///
1377 /// ## Other OS
1378 ///
1379 /// Not available.
1380 Zombie,
1381 /// ## Linux
1382 ///
1383 /// Tracing stop (Linux 2.6.33 onward). Stopped by debugger during the tracing.
1384 ///
1385 /// ## NetBSD
1386 ///
1387 /// The process is being traced or debugged.
1388 ///
1389 /// ## Other OS
1390 ///
1391 /// Not available.
1392 Tracing,
1393 /// ## Linux
1394 ///
1395 /// Dead/uninterruptible sleep (usually IO).
1396 ///
1397 /// ## FreeBSD
1398 ///
1399 /// A process should never end up in this state.
1400 ///
1401 /// ## Other OS
1402 ///
1403 /// Not available.
1404 Dead,
1405 /// ## Linux
1406 ///
1407 /// Wakekill (Linux 2.6.33 to 3.13 only).
1408 ///
1409 /// ## Other OS
1410 ///
1411 /// Not available.
1412 Wakekill,
1413 /// ## Linux
1414 ///
1415 /// Waking (Linux 2.6.33 to 3.13 only).
1416 ///
1417 /// ## Other OS
1418 ///
1419 /// Not available.
1420 Waking,
1421 /// ## Linux
1422 ///
1423 /// Parked (Linux 3.9 to 3.13 only).
1424 ///
1425 /// ## macOS
1426 ///
1427 /// Halted at a clean point.
1428 ///
1429 /// ## Other OS
1430 ///
1431 /// Not available.
1432 Parked,
1433 /// ## FreeBSD
1434 ///
1435 /// Blocked on a lock.
1436 ///
1437 /// ## Other OS
1438 ///
1439 /// Not available.
1440 LockBlocked,
1441 /// ## Linux
1442 ///
1443 /// Waiting in uninterruptible disk sleep.
1444 ///
1445 /// ## Other OS
1446 ///
1447 /// Not available.
1448 UninterruptibleDiskSleep,
1449 /// ## NetBSD
1450 ///
1451 /// Suspended process.
1452 ///
1453 /// ## Other OS
1454 ///
1455 /// Not available.
1456 Suspended,
1457 /// Unknown.
1458 Unknown(u32),
1459}
1460
1461/// Enum describing the different kind of threads.
1462#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1463#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
1464pub enum ThreadKind {
1465 /// Kernel thread.
1466 Kernel,
1467 /// User thread.
1468 Userland,
1469}
1470
1471/// Enum describing possible [`Process::kill_and_wait`] errors.
1472#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1473#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
1474pub enum KillError {
1475 /// This signal doesn't exist on this platform.
1476 SignalDoesNotExist,
1477 /// The signal failed to be sent to the target process.
1478 FailedToSendSignal,
1479}
1480
1481impl core::fmt::Display for KillError {
1482 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1483 match self {
1484 Self::SignalDoesNotExist => f.write_str("signal does not exist"),
1485 Self::FailedToSendSignal => f.write_str("failed to send signal"),
1486 }
1487 }
1488}
1489
1490impl core::error::Error for KillError {}
1491
1492/// Struct containing information of a process.
1493///
1494/// ## iOS
1495///
1496/// This information cannot be retrieved on iOS due to sandboxing.
1497///
1498/// ## Apple app store
1499///
1500/// If you are building a macOS Apple app store, it won't be able
1501/// to retrieve this information.
1502///
1503/// ```no_run
1504/// use sysinfo::{Pid, System};
1505///
1506/// let s = System::new_all();
1507/// if let Some(process) = s.process(Pid::from(1337)) {
1508/// println!("{:?}", process.name());
1509/// }
1510/// ```
1511pub struct Process {
1512 pub(crate) inner: ProcessInner,
1513}
1514
1515impl Process {
1516 /// Sends [`Signal::Kill`] to the process (which is the only signal supported on all supported
1517 /// platforms by this crate).
1518 ///
1519 /// Returns `true` if the signal was sent successfully. If you want to wait for this process
1520 /// to end, you can use [`Process::wait`] or directly [`Process::kill_and_wait`].
1521 ///
1522 /// ⚠️ Even if this function returns `true`, it doesn't necessarily mean that the process will
1523 /// be killed. It just means that the signal was sent successfully.
1524 ///
1525 /// ⚠️ Please note that some processes might not be "killable", like if they run with higher
1526 /// levels than the current process for example.
1527 ///
1528 /// If you want to use another signal, take a look at [`Process::kill_with`].
1529 ///
1530 /// To get the list of the supported signals on this system, use
1531 /// [`SUPPORTED_SIGNALS`][crate::SUPPORTED_SIGNALS].
1532 ///
1533 /// ```no_run
1534 /// use sysinfo::{Pid, System};
1535 ///
1536 /// let s = System::new_all();
1537 /// if let Some(process) = s.process(Pid::from(1337)) {
1538 /// process.kill();
1539 /// }
1540 /// ```
1541 pub fn kill(&self) -> bool {
1542 self.kill_with(Signal::Kill).unwrap_or(false)
1543 }
1544
1545 /// Sends the given `signal` to the process. If the signal doesn't exist on this platform,
1546 /// it'll do nothing and will return `None`. Otherwise it'll return `Some(bool)`. The boolean
1547 /// value will depend on whether or not the signal was sent successfully.
1548 ///
1549 /// If you just want to kill the process, use [`Process::kill`] directly. If you want to wait
1550 /// for this process to end, you can use [`Process::wait`] or [`Process::kill_with_and_wait`].
1551 ///
1552 /// ⚠️ Please note that some processes might not be "killable", like if they run with higher
1553 /// levels than the current process for example.
1554 ///
1555 /// To get the list of the supported signals on this system, use
1556 /// [`SUPPORTED_SIGNALS`][crate::SUPPORTED_SIGNALS].
1557 ///
1558 /// ```no_run
1559 /// use sysinfo::{Pid, Signal, System};
1560 ///
1561 /// let s = System::new_all();
1562 /// if let Some(process) = s.process(Pid::from(1337)) {
1563 /// if process.kill_with(Signal::Kill).is_none() {
1564 /// println!("This signal isn't supported on this platform");
1565 /// }
1566 /// }
1567 /// ```
1568 pub fn kill_with(&self, signal: Signal) -> Option<bool> {
1569 self.inner.kill_with(signal)
1570 }
1571
1572 /// Sends [`Signal::Kill`] to the process then waits for its termination.
1573 ///
1574 /// Internally, this method is calling [`Process::kill`] then [`Process::wait`].
1575 ///
1576 /// ⚠️ Please note that some processes might not be "killable", like if they run with higher
1577 /// levels than the current process for example. In this case, this method could enter an
1578 /// infinite loop.
1579 ///
1580 /// ```no_run
1581 /// use sysinfo::{Pid, System};
1582 ///
1583 /// let s = System::new_all();
1584 /// if let Some(process) = s.process(Pid::from(1337)) {
1585 /// if let Err(error) = process.kill_and_wait() {
1586 /// println!("`kill_and_wait` failed: {error:?}");
1587 /// }
1588 /// }
1589 /// ```
1590 pub fn kill_and_wait(&self) -> Result<Option<ExitStatus>, KillError> {
1591 self.kill_with_and_wait(Signal::Kill)
1592 }
1593
1594 /// Sends the given `signal` to the process.then waits for its termination.
1595 ///
1596 /// Internally, this method is calling [`Process::kill_with`] then [`Process::wait`].
1597 ///
1598 /// ⚠️ Please note that some processes might not be "killable", like if they run with higher
1599 /// levels than the current process for example. In this case, this method could enter an
1600 /// infinite loop.
1601 ///
1602 /// To get the list of the supported signals on this system, use
1603 /// [`SUPPORTED_SIGNALS`][crate::SUPPORTED_SIGNALS].
1604 ///
1605 /// ```no_run
1606 /// use sysinfo::{Pid, System};
1607 ///
1608 /// let s = System::new_all();
1609 /// if let Some(process) = s.process(Pid::from(1337)) {
1610 /// if let Err(error) = process.kill_and_wait() {
1611 /// println!("`kill_and_wait` failed: {error:?}");
1612 /// }
1613 /// }
1614 /// ```
1615 pub fn kill_with_and_wait(&self, signal: Signal) -> Result<Option<ExitStatus>, KillError> {
1616 match self.inner.kill_with(signal) {
1617 Some(sent) => {
1618 if !sent {
1619 return Err(KillError::FailedToSendSignal);
1620 }
1621 }
1622 None => return Err(KillError::SignalDoesNotExist),
1623 }
1624
1625 Ok(self.inner.wait())
1626 }
1627
1628 /// Waits for process termination and returns its [`ExitStatus`] if it could be retrieved,
1629 /// returns `None` otherwise. It means that as long as the process is alive, this method will
1630 /// not return.
1631 ///
1632 /// ⚠️ On **macOS** and **FreeBSD**, if the process died and a new one took its PID, unless
1633 /// you refreshed, it will wait for the new process to end.
1634 ///
1635 /// On **Windows**, as long as we have a (internal) handle, we can always retrieve the exit
1636 /// status.
1637 ///
1638 /// On **Linux**/**Android**, we check that the start time of the PID we're waiting is the same
1639 /// as the current process'. If not it means the process died and a new one got its PID.
1640 ///
1641 /// ```no_run
1642 /// use sysinfo::{Pid, System};
1643 ///
1644 /// let mut s = System::new_all();
1645 ///
1646 /// if let Some(process) = s.process(Pid::from(1337)) {
1647 /// println!("Waiting for pid 1337");
1648 /// let exit_status = process.wait();
1649 /// println!("Pid 1337 exited with: {exit_status:?}");
1650 /// }
1651 /// ```
1652 pub fn wait(&self) -> Option<ExitStatus> {
1653 self.inner.wait()
1654 }
1655
1656 /// Returns the name of the process.
1657 ///
1658 /// **⚠️ Important ⚠️**
1659 ///
1660 /// On **Linux**, there are two things to know about processes' name:
1661 /// 1. It is limited to 15 characters.
1662 /// 2. It is not always the exe name.
1663 ///
1664 /// If you are looking for a specific process, unless you know what you are
1665 /// doing, in most cases it's better to use [`Process::exe`] instead (which
1666 /// can be empty sometimes!).
1667 ///
1668 /// ```no_run
1669 /// use sysinfo::{Pid, System};
1670 ///
1671 /// let s = System::new_all();
1672 /// if let Some(process) = s.process(Pid::from(1337)) {
1673 /// println!("{:?}", process.name());
1674 /// }
1675 /// ```
1676 pub fn name(&self) -> &OsStr {
1677 self.inner.name()
1678 }
1679
1680 /// Returns the command line.
1681 ///
1682 /// **⚠️ Important ⚠️**
1683 ///
1684 /// On **Windows**, you might need to use `administrator` privileges when running your program
1685 /// to have access to this information.
1686 ///
1687 /// ```no_run
1688 /// use sysinfo::{Pid, System};
1689 ///
1690 /// let s = System::new_all();
1691 /// if let Some(process) = s.process(Pid::from(1337)) {
1692 /// println!("{:?}", process.cmd());
1693 /// }
1694 /// ```
1695 pub fn cmd(&self) -> &[OsString] {
1696 self.inner.cmd()
1697 }
1698
1699 /// Returns the path to the process.
1700 ///
1701 /// ```no_run
1702 /// use sysinfo::{Pid, System};
1703 ///
1704 /// let s = System::new_all();
1705 /// if let Some(process) = s.process(Pid::from(1337)) {
1706 /// println!("{:?}", process.exe());
1707 /// }
1708 /// ```
1709 ///
1710 /// ### Implementation notes
1711 ///
1712 /// On Linux, this method will return an empty path if there
1713 /// was an error trying to read `/proc/<pid>/exe`. This can
1714 /// happen, for example, if the permission levels or UID namespaces
1715 /// between the caller and target processes are different.
1716 ///
1717 /// It is also the case that `cmd[0]` is _not_ usually a correct
1718 /// replacement for this.
1719 /// A process [may change its `cmd[0]` value](https://man7.org/linux/man-pages/man5/proc.5.html)
1720 /// freely, making this an untrustworthy source of information.
1721 pub fn exe(&self) -> Option<&Path> {
1722 self.inner.exe()
1723 }
1724
1725 /// Returns the PID of the process.
1726 ///
1727 /// ```no_run
1728 /// use sysinfo::{Pid, System};
1729 ///
1730 /// let s = System::new_all();
1731 /// if let Some(process) = s.process(Pid::from(1337)) {
1732 /// println!("{}", process.pid());
1733 /// }
1734 /// ```
1735 pub fn pid(&self) -> Pid {
1736 self.inner.pid()
1737 }
1738
1739 /// Retrieves the limits for the process cgroup (if any), otherwise it returns `None`.
1740 ///
1741 /// This information is computed every time the method is called.
1742 ///
1743 /// ⚠️ This method is only implemented for Linux. It always returns `None` for all other
1744 /// systems.
1745 ///
1746 /// ```no_run
1747 /// use sysinfo::{Pid, System};
1748 ///
1749 /// let s = System::new_all();
1750 /// if let Some(process) = s.process(Pid::from(1337)) {
1751 /// println!("limits: {:?}", process.cgroup_limits());
1752 /// }
1753 /// ```
1754 pub fn cgroup_limits(&self) -> Option<CGroupLimits> {
1755 self.inner.cgroup_limits()
1756 }
1757
1758 /// Returns the environment variables of the process.
1759 ///
1760 /// ```no_run
1761 /// use sysinfo::{Pid, System};
1762 ///
1763 /// let s = System::new_all();
1764 /// if let Some(process) = s.process(Pid::from(1337)) {
1765 /// println!("{:?}", process.environ());
1766 /// }
1767 /// ```
1768 pub fn environ(&self) -> &[OsString] {
1769 self.inner.environ()
1770 }
1771
1772 /// Returns the current working directory.
1773 ///
1774 /// ```no_run
1775 /// use sysinfo::{Pid, System};
1776 ///
1777 /// let s = System::new_all();
1778 /// if let Some(process) = s.process(Pid::from(1337)) {
1779 /// println!("{:?}", process.cwd());
1780 /// }
1781 /// ```
1782 pub fn cwd(&self) -> Option<&Path> {
1783 self.inner.cwd()
1784 }
1785
1786 /// Returns the path of the root directory.
1787 ///
1788 /// ⚠️ Not implemented in NetBSD.
1789 ///
1790 /// ```no_run
1791 /// use sysinfo::{Pid, System};
1792 ///
1793 /// let s = System::new_all();
1794 /// if let Some(process) = s.process(Pid::from(1337)) {
1795 /// println!("{:?}", process.root());
1796 /// }
1797 /// ```
1798 pub fn root(&self) -> Option<&Path> {
1799 self.inner.root()
1800 }
1801
1802 /// Returns the memory usage (in bytes).
1803 ///
1804 /// This method returns the [size of the resident set], that is, the amount of memory that the
1805 /// process allocated and which is currently mapped in physical RAM. It does not include memory
1806 /// that is swapped out, or, in some operating systems, that has been allocated but never used.
1807 ///
1808 /// Thus, it represents exactly the amount of physical RAM that the process is using at the
1809 /// present time, but it might not be a good indicator of the total memory that the process will
1810 /// be using over its lifetime. For that purpose, you can try and use
1811 /// [`virtual_memory`](Process::virtual_memory).
1812 ///
1813 /// ```no_run
1814 /// use sysinfo::{Pid, System};
1815 ///
1816 /// let s = System::new_all();
1817 /// if let Some(process) = s.process(Pid::from(1337)) {
1818 /// println!("{} bytes", process.memory());
1819 /// }
1820 /// ```
1821 ///
1822 /// [size of the resident set]: https://en.wikipedia.org/wiki/Resident_set_size
1823 pub fn memory(&self) -> u64 {
1824 self.inner.memory()
1825 }
1826
1827 /// Returns the virtual memory usage (in bytes).
1828 ///
1829 /// This method returns the [size of virtual memory], that is, the amount of memory that the
1830 /// process can access, whether it is currently mapped in physical RAM or not. It includes
1831 /// physical RAM, allocated but not used regions, swapped-out regions, and even memory
1832 /// associated with [memory-mapped files](https://en.wikipedia.org/wiki/Memory-mapped_file).
1833 ///
1834 /// This value has limitations though. Depending on the operating system and type of process,
1835 /// this value might be a good indicator of the total memory that the process will be using over
1836 /// its lifetime. However, for example, in the version 14 of macOS this value is in the order of
1837 /// the hundreds of gigabytes for every process, and thus not very informative. Moreover, if a
1838 /// process maps into memory a very large file, this value will increase accordingly, even if
1839 /// the process is not actively using the memory.
1840 ///
1841 /// ```no_run
1842 /// use sysinfo::{Pid, System};
1843 ///
1844 /// let s = System::new_all();
1845 /// if let Some(process) = s.process(Pid::from(1337)) {
1846 /// println!("{} bytes", process.virtual_memory());
1847 /// }
1848 /// ```
1849 ///
1850 /// [size of virtual memory]: https://en.wikipedia.org/wiki/Virtual_memory
1851 pub fn virtual_memory(&self) -> u64 {
1852 self.inner.virtual_memory()
1853 }
1854
1855 /// Returns the parent PID.
1856 ///
1857 /// ```no_run
1858 /// use sysinfo::{Pid, System};
1859 ///
1860 /// let s = System::new_all();
1861 /// if let Some(process) = s.process(Pid::from(1337)) {
1862 /// println!("{:?}", process.parent());
1863 /// }
1864 /// ```
1865 pub fn parent(&self) -> Option<Pid> {
1866 self.inner.parent()
1867 }
1868
1869 /// Returns the status of the process.
1870 ///
1871 /// ```no_run
1872 /// use sysinfo::{Pid, System};
1873 ///
1874 /// let s = System::new_all();
1875 /// if let Some(process) = s.process(Pid::from(1337)) {
1876 /// println!("{:?}", process.status());
1877 /// }
1878 /// ```
1879 pub fn status(&self) -> ProcessStatus {
1880 self.inner.status()
1881 }
1882
1883 /// Returns the time where the process was started (in seconds) from epoch.
1884 ///
1885 /// ```no_run
1886 /// use sysinfo::{Pid, System};
1887 ///
1888 /// let s = System::new_all();
1889 /// if let Some(process) = s.process(Pid::from(1337)) {
1890 /// println!("Started at {} seconds", process.start_time());
1891 /// }
1892 /// ```
1893 pub fn start_time(&self) -> u64 {
1894 self.inner.start_time()
1895 }
1896
1897 /// Returns for how much time the process has been running (in seconds).
1898 ///
1899 /// ```no_run
1900 /// use sysinfo::{Pid, System};
1901 ///
1902 /// let s = System::new_all();
1903 /// if let Some(process) = s.process(Pid::from(1337)) {
1904 /// println!("Running since {} seconds", process.run_time());
1905 /// }
1906 /// ```
1907 pub fn run_time(&self) -> u64 {
1908 self.inner.run_time()
1909 }
1910
1911 /// Returns the total CPU usage (in %). Notice that it might be bigger than
1912 /// 100 if run on a multi-core machine.
1913 ///
1914 /// If you want a value between 0% and 100%, divide the returned value by
1915 /// the number of CPUs.
1916 ///
1917 /// ⚠️ To start to have accurate CPU usage, a process needs to be refreshed
1918 /// **twice** because CPU usage computation is based on time diff (process
1919 /// time on a given time period divided by total system time on the same
1920 /// time period).
1921 ///
1922 /// ⚠️ If you want accurate CPU usage number, better leave a bit of time
1923 /// between two calls of this method (take a look at
1924 /// [`MINIMUM_CPU_UPDATE_INTERVAL`][crate::MINIMUM_CPU_UPDATE_INTERVAL] for
1925 /// more information).
1926 ///
1927 /// ```no_run
1928 /// use sysinfo::{Pid, ProcessesToUpdate, ProcessRefreshKind, System};
1929 ///
1930 /// let mut s = System::new_all();
1931 /// // Wait a bit because CPU usage is based on diff.
1932 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
1933 /// // Refresh CPU usage to get actual value.
1934 /// s.refresh_processes_specifics(
1935 /// ProcessesToUpdate::All,
1936 /// true,
1937 /// ProcessRefreshKind::nothing().with_cpu()
1938 /// );
1939 /// if let Some(process) = s.process(Pid::from(1337)) {
1940 /// println!("{}%", process.cpu_usage());
1941 /// }
1942 /// ```
1943 pub fn cpu_usage(&self) -> f32 {
1944 self.inner.cpu_usage()
1945 }
1946
1947 /// Returns the total accumulated CPU usage (in CPU-milliseconds). Note
1948 /// that it might be bigger than the total clock run time of a process if
1949 /// run on a multi-core machine.
1950 ///
1951 /// ```no_run
1952 /// use sysinfo::{Pid, System};
1953 ///
1954 /// let s = System::new_all();
1955 /// if let Some(process) = s.process(Pid::from(1337)) {
1956 /// println!("{}", process.accumulated_cpu_time());
1957 /// }
1958 /// ```
1959 pub fn accumulated_cpu_time(&self) -> u64 {
1960 self.inner.accumulated_cpu_time()
1961 }
1962
1963 /// Returns number of bytes read and written to disk.
1964 ///
1965 /// ⚠️ On Windows, this method actually returns **ALL** I/O read and
1966 /// written bytes.
1967 ///
1968 /// ⚠️ Files might be cached in memory by your OS, meaning that reading/writing them might not
1969 /// increase the `read_bytes`/`written_bytes` values. You can find more information about it
1970 /// in the `proc_pid_io` manual (`man proc_pid_io` on unix platforms).
1971 ///
1972 /// ```no_run
1973 /// use sysinfo::{Pid, System};
1974 ///
1975 /// let s = System::new_all();
1976 /// if let Some(process) = s.process(Pid::from(1337)) {
1977 /// let disk_usage = process.disk_usage();
1978 /// println!("read bytes : new/total => {}/{}",
1979 /// disk_usage.read_bytes,
1980 /// disk_usage.total_read_bytes,
1981 /// );
1982 /// println!("written bytes: new/total => {}/{}",
1983 /// disk_usage.written_bytes,
1984 /// disk_usage.total_written_bytes,
1985 /// );
1986 /// }
1987 /// ```
1988 pub fn disk_usage(&self) -> DiskUsage {
1989 self.inner.disk_usage()
1990 }
1991
1992 /// Returns the ID of the owner user of this process or `None` if this
1993 /// information couldn't be retrieved. If you want to get the [`User`] from
1994 /// it, take a look at [`Users::get_user_by_id`].
1995 ///
1996 /// [`User`]: crate::User
1997 /// [`Users::get_user_by_id`]: crate::Users::get_user_by_id
1998 ///
1999 /// ```no_run
2000 /// use sysinfo::{Pid, System};
2001 ///
2002 /// let mut s = System::new_all();
2003 ///
2004 /// if let Some(process) = s.process(Pid::from(1337)) {
2005 /// println!("User id for process 1337: {:?}", process.user_id());
2006 /// }
2007 /// ```
2008 pub fn user_id(&self) -> Option<&Uid> {
2009 self.inner.user_id()
2010 }
2011
2012 /// Returns the user ID of the effective owner of this process or `None` if
2013 /// this information couldn't be retrieved. If you want to get the [`User`]
2014 /// from it, take a look at [`Users::get_user_by_id`].
2015 ///
2016 /// If you run something with `sudo`, the real user ID of the launched
2017 /// process will be the ID of the user you are logged in as but effective
2018 /// user ID will be `0` (i-e root).
2019 ///
2020 /// ⚠️ It always returns `None` on Windows.
2021 ///
2022 /// [`User`]: crate::User
2023 /// [`Users::get_user_by_id`]: crate::Users::get_user_by_id
2024 ///
2025 /// ```no_run
2026 /// use sysinfo::{Pid, System};
2027 ///
2028 /// let mut s = System::new_all();
2029 ///
2030 /// if let Some(process) = s.process(Pid::from(1337)) {
2031 /// println!("User id for process 1337: {:?}", process.effective_user_id());
2032 /// }
2033 /// ```
2034 pub fn effective_user_id(&self) -> Option<&Uid> {
2035 self.inner.effective_user_id()
2036 }
2037
2038 /// Returns the process group ID of the process.
2039 ///
2040 /// ⚠️ It always returns `None` on Windows.
2041 ///
2042 /// ```no_run
2043 /// use sysinfo::{Pid, System};
2044 ///
2045 /// let mut s = System::new_all();
2046 ///
2047 /// if let Some(process) = s.process(Pid::from(1337)) {
2048 /// println!("Group ID for process 1337: {:?}", process.group_id());
2049 /// }
2050 /// ```
2051 pub fn group_id(&self) -> Option<Gid> {
2052 self.inner.group_id()
2053 }
2054
2055 /// Returns the effective group ID of the process.
2056 ///
2057 /// If you run something with `sudo`, the real group ID of the launched
2058 /// process will be the primary group ID you are logged in as but effective
2059 /// group ID will be `0` (i-e root).
2060 ///
2061 /// ⚠️ It always returns `None` on Windows.
2062 ///
2063 /// ```no_run
2064 /// use sysinfo::{Pid, System};
2065 ///
2066 /// let mut s = System::new_all();
2067 ///
2068 /// if let Some(process) = s.process(Pid::from(1337)) {
2069 /// println!("User id for process 1337: {:?}", process.effective_group_id());
2070 /// }
2071 /// ```
2072 pub fn effective_group_id(&self) -> Option<Gid> {
2073 self.inner.effective_group_id()
2074 }
2075
2076 /// Returns the session ID for the current process or `None` if it couldn't
2077 /// be retrieved.
2078 ///
2079 /// ⚠️ This information is computed every time this method is called.
2080 ///
2081 /// ```no_run
2082 /// use sysinfo::{Pid, System};
2083 ///
2084 /// let mut s = System::new_all();
2085 ///
2086 /// if let Some(process) = s.process(Pid::from(1337)) {
2087 /// println!("Session ID for process 1337: {:?}", process.session_id());
2088 /// }
2089 /// ```
2090 pub fn session_id(&self) -> Option<Pid> {
2091 self.inner.session_id()
2092 }
2093
2094 /// Tasks run by this process. If there are none, returns `None`.
2095 ///
2096 /// ⚠️ This method always returns `None` on other platforms than Linux.
2097 ///
2098 /// ```no_run
2099 /// use sysinfo::{Pid, System};
2100 ///
2101 /// let mut s = System::new_all();
2102 ///
2103 /// if let Some(process) = s.process(Pid::from(1337)) {
2104 /// if let Some(tasks) = process.tasks() {
2105 /// println!("Listing tasks for process {:?}", process.pid());
2106 /// for task_pid in tasks {
2107 /// if let Some(task) = s.process(*task_pid) {
2108 /// println!("Task {:?}: {:?}", task.pid(), task.name());
2109 /// }
2110 /// }
2111 /// }
2112 /// }
2113 /// ```
2114 pub fn tasks(&self) -> Option<&HashSet<Pid>> {
2115 cfg_select! {
2116 all(
2117 any(target_os = "linux", target_os = "android"),
2118 not(feature = "unknown-ci")
2119 ) => {
2120 self.inner.tasks.as_ref()
2121 }
2122 _ => {
2123 None
2124 }
2125 }
2126 }
2127
2128 /// If the process is a thread, it'll return `Some` with the kind of thread it is. Returns
2129 /// `None` otherwise.
2130 ///
2131 /// ⚠️ This method always returns `None` on other platforms than Linux.
2132 ///
2133 /// ```no_run
2134 /// use sysinfo::System;
2135 ///
2136 /// let s = System::new_all();
2137 ///
2138 /// for (_, process) in s.processes() {
2139 /// if let Some(thread_kind) = process.thread_kind() {
2140 /// println!("Process {:?} is a {thread_kind:?} thread", process.pid());
2141 /// }
2142 /// }
2143 /// ```
2144 pub fn thread_kind(&self) -> Option<ThreadKind> {
2145 cfg_select! {
2146 all(
2147 any(target_os = "linux", target_os = "android"),
2148 not(feature = "unknown-ci")
2149 ) => self.inner.thread_kind(),
2150 _ => None,
2151 }
2152 }
2153
2154 /// Returns `true` if the process doesn't exist anymore but was not yet removed from
2155 /// the processes list because the `remove_dead_processes` argument was set to `false`
2156 /// in methods like [`System::refresh_processes`].
2157 ///
2158 /// ```no_run
2159 /// use sysinfo::{ProcessesToUpdate, System};
2160 ///
2161 /// let mut s = System::new_all();
2162 /// // We set the `remove_dead_processes` to `false`.
2163 /// s.refresh_processes(ProcessesToUpdate::All, false);
2164 ///
2165 /// for (_, process) in s.processes() {
2166 /// println!(
2167 /// "Process {:?} {}",
2168 /// process.pid(),
2169 /// if process.exists() { "exists" } else { "doesn't exist" },
2170 /// );
2171 /// }
2172 /// ```
2173 pub fn exists(&self) -> bool {
2174 self.inner.exists()
2175 }
2176
2177 /// Returns the number of open files in the current process.
2178 ///
2179 /// Returns `None` if it failed retrieving the information or if the current system is not
2180 /// supported.
2181 ///
2182 /// **Important**: this information is computed every time this function is called.
2183 ///
2184 /// ⚠️ Not implemented on NetBSD.
2185 ///
2186 /// ```no_run
2187 /// use sysinfo::System;
2188 ///
2189 /// let s = System::new_all();
2190 ///
2191 /// for (_, process) in s.processes() {
2192 /// println!(
2193 /// "Process {:?} {:?}",
2194 /// process.pid(),
2195 /// process.open_files(),
2196 /// );
2197 /// }
2198 /// ```
2199 pub fn open_files(&self) -> Option<usize> {
2200 self.inner.open_files()
2201 }
2202
2203 /// Returns the maximum number of open files for the current process.
2204 ///
2205 /// Returns `None` if it failed retrieving the information or if the current system is not
2206 /// supported.
2207 ///
2208 /// **Important**: this information is computed every time this function is called.
2209 ///
2210 /// ```no_run
2211 /// use sysinfo::System;
2212 ///
2213 /// let s = System::new_all();
2214 ///
2215 /// for (_, process) in s.processes() {
2216 /// println!(
2217 /// "Process {:?} {:?}",
2218 /// process.pid(),
2219 /// process.open_files_limit(),
2220 /// );
2221 /// }
2222 /// ```
2223 pub fn open_files_limit(&self) -> Option<usize> {
2224 self.inner.open_files_limit()
2225 }
2226}
2227
2228macro_rules! pid_decl {
2229 ($typ:ty) => {
2230 #[doc = include_str!("../../md_doc/pid.md")]
2231 #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
2232 #[repr(transparent)]
2233 pub struct Pid(pub(crate) $typ);
2234
2235 impl From<usize> for Pid {
2236 fn from(v: usize) -> Self {
2237 Self(v as _)
2238 }
2239 }
2240 impl From<Pid> for usize {
2241 fn from(v: Pid) -> Self {
2242 v.0 as _
2243 }
2244 }
2245 impl FromStr for Pid {
2246 type Err = <$typ as FromStr>::Err;
2247 fn from_str(s: &str) -> Result<Self, Self::Err> {
2248 Ok(Self(<$typ>::from_str(s)?))
2249 }
2250 }
2251 impl fmt::Display for Pid {
2252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2253 write!(f, "{}", self.0)
2254 }
2255 }
2256 impl Pid {
2257 /// Allows to convert [`Pid`][crate::Pid] into [`u32`].
2258 ///
2259 /// ```
2260 /// use sysinfo::Pid;
2261 ///
2262 /// let pid = Pid::from_u32(0);
2263 /// let value: u32 = pid.as_u32();
2264 /// ```
2265 pub fn as_u32(self) -> u32 {
2266 self.0 as _
2267 }
2268 /// Allows to convert a [`u32`] into [`Pid`][crate::Pid].
2269 ///
2270 /// ```
2271 /// use sysinfo::Pid;
2272 ///
2273 /// let pid = Pid::from_u32(0);
2274 /// ```
2275 pub fn from_u32(v: u32) -> Self {
2276 Self(v as _)
2277 }
2278 }
2279 };
2280}
2281
2282cfg_select! {
2283 all(
2284 not(feature = "unknown-ci"),
2285 any(
2286 target_os = "freebsd",
2287 target_os = "netbsd",
2288 target_os = "linux",
2289 target_os = "android",
2290 target_os = "macos",
2291 target_os = "ios",
2292 )
2293 ) => {
2294 use libc::pid_t;
2295
2296 pid_decl!(pid_t);
2297 }
2298 _ => {
2299 pid_decl!(usize);
2300 }
2301}
2302
2303/// This enum allows you to specify when you want the related information to be updated.
2304///
2305/// For example if you only want the [`Process::exe()`] information to be refreshed only if it's not
2306/// already set:
2307///
2308/// ```no_run
2309/// use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System, UpdateKind};
2310///
2311/// let mut system = System::new();
2312/// system.refresh_processes_specifics(
2313/// ProcessesToUpdate::All,
2314/// true,
2315/// ProcessRefreshKind::nothing().with_exe(UpdateKind::OnlyIfNotSet),
2316/// );
2317/// ```
2318#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2319pub enum UpdateKind {
2320 /// Never update the related information.
2321 #[default]
2322 Never,
2323 /// Always update the related information.
2324 Always,
2325 /// Only update the related information if it was not already set at least once.
2326 OnlyIfNotSet,
2327}
2328
2329impl UpdateKind {
2330 /// If `self` is `OnlyIfNotSet`, `f` is called and its returned value is returned.
2331 #[allow(dead_code)] // Needed for unsupported targets.
2332 pub(crate) fn needs_update(self, f: impl Fn() -> bool) -> bool {
2333 match self {
2334 Self::Never => false,
2335 Self::Always => true,
2336 Self::OnlyIfNotSet => f(),
2337 }
2338 }
2339}
2340
2341/// This enum allows you to specify if you want all processes to be updated or just
2342/// some of them.
2343///
2344/// Example:
2345///
2346/// ```no_run
2347/// use sysinfo::{ProcessesToUpdate, System, get_current_pid};
2348///
2349/// let mut system = System::new();
2350/// // To refresh all processes:
2351/// system.refresh_processes(ProcessesToUpdate::All, true);
2352///
2353/// // To refresh only the current one:
2354/// system.refresh_processes(
2355/// ProcessesToUpdate::Some(&[get_current_pid().unwrap()]),
2356/// true,
2357/// );
2358/// ```
2359#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2360pub enum ProcessesToUpdate<'a> {
2361 /// To refresh all processes.
2362 All,
2363 /// To refresh only the processes with the listed [`Pid`].
2364 ///
2365 /// [`Pid`]: crate::Pid
2366 Some(&'a [Pid]),
2367}
2368
2369/// Used to determine what you want to refresh specifically on the [`Process`] type.
2370///
2371/// When all refresh are ruled out, a [`Process`] will still retrieve the following information:
2372/// * Process ID ([`Pid`])
2373/// * Parent process ID (on Windows it never changes though)
2374/// * Process name
2375/// * Start time
2376///
2377/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2378/// the information won't be retrieved if the information is accessible without needing
2379/// extra computation.
2380///
2381/// ⚠️ ** Linux Specific ** ⚠️
2382/// When using `ProcessRefreshKind::everything()`, in linux we will fetch all relevant
2383/// information from `/proc/<pid>/` as well as all the information from `/proc/<pid>/task/<tid>/`
2384/// folders. This makes the refresh mechanism a lot slower depending on the number of tasks
2385/// each process has.
2386///
2387/// If you don't care about tasks information, use `ProcessRefreshKind::everything().without_tasks()`
2388/// as much as possible.
2389///
2390/// ```
2391/// use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System};
2392///
2393/// let mut system = System::new();
2394///
2395/// // We don't want to update the CPU information.
2396/// system.refresh_processes_specifics(
2397/// ProcessesToUpdate::All,
2398/// true,
2399/// ProcessRefreshKind::everything().without_cpu(),
2400/// );
2401///
2402/// for (_, proc_) in system.processes() {
2403/// // We use a `==` comparison on float only because we know it's set to 0 here.
2404/// assert_eq!(proc_.cpu_usage(), 0.);
2405/// }
2406/// ```
2407///
2408/// [`Process`]: crate::Process
2409#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2410pub struct ProcessRefreshKind {
2411 cpu: bool,
2412 disk_usage: bool,
2413 memory: bool,
2414 user: UpdateKind,
2415 cwd: UpdateKind,
2416 root: UpdateKind,
2417 environ: UpdateKind,
2418 cmd: UpdateKind,
2419 exe: UpdateKind,
2420 tasks: bool,
2421}
2422
2423/// Creates a new `ProcessRefreshKind` with every refresh set to `false`, except for `tasks`.
2424/// By default, we want to list all processes and tasks are considered processes on their own
2425/// in linux so we still fetch them by default. However, the processes information are not
2426/// refreshed.
2427impl Default for ProcessRefreshKind {
2428 fn default() -> Self {
2429 Self {
2430 cpu: false,
2431 disk_usage: false,
2432 memory: false,
2433 user: UpdateKind::default(),
2434 cwd: UpdateKind::default(),
2435 root: UpdateKind::default(),
2436 environ: UpdateKind::default(),
2437 cmd: UpdateKind::default(),
2438 exe: UpdateKind::default(),
2439 tasks: true, // Process by default includes all tasks.
2440 }
2441 }
2442}
2443
2444impl ProcessRefreshKind {
2445 /// Creates a new `ProcessRefreshKind` with every refresh set to `false`, except for `tasks`.
2446 /// By default, we want to list all processes and tasks are considered processes on their own
2447 /// in linux so we still fetch them by default. However, the processes information are not
2448 /// refreshed.
2449 /// ```
2450 /// use sysinfo::{ProcessRefreshKind, UpdateKind};
2451 ///
2452 /// let r = ProcessRefreshKind::nothing();
2453 ///
2454 /// assert_eq!(r.cpu(), false);
2455 /// assert_eq!(r.user(), UpdateKind::Never);
2456 /// ```
2457 pub fn nothing() -> Self {
2458 Self::default()
2459 }
2460
2461 /// Creates a new `ProcessRefreshKind` with every refresh set to `true` or
2462 /// [`UpdateKind::OnlyIfNotSet`].
2463 ///
2464 /// ```
2465 /// use sysinfo::{ProcessRefreshKind, UpdateKind};
2466 ///
2467 /// let r = ProcessRefreshKind::everything();
2468 ///
2469 /// assert_eq!(r.cpu(), true);
2470 /// assert_eq!(r.user(), UpdateKind::OnlyIfNotSet);
2471 /// ```
2472 pub fn everything() -> Self {
2473 Self {
2474 cpu: true,
2475 disk_usage: true,
2476 memory: true,
2477 user: UpdateKind::OnlyIfNotSet,
2478 cwd: UpdateKind::OnlyIfNotSet,
2479 root: UpdateKind::OnlyIfNotSet,
2480 environ: UpdateKind::OnlyIfNotSet,
2481 cmd: UpdateKind::OnlyIfNotSet,
2482 exe: UpdateKind::OnlyIfNotSet,
2483 tasks: true,
2484 }
2485 }
2486
2487 impl_get_set!(
2488 ProcessRefreshKind,
2489 cpu,
2490 with_cpu,
2491 without_cpu,
2492 "\
2493It will retrieve both CPU usage and CPU accumulated time,"
2494 );
2495 impl_get_set!(
2496 ProcessRefreshKind,
2497 disk_usage,
2498 with_disk_usage,
2499 without_disk_usage
2500 );
2501 impl_get_set!(
2502 ProcessRefreshKind,
2503 user,
2504 with_user,
2505 without_user,
2506 UpdateKind,
2507 "\
2508It will retrieve the following information:
2509
2510 * user ID
2511 * user effective ID (if available on the platform)
2512 * user group ID (if available on the platform)
2513 * user effective ID (if available on the platform)"
2514 );
2515 impl_get_set!(ProcessRefreshKind, memory, with_memory, without_memory);
2516 impl_get_set!(ProcessRefreshKind, cwd, with_cwd, without_cwd, UpdateKind);
2517 impl_get_set!(
2518 ProcessRefreshKind,
2519 root,
2520 with_root,
2521 without_root,
2522 UpdateKind
2523 );
2524 impl_get_set!(
2525 ProcessRefreshKind,
2526 environ,
2527 with_environ,
2528 without_environ,
2529 UpdateKind
2530 );
2531 impl_get_set!(ProcessRefreshKind, cmd, with_cmd, without_cmd, UpdateKind);
2532 impl_get_set!(ProcessRefreshKind, exe, with_exe, without_exe, UpdateKind);
2533 impl_get_set!(ProcessRefreshKind, tasks, with_tasks, without_tasks);
2534}
2535
2536/// Used to determine what you want to refresh specifically on the [`Cpu`] type.
2537///
2538/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2539/// the information won't be retrieved if the information is accessible without needing
2540/// extra computation.
2541///
2542/// ```
2543/// use sysinfo::{CpuRefreshKind, System};
2544///
2545/// let mut system = System::new();
2546///
2547/// // We don't want to update all the CPU information.
2548/// system.refresh_cpu_specifics(CpuRefreshKind::everything().without_frequency());
2549///
2550/// for cpu in system.cpus() {
2551/// assert_eq!(cpu.frequency(), 0);
2552/// }
2553/// ```
2554///
2555/// [`Cpu`]: crate::Cpu
2556#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2557pub struct CpuRefreshKind {
2558 cpu_usage: bool,
2559 frequency: bool,
2560}
2561
2562impl CpuRefreshKind {
2563 /// Creates a new `CpuRefreshKind` with every refresh set to `false`.
2564 ///
2565 /// ```
2566 /// use sysinfo::CpuRefreshKind;
2567 ///
2568 /// let r = CpuRefreshKind::nothing();
2569 ///
2570 /// assert_eq!(r.frequency(), false);
2571 /// assert_eq!(r.cpu_usage(), false);
2572 /// ```
2573 pub fn nothing() -> Self {
2574 Self::default()
2575 }
2576
2577 /// Creates a new `CpuRefreshKind` with every refresh set to `true`.
2578 ///
2579 /// ```
2580 /// use sysinfo::CpuRefreshKind;
2581 ///
2582 /// let r = CpuRefreshKind::everything();
2583 ///
2584 /// assert_eq!(r.frequency(), true);
2585 /// assert_eq!(r.cpu_usage(), true);
2586 /// ```
2587 pub fn everything() -> Self {
2588 Self {
2589 cpu_usage: true,
2590 frequency: true,
2591 }
2592 }
2593
2594 impl_get_set!(CpuRefreshKind, cpu_usage, with_cpu_usage, without_cpu_usage);
2595 impl_get_set!(CpuRefreshKind, frequency, with_frequency, without_frequency);
2596}
2597
2598/// Used to determine which memory you want to refresh specifically.
2599///
2600/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2601/// the information won't be retrieved if the information is accessible without needing
2602/// extra computation.
2603///
2604/// ```
2605/// use sysinfo::{MemoryRefreshKind, System};
2606///
2607/// let mut system = System::new();
2608///
2609/// // We don't want to update all memories information.
2610/// system.refresh_memory_specifics(MemoryRefreshKind::nothing().with_ram());
2611///
2612/// println!("total RAM: {}", system.total_memory());
2613/// println!("free RAM: {}", system.free_memory());
2614/// ```
2615#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2616pub struct MemoryRefreshKind {
2617 ram: bool,
2618 swap: bool,
2619}
2620
2621impl MemoryRefreshKind {
2622 /// Creates a new `MemoryRefreshKind` with every refresh set to `false`.
2623 ///
2624 /// ```
2625 /// use sysinfo::MemoryRefreshKind;
2626 ///
2627 /// let r = MemoryRefreshKind::nothing();
2628 ///
2629 /// assert_eq!(r.ram(), false);
2630 /// assert_eq!(r.swap(), false);
2631 /// ```
2632 pub fn nothing() -> Self {
2633 Self::default()
2634 }
2635
2636 /// Creates a new `MemoryRefreshKind` with every refresh set to `true`.
2637 ///
2638 /// ```
2639 /// use sysinfo::MemoryRefreshKind;
2640 ///
2641 /// let r = MemoryRefreshKind::everything();
2642 ///
2643 /// assert_eq!(r.ram(), true);
2644 /// assert_eq!(r.swap(), true);
2645 /// ```
2646 pub fn everything() -> Self {
2647 Self {
2648 ram: true,
2649 swap: true,
2650 }
2651 }
2652
2653 impl_get_set!(MemoryRefreshKind, ram, with_ram, without_ram);
2654 impl_get_set!(MemoryRefreshKind, swap, with_swap, without_swap);
2655}
2656
2657/// Used to determine what you want to refresh specifically on the [`System`][crate::System] type.
2658///
2659/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2660/// the information won't be retrieved if the information is accessible without needing
2661/// extra computation.
2662///
2663/// ```
2664/// use sysinfo::{RefreshKind, System};
2665///
2666/// // We want everything except memory.
2667/// let mut system = System::new_with_specifics(RefreshKind::everything().without_memory());
2668///
2669/// assert_eq!(system.total_memory(), 0);
2670/// # if sysinfo::IS_SUPPORTED_SYSTEM && !cfg!(feature = "apple-sandbox") {
2671/// assert!(system.processes().len() > 0);
2672/// # }
2673/// ```
2674#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2675pub struct RefreshKind {
2676 processes: Option<ProcessRefreshKind>,
2677 memory: Option<MemoryRefreshKind>,
2678 cpu: Option<CpuRefreshKind>,
2679}
2680
2681impl RefreshKind {
2682 /// Creates a new `RefreshKind` with every refresh set to `false`/`None`.
2683 ///
2684 /// ```
2685 /// use sysinfo::RefreshKind;
2686 ///
2687 /// let r = RefreshKind::nothing();
2688 ///
2689 /// assert_eq!(r.processes().is_some(), false);
2690 /// assert_eq!(r.memory().is_some(), false);
2691 /// assert_eq!(r.cpu().is_some(), false);
2692 /// ```
2693 pub fn nothing() -> Self {
2694 Self::default()
2695 }
2696
2697 /// Creates a new `RefreshKind` with every refresh set to `true`/`Some(...)`.
2698 ///
2699 /// ```
2700 /// use sysinfo::RefreshKind;
2701 ///
2702 /// let r = RefreshKind::everything();
2703 ///
2704 /// assert_eq!(r.processes().is_some(), true);
2705 /// assert_eq!(r.memory().is_some(), true);
2706 /// assert_eq!(r.cpu().is_some(), true);
2707 /// ```
2708 pub fn everything() -> Self {
2709 Self {
2710 processes: Some(ProcessRefreshKind::everything()),
2711 memory: Some(MemoryRefreshKind::everything()),
2712 cpu: Some(CpuRefreshKind::everything()),
2713 }
2714 }
2715
2716 impl_get_set!(
2717 RefreshKind,
2718 processes,
2719 with_processes,
2720 without_processes,
2721 ProcessRefreshKind
2722 );
2723 impl_get_set!(
2724 RefreshKind,
2725 memory,
2726 with_memory,
2727 without_memory,
2728 MemoryRefreshKind
2729 );
2730 impl_get_set!(RefreshKind, cpu, with_cpu, without_cpu, CpuRefreshKind);
2731}
2732
2733/// Returns the pid for the current process.
2734///
2735/// `Err` is returned in case the platform isn't supported.
2736///
2737/// ```no_run
2738/// use sysinfo::get_current_pid;
2739///
2740/// match get_current_pid() {
2741/// Ok(pid) => {
2742/// println!("current pid: {}", pid);
2743/// }
2744/// Err(e) => {
2745/// println!("failed to get current pid: {}", e);
2746/// }
2747/// }
2748/// ```
2749#[allow(clippy::unnecessary_wraps)]
2750pub fn get_current_pid() -> Result<Pid, &'static str> {
2751 cfg_select! {
2752 feature = "unknown-ci" => {
2753 fn inner() -> Result<Pid, &'static str> {
2754 Err("Unknown platform (CI)")
2755 }
2756 }
2757 any(
2758 target_os = "freebsd",
2759 target_os = "netbsd",
2760 target_os = "linux",
2761 target_os = "android",
2762 target_os = "macos",
2763 target_os = "ios",
2764 ) => {
2765 fn inner() -> Result<Pid, &'static str> {
2766 unsafe { Ok(Pid(libc::getpid())) }
2767 }
2768 }
2769 windows => {
2770 fn inner() -> Result<Pid, &'static str> {
2771 use windows::Win32::System::Threading::GetCurrentProcessId;
2772
2773 unsafe { Ok(Pid(GetCurrentProcessId() as _)) }
2774 }
2775 }
2776 _ => {
2777 fn inner() -> Result<Pid, &'static str> {
2778 Err("Unknown platform")
2779 }
2780 }
2781 }
2782 inner()
2783}
2784
2785/// Contains all the methods of the [`Cpu`][crate::Cpu] struct.
2786///
2787/// ```no_run
2788/// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2789///
2790/// let mut s = System::new_with_specifics(
2791/// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2792/// );
2793///
2794/// // Wait a bit because CPU usage is based on diff.
2795/// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
2796/// // Refresh CPUs again to get actual value.
2797/// s.refresh_cpu_all();
2798///
2799/// for cpu in s.cpus() {
2800/// println!("{}%", cpu.cpu_usage());
2801/// }
2802/// ```
2803pub struct Cpu {
2804 pub(crate) inner: CpuInner,
2805}
2806
2807impl Cpu {
2808 /// Returns this CPU's usage.
2809 ///
2810 /// Note: You'll need to refresh it at least twice (diff between the first and the second is
2811 /// how CPU usage is computed) at first if you want to have a non-zero value.
2812 ///
2813 /// ```no_run
2814 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2815 ///
2816 /// let mut s = System::new_with_specifics(
2817 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2818 /// );
2819 ///
2820 /// // Wait a bit because CPU usage is based on diff.
2821 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
2822 /// // Refresh CPUs again to get actual value.
2823 /// s.refresh_cpu_all();
2824 ///
2825 /// for cpu in s.cpus() {
2826 /// println!("{}%", cpu.cpu_usage());
2827 /// }
2828 /// ```
2829 pub fn cpu_usage(&self) -> f32 {
2830 self.inner.cpu_usage()
2831 }
2832
2833 /// Returns this CPU's name.
2834 ///
2835 /// ```no_run
2836 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2837 ///
2838 /// let s = System::new_with_specifics(
2839 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2840 /// );
2841 /// for cpu in s.cpus() {
2842 /// println!("{}", cpu.name());
2843 /// }
2844 /// ```
2845 pub fn name(&self) -> &str {
2846 self.inner.name()
2847 }
2848
2849 /// Returns the CPU's vendor id.
2850 ///
2851 /// ```no_run
2852 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2853 ///
2854 /// let s = System::new_with_specifics(
2855 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2856 /// );
2857 /// for cpu in s.cpus() {
2858 /// println!("{}", cpu.vendor_id());
2859 /// }
2860 /// ```
2861 pub fn vendor_id(&self) -> &str {
2862 self.inner.vendor_id()
2863 }
2864
2865 /// Returns the CPU's brand.
2866 ///
2867 /// ```no_run
2868 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2869 ///
2870 /// let s = System::new_with_specifics(
2871 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2872 /// );
2873 /// for cpu in s.cpus() {
2874 /// println!("{}", cpu.brand());
2875 /// }
2876 /// ```
2877 pub fn brand(&self) -> &str {
2878 self.inner.brand()
2879 }
2880
2881 /// Returns the CPU's frequency (in MHz).
2882 ///
2883 /// ```no_run
2884 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2885 ///
2886 /// let s = System::new_with_specifics(
2887 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2888 /// );
2889 /// for cpu in s.cpus() {
2890 /// println!("{}", cpu.frequency());
2891 /// }
2892 /// ```
2893 pub fn frequency(&self) -> u64 {
2894 self.inner.frequency()
2895 }
2896}
2897
2898#[cfg(test)]
2899mod test {
2900 use crate::*;
2901 use std::str::FromStr;
2902
2903 // In case `Process::updated` is misused, `System::refresh_processes` might remove them
2904 // so this test ensures that it doesn't happen.
2905 #[test]
2906 fn check_refresh_process_update() {
2907 if !IS_SUPPORTED_SYSTEM {
2908 return;
2909 }
2910 let mut s = System::new_all();
2911 let total = s.processes().len() as isize;
2912 s.refresh_processes(ProcessesToUpdate::All, false);
2913 let new_total = s.processes().len() as isize;
2914 // There should be almost no difference in the processes count.
2915 assert!(
2916 (new_total - total).abs() <= 5,
2917 "{} <= 5",
2918 (new_total - total).abs()
2919 );
2920 }
2921
2922 #[test]
2923 fn check_cpu_arch() {
2924 assert!(!System::cpu_arch().is_empty());
2925 }
2926
2927 // Ensure that the CPUs frequency isn't retrieved until we ask for it.
2928 #[test]
2929 fn check_cpu_frequency() {
2930 if !IS_SUPPORTED_SYSTEM {
2931 return;
2932 }
2933 let mut s = System::new();
2934 s.refresh_processes(ProcessesToUpdate::All, false);
2935 for proc_ in s.cpus() {
2936 assert_eq!(proc_.frequency(), 0);
2937 }
2938 s.refresh_cpu_usage();
2939 for proc_ in s.cpus() {
2940 assert_eq!(proc_.frequency(), 0);
2941 }
2942 // In a VM, it'll fail.
2943 if std::env::var("APPLE_CI").is_ok()
2944 || std::env::var("FREEBSD_CI").is_ok()
2945 || std::env::var("NETBSD_CI").is_ok()
2946 {
2947 return;
2948 }
2949 s.refresh_cpu_specifics(CpuRefreshKind::everything());
2950 for proc_ in s.cpus() {
2951 assert_ne!(proc_.frequency(), 0);
2952 }
2953 }
2954
2955 #[test]
2956 fn check_process_memory_usage() {
2957 let mut s = System::new();
2958 s.refresh_specifics(RefreshKind::everything());
2959
2960 if IS_SUPPORTED_SYSTEM {
2961 // No process should have 0 as memory usage.
2962 #[cfg(not(feature = "apple-sandbox"))]
2963 assert!(!s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
2964 } else {
2965 // There should be no process, but if there is one, its memory usage should be 0.
2966 assert!(s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
2967 }
2968 }
2969
2970 #[test]
2971 fn check_system_implemented_traits() {
2972 fn check<T: Sized + std::fmt::Debug + Default + Send + Sync>(_: T) {}
2973
2974 check(System::new());
2975 }
2976
2977 #[test]
2978 fn check_memory_usage() {
2979 let mut s = System::new();
2980
2981 assert_eq!(s.total_memory(), 0);
2982 assert_eq!(s.free_memory(), 0);
2983 assert_eq!(s.available_memory(), 0);
2984 assert_eq!(s.used_memory(), 0);
2985 assert_eq!(s.total_swap(), 0);
2986 assert_eq!(s.free_swap(), 0);
2987 assert_eq!(s.used_swap(), 0);
2988
2989 s.refresh_memory();
2990 if IS_SUPPORTED_SYSTEM {
2991 assert!(s.total_memory() > 0);
2992 assert!(s.used_memory() > 0);
2993 if s.total_swap() > 0 {
2994 // I think it's pretty safe to assume that there is still some swap left...
2995 assert!(s.free_swap() > 0);
2996 }
2997 } else {
2998 assert_eq!(s.total_memory(), 0);
2999 assert_eq!(s.used_memory(), 0);
3000 assert_eq!(s.total_swap(), 0);
3001 assert_eq!(s.free_swap(), 0);
3002 }
3003 }
3004
3005 #[cfg(target_os = "linux")]
3006 #[test]
3007 fn check_processes_cpu_usage() {
3008 if !IS_SUPPORTED_SYSTEM {
3009 return;
3010 }
3011 let mut s = System::new();
3012
3013 s.refresh_processes(ProcessesToUpdate::All, false);
3014 // All CPU usage will start at zero until the second refresh
3015 assert!(
3016 s.processes()
3017 .iter()
3018 .all(|(_, proc_)| proc_.cpu_usage() == 0.0)
3019 );
3020
3021 // Wait a bit to update CPU usage values
3022 std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL);
3023 s.refresh_processes(ProcessesToUpdate::All, true);
3024 assert!(
3025 s.processes()
3026 .iter()
3027 .all(|(_, proc_)| proc_.cpu_usage() >= 0.0
3028 && proc_.cpu_usage() <= (s.cpus().len() as f32) * 100.0)
3029 );
3030 assert!(
3031 s.processes()
3032 .iter()
3033 .any(|(_, proc_)| proc_.cpu_usage() > 0.0)
3034 );
3035 }
3036
3037 #[test]
3038 fn check_cpu_usage() {
3039 if !IS_SUPPORTED_SYSTEM {
3040 return;
3041 }
3042 let mut s = System::new();
3043 for _ in 0..10 {
3044 s.refresh_cpu_usage();
3045 // Wait a bit to update CPU usage values
3046 std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL);
3047 if s.cpus().iter().any(|c| c.cpu_usage() > 0.0) {
3048 // All good!
3049 return;
3050 }
3051 }
3052 panic!("CPU usage is always zero...");
3053 }
3054
3055 #[test]
3056 fn check_system_info() {
3057 // We don't want to test on unsupported systems.
3058 if IS_SUPPORTED_SYSTEM {
3059 assert!(
3060 !System::name()
3061 .expect("Failed to get system name")
3062 .is_empty()
3063 );
3064
3065 assert!(
3066 !System::kernel_version()
3067 .expect("Failed to get kernel version")
3068 .is_empty()
3069 );
3070
3071 assert!(
3072 !System::os_version()
3073 .expect("Failed to get os version")
3074 .is_empty()
3075 );
3076
3077 assert!(
3078 !System::long_os_version()
3079 .expect("Failed to get long OS version")
3080 .is_empty()
3081 );
3082 }
3083
3084 assert!(!System::distribution_id().is_empty());
3085 }
3086
3087 #[test]
3088 fn check_host_name() {
3089 // We don't want to test on unsupported systems.
3090 if IS_SUPPORTED_SYSTEM {
3091 assert!(System::host_name().is_some());
3092 }
3093 }
3094
3095 #[test]
3096 fn check_refresh_process_return_value() {
3097 // We don't want to test on unsupported systems.
3098 if IS_SUPPORTED_SYSTEM {
3099 let _pid = get_current_pid().expect("Failed to get current PID");
3100
3101 #[cfg(not(feature = "apple-sandbox"))]
3102 {
3103 let mut s = System::new();
3104 // First check what happens in case the process isn't already in our process list.
3105 assert_eq!(
3106 s.refresh_processes(ProcessesToUpdate::Some(&[_pid]), true),
3107 1
3108 );
3109 // Then check that it still returns 1 if the process is already in our process list.
3110 assert_eq!(
3111 s.refresh_processes(ProcessesToUpdate::Some(&[_pid]), true),
3112 1
3113 );
3114 }
3115 }
3116 }
3117
3118 #[test]
3119 fn check_cpus_number() {
3120 let mut s = System::new();
3121
3122 // This information isn't retrieved by default.
3123 assert!(s.cpus().is_empty());
3124 if IS_SUPPORTED_SYSTEM {
3125 // The physical cores count is recomputed every time the function is called, so the
3126 // information must be relevant even with nothing initialized.
3127 let physical_cores_count =
3128 System::physical_core_count().expect("failed to get number of physical cores");
3129
3130 s.refresh_cpu_usage();
3131 // The cpus shouldn't be empty anymore.
3132 assert!(!s.cpus().is_empty());
3133
3134 // In case we are running inside a VM, it's possible to not have a physical core, only
3135 // logical ones, which is why we don't test `physical_cores_count > 0`.
3136 let physical_cores_count2 =
3137 System::physical_core_count().expect("failed to get number of physical cores");
3138 assert!(physical_cores_count2 <= s.cpus().len());
3139 assert_eq!(physical_cores_count, physical_cores_count2);
3140 } else {
3141 assert_eq!(System::physical_core_count(), None);
3142 }
3143 assert!(System::physical_core_count().unwrap_or(0) <= s.cpus().len());
3144 }
3145
3146 // This test only exists to ensure that the `Display` and `Debug` traits are implemented on the
3147 // `ProcessStatus` enum on all targets.
3148 #[test]
3149 fn check_display_impl_process_status() {
3150 println!("{} {:?}", ProcessStatus::Parked, ProcessStatus::Idle);
3151 }
3152
3153 #[test]
3154 #[allow(clippy::unnecessary_fallible_conversions)]
3155 fn check_pid_from_impls() {
3156 assert!(crate::Pid::try_from(0usize).is_ok());
3157 // If it doesn't panic, it's fine.
3158 let _ = crate::Pid::from(0);
3159 assert!(crate::Pid::from_str("0").is_ok());
3160 }
3161
3162 #[test]
3163 #[allow(clippy::const_is_empty)]
3164 fn check_nb_supported_signals() {
3165 if IS_SUPPORTED_SYSTEM {
3166 assert!(
3167 !SUPPORTED_SIGNALS.is_empty(),
3168 "SUPPORTED_SIGNALS shouldn't be empty on supported systems!"
3169 );
3170 } else {
3171 assert!(
3172 SUPPORTED_SIGNALS.is_empty(),
3173 "SUPPORTED_SIGNALS should be empty on not support systems!"
3174 );
3175 }
3176 }
3177}
3178
3179#[cfg(doctest)]
3180mod doctest {
3181 // FIXME: Can be removed once negative trait bounds are supported.
3182 /// Check that `Process` doesn't implement `Clone`.
3183 ///
3184 /// First we check that the "basic" code works:
3185 ///
3186 /// ```no_run
3187 /// use sysinfo::{Process, System};
3188 ///
3189 /// let mut s = System::new_all();
3190 /// let p: &Process = s.processes().values().next().unwrap();
3191 /// ```
3192 ///
3193 /// And now we check if it fails when we try to clone it:
3194 ///
3195 /// ```compile_fail
3196 /// use sysinfo::{Process, System};
3197 ///
3198 /// let mut s = System::new_all();
3199 /// let p: &Process = s.processes().values().next().unwrap();
3200 /// let p = (*p).clone();
3201 /// ```
3202 mod process_clone {}
3203
3204 // FIXME: Can be removed once negative trait bounds are supported.
3205 /// Check that `System` doesn't implement `Clone`.
3206 ///
3207 /// First we check that the "basic" code works:
3208 ///
3209 /// ```no_run
3210 /// use sysinfo::{Process, System};
3211 ///
3212 /// let s = System::new();
3213 /// ```
3214 ///
3215 /// And now we check if it fails when we try to clone it:
3216 ///
3217 /// ```compile_fail
3218 /// use sysinfo::{Process, System};
3219 ///
3220 /// let s = System::new();
3221 /// let s = s.clone();
3222 /// ```
3223 mod system_clone {}
3224}