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}