1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//! Module abstracting interactions with getrusage(2)
//!
//! Also holds utility functions for summarizing the data returned by getrusage(2)
#[cfg(not(target_os = "fuchsia"))]
use libc::getrusage;
use libc::{c_int, rusage, RUSAGE_CHILDREN, RUSAGE_SELF};
use time::Duration;
use super::TimeVal;
/// Interface for `RUSAGE_*` constants from libc.
///
/// TODO This is an incomplete set of constants. It is currently missing
/// `libc::RUSAGE_THREAD` which requires the `_GNU_SOURCE` macro to be defined
/// at build time.
pub enum ResourceConsumer {
Caller = RUSAGE_SELF as isize,
Children = RUSAGE_CHILDREN as isize,
}
#[derive(Debug)]
pub struct RUsage {
pub timing: Timing,
pub mem: MemoryUsage,
pub io: IOUsage,
}
#[derive(Debug)]
pub struct Timing {
/// User CPU time used
pub user_time: Duration,
/// System CPU time used
pub sys_time: Duration,
}
#[derive(Debug)]
pub struct MemoryUsage {
/// Maximum resident set size
pub max_rss: u64,
/// Number of page reclaims (soft page faults)
pub num_minor_page_flt: u64,
/// Number of page faults (hard page faults)
pub num_major_page_flt: u64,
/// Number of voluntary context switches
pub num_vol_ctx_switch: u64,
/// Number of involuntary context switches
pub num_invol_ctx_switch: u64,
/// Unmaintained on linux: Integral shared memory size
pub shared_mem_size: u64,
/// Unmaintained on linux: Integral unshared data size
pub unshared_data_size: u64,
/// Unmaintained on linux: Integral unshared stack size
pub unshared_stack_size: u64,
/// Unmaintained on linux: Number of swaps
pub num_swaps: u64,
}
#[derive(Debug)]
pub struct IOUsage {
/// Number of block input operations
pub num_block_in: u64,
/// Number of block output operations
pub num_block_out: u64,
/// Unmaintained on linux: Number of IPC messages recieved
pub num_sock_recv: u64,
/// Unmaintained on linux: Number of IPC messages sent
pub num_sock_send: u64,
/// Unmaintained: Number of signals recieved
pub num_signals: u64,
}
fn timeval_to_duration(t: TimeVal) -> Duration {
// This type cast is realistically safe because the number of
// microseconds in a second cannot exceed `1e+6`, which at
// most would be `1e+9` nanoseconds, which fits in i32
// If this panics something really went wrong in the underlying
// C-api that returned this timeval
Duration::new(t.tv_sec as i64, t.tv_usec as i32 * 1_000)
}
impl From<rusage> for RUsage {
fn from(ru: rusage) -> Self {
RUsage {
timing: Timing {
user_time: timeval_to_duration(ru.ru_utime),
sys_time: timeval_to_duration(ru.ru_stime),
},
mem: MemoryUsage {
max_rss: ru.ru_maxrss as u64,
num_minor_page_flt: ru.ru_minflt as u64,
num_major_page_flt: ru.ru_majflt as u64,
num_vol_ctx_switch: ru.ru_nvcsw as u64,
num_invol_ctx_switch: ru.ru_nivcsw as u64,
shared_mem_size: ru.ru_ixrss as u64,
unshared_data_size: ru.ru_idrss as u64,
unshared_stack_size: ru.ru_isrss as u64,
num_swaps: ru.ru_nswap as u64,
},
io: IOUsage {
num_block_in: ru.ru_inblock as u64,
num_block_out: ru.ru_oublock as u64,
num_sock_recv: ru.ru_msgrcv as u64,
num_sock_send: ru.ru_msgsnd as u64,
num_signals: ru.ru_nsignals as u64,
},
}
}
}
/// Safely wrap `libc::getrusage`
pub fn get_rusage(target: ResourceConsumer) -> RUsage {
let mut usage: rusage = unsafe { std::mem::zeroed() };
#[cfg(not(target_os = "fuchsia"))]
// Fuchsia doesn't have a getrusage syscall, but provides the rusage struct.
// The default is to abort with an error message so that callers don't end
// up with invalid data.
unsafe {
getrusage(target as c_int, &mut usage);
}
RUsage::from(usage)
}