self_meter/
meter.rs

1use std::fs::File;
2use std::time::{Duration, SystemTime};
3use std::collections::{VecDeque, HashMap};
4
5use num_cpus;
6
7use {Meter, Error, Pid};
8use error::IoStatError;
9
10
11impl Meter {
12    /// Create a new meter with scan_interval
13    ///
14    /// Note: meter will not scan by itself, you are expected to call `scan()`
15    /// with interval.
16    ///
17    /// You don't have to guarantee the interval exactly, but it influences
18    /// the accuracy of your measurements.
19    ///
20    /// When creating a `Meter` object we are trying to discover the number
21    /// of processes on the system. If that fails, we return error.
22    pub fn new(scan_interval: Duration) -> Result<Meter, Error> {
23        Meter::_new(scan_interval)
24    }
25    #[cfg(target_os="linux")]
26    fn _new(scan_interval: Duration) -> Result<Meter, Error> {
27        let io_file = File::open("/proc/self/io").map_err(IoStatError::Io)?;
28        Ok(Meter {
29            scan_interval: scan_interval,
30            num_cpus: num_cpus::get(),
31            num_snapshots: 10,
32            start_time: SystemTime::now(),
33            snapshots: VecDeque::with_capacity(10),
34            thread_names: HashMap::new(),
35            text_buf: String::with_capacity(1024),
36            path_buf: String::with_capacity(100),
37            io_file: io_file,
38
39            memory_swap_peak: 0,
40            memory_rss_peak: 0,
41        })
42    }
43
44    #[cfg(not(target_os="linux"))]
45    fn _new(scan_interval: Duration) -> Result<Meter, Error> {
46        Ok(Meter {
47            scan_interval: scan_interval,
48            num_cpus: num_cpus::get(),
49            num_snapshots: 10,
50            start_time: SystemTime::now(),
51            snapshots: VecDeque::with_capacity(10),
52            thread_names: HashMap::new(),
53            text_buf: String::with_capacity(1024),
54            path_buf: String::with_capacity(100),
55
56            memory_swap_peak: 0,
57            memory_rss_peak: 0,
58        })
59    }
60
61    /// Start tracking specified thread
62    ///
63    /// Note you must add main thread here manually
64    pub fn track_thread(&mut self, tid: Pid, name: &str) {
65        self.thread_names.insert(tid, name.to_string());
66    }
67    /// Stop tracking specified thread (for example if it's dead)
68    pub fn untrack_thread(&mut self, tid: Pid) {
69        self.thread_names.remove(&tid);
70        for s in &mut self.snapshots {
71            s.threads.remove(&tid);
72        }
73    }
74    /// Add current thread using `track_thread`, returns thread id
75    #[cfg(target_os="linux")]
76    pub fn track_current_thread(&mut self, name: &str) -> Pid {
77        use libc::{syscall, SYS_gettid};
78        let tid = unsafe { syscall(SYS_gettid) } as Pid;
79        self.track_thread(tid, name);
80        return tid;
81    }
82    /// Add current thread using `track_thread`, returns thread id
83    ///
84    /// Non-linux is not supported yet (no-op)
85    #[cfg(not(target_os="linux"))]
86    pub fn track_current_thread(&mut self, _name: &str) -> Pid {
87        // TODO(tailhook) OS X and windows
88        0
89    }
90    /// Remove current thread using `untrack_thread`
91    #[cfg(target_os="linux")]
92    pub fn untrack_current_thread(&mut self) {
93        use libc::{syscall, SYS_gettid};
94        let tid = unsafe { syscall(SYS_gettid) } as Pid;
95        self.untrack_thread(tid);
96    }
97    /// Remove current thread using `untrack_thread`
98    ///
99    /// Non-linux is not supported yet (no-op)
100    #[cfg(not(target_os="linux"))]
101    pub fn untrack_current_thread(&mut self) {
102        // TODO
103    }
104    /// Returns interval value configured in constructor
105    pub fn get_scan_interval(&self) -> Duration {
106        self.scan_interval
107    }
108}