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