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