self_meter/lib.rs
1#![warn(missing_docs)]
2#![warn(missing_debug_implementations)]
3//! A tiny library to measure resource usage of the process it's used in.
4//! Currently it measures:
5//!
6//! * Memory Usage
7//! * CPU Usage with breakdown by each thread
8//! * Disk Usage
9//!
10//! More metrics might be added later. Currently, library supports only linux,
11//! but pull requests for other platforms are welcome.
12//!
13//! # Example
14//!
15//! ```rust,no_run
16//!
17//! # use std::io::{Write, stderr};
18//! # use std::time::Duration;
19//! # use std::thread::sleep;
20//! # use std::collections::BTreeMap;
21//!
22//! fn main() {
23//! let mut meter = self_meter::Meter::new(Duration::new(1, 0)).unwrap();
24//! meter.track_current_thread("main");
25//! loop {
26//! meter.scan()
27//! .map_err(|e| writeln!(&mut stderr(), "Scan error: {}", e)).ok();
28//! println!("Report: {:#?}", meter.report());
29//! println!("Threads: {:#?}",
30//! meter.thread_report().map(|x| x.collect::<BTreeMap<_,_>>()));
31//! // Put your task here
32//! // ...
33//! //
34//! sleep(Duration::new(1, 0));
35//! }
36//! }
37//! ```
38extern crate libc;
39extern crate num_cpus;
40extern crate serde;
41
42#[macro_use] extern crate quick_error;
43#[macro_use] extern crate serde_derive;
44
45use std::fs::File;
46use std::time::{SystemTime, Instant, Duration};
47use std::collections::{VecDeque, HashMap};
48
49mod meter;
50mod scan;
51mod error;
52mod report;
53mod serialize;
54mod debug;
55
56pub use error::Error;
57pub use report::ThreadReportIter;
58/// A Pid type used to identify processes and threads
59pub type Pid = u32;
60
61struct ThreadInfo {
62 user_time: u64,
63 system_time: u64,
64 child_user_time: u64,
65 child_system_time: u64,
66}
67
68struct Snapshot {
69 timestamp: SystemTime,
70 instant: Instant,
71 /// System uptime in centisecs
72 uptime: u64,
73 /// System idle time in centisecs
74 idle_time: u64,
75 process: ThreadInfo,
76 memory_rss: u64,
77 memory_virtual: u64,
78 memory_virtual_peak: u64,
79 memory_swap: u64,
80 read_bytes: u64,
81 write_bytes: u64,
82 read_ops: u64,
83 write_ops: u64,
84 read_disk_bytes: u64,
85 write_disk_bytes: u64,
86 write_cancelled_bytes: u64,
87 threads: HashMap<Pid, ThreadInfo>,
88}
89
90
91/// CPU usage of a single thread
92#[derive(Debug)]
93pub struct ThreadUsage {
94 /// Thread's own CPU usage. 100% is a single core
95 pub cpu_usage: f32,
96 /// Thread's CPU usage with its awaited children. 100% is a single core
97 pub cpu_usage_with_children: f32,
98}
99
100/// Report returned by `Meter::report`
101///
102/// Note: this structure implements `serde::Serialize`, and all timestamps and
103/// durations are stored as integers in milliseconds.
104#[derive(Debug, Serialize)]
105pub struct Report {
106 /// Timestamp
107 #[serde(serialize_with="serialize::serialize_timestamp")]
108 pub timestamp: SystemTime,
109
110 /// The interval time this data has averaged over in milliseconds
111 #[serde(serialize_with="serialize::serialize_duration")]
112 pub duration: Duration,
113
114 /// Start time
115 #[serde(serialize_with="serialize::serialize_timestamp")]
116 pub start_time: SystemTime,
117
118 /// The uptime of the system
119 ///
120 /// Note this value can be smaller than time since `start_time`
121 /// because this value doesn't include time when system was sleeping
122 #[serde(serialize_with="serialize::serialize_duration")]
123 pub system_uptime: Duration,
124 /// Whole system CPU usage. 100% is all cores
125 pub global_cpu_usage: f32,
126 /// Process' own CPU usage. 100% is a single core
127 pub process_cpu_usage: f32,
128 /// Process' CPU usage with its awaited children. 100% is a single core
129 pub gross_cpu_usage: f32,
130 /// Process' memory usage
131 pub memory_rss: u64,
132 /// Process' virtual memory usage
133 pub memory_virtual: u64,
134 /// Process' swap usage
135 pub memory_swap: u64,
136 /// Process' peak memory usage (not precise)
137 pub memory_rss_peak: u64,
138 /// Process' peak virtual memory usage (tracked by OS)
139 pub memory_virtual_peak: u64,
140 /// Process' swap usage (not precise)
141 pub memory_swap_peak: u64,
142 /// Bytes read per second from block-backed filesystems
143 pub disk_read: f32,
144 /// Bytes written per second from block-backed filesystems
145 pub disk_write: f32,
146 /// Bytes per second of cancelled writes (i.e. removed temporary files)
147 pub disk_cancelled: f32,
148 /// Bytes read per second (total)
149 pub io_read: f32,
150 /// Bytes written per second (total)
151 pub io_write: f32,
152 /// Read operations (syscalls) per second (total)
153 pub io_read_ops: f32,
154 /// Write operations (syscalls) per second (total)
155 pub io_write_ops: f32,
156}
157
158/// Report of CPU usage by single thread
159#[derive(Debug, Serialize)]
160pub struct ThreadReport {
161 /// Threads' own CPU usage. 100% is a single core
162 pub cpu_usage: f32,
163 /// Threads' own CPU usage in kernel space. 100% is a single core
164 pub system_cpu: f32,
165 /// Threads' own CPU usage in user space. 100% is a single core
166 pub user_cpu: f32,
167}
168
169/// The main structure that makes mesurements and reports values
170///
171/// Create it with `new()` then add threads that you want to track in a thread
172/// breakdown information with `meter.track_thread()` and
173/// `meter.untrack_thread()`.
174///
175/// Then add `meter.scan()` with a timer to scan the process info. It's
176/// recommended to call it on the interval of one second.
177///
178/// Method `report()` may be used to get structure with stats. `report_json()`
179/// can return a `rustc_serialize::Json` and `report_json_str()` returns that
180/// serialized.
181///
182/// Note that the structure returned with `report()` can be changed when we
183/// bump **major version** of the library. And while `report_json()` and
184/// `report_json_str()` will never break the type system, their format will
185/// always reflect that of `report()` call.
186///
187/// We don't track all the threads separately because thread ids are useless
188/// without names, and we can fine-tune performance in the case we have known
189/// number of threads. Obviously, process-wide info accounts all the threads.
190pub struct Meter {
191 #[allow(dead_code)]
192 scan_interval: Duration,
193 num_cpus: usize,
194 num_snapshots: usize,
195 start_time: SystemTime,
196 snapshots: VecDeque<Snapshot>,
197 thread_names: HashMap<Pid, String>,
198 /// This is a buffer for reading some text data from /proc/anything.
199 /// We use it to avoid memory allocations. This makes code a little bit
200 /// more complex, but we want to avoid overhead as much as possible
201 text_buf: String,
202 /// This is a smaller buffer for formatting paths, similar to `text_buf`
203 path_buf: String,
204
205 /// This file is always open because if we drop privileges and then
206 /// try to open a file we can't open it back again
207 #[cfg(target_os="linux")]
208 io_file: File,
209
210 memory_rss_peak: u64,
211 memory_swap_peak: u64,
212}