rd_hashd_intf/
report.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2use chrono::prelude::*;
3use serde::{Deserialize, Serialize};
4use std::ops;
5use std::time::UNIX_EPOCH;
6
7use rd_util::*;
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
10pub enum Phase {
11    Prep,
12    Running,
13    BenchCpuSinglePrep,
14    BenchCpuSingle,
15    BenchCpuSaturationPrep,
16    BenchCpuSaturation,
17    BenchMemPrep,
18    BenchMemUp,
19    BenchMemBisect,
20    BenchMemRefine,
21}
22
23impl Default for Phase {
24    fn default() -> Self {
25        Phase::Prep
26    }
27}
28
29impl Phase {
30    pub fn name(&self) -> &'static str {
31        match self {
32            Self::Prep => "prep",
33            Self::Running => "run",
34            Self::BenchCpuSinglePrep => "1cpu-prep",
35            Self::BenchCpuSingle => "1cpu",
36            Self::BenchCpuSaturationPrep => "cpu-prep",
37            Self::BenchCpuSaturation => "cpu",
38            Self::BenchMemPrep => "mem-prep",
39            Self::BenchMemUp => "mem-up",
40            Self::BenchMemBisect => "mem-bisect",
41            Self::BenchMemRefine => "mem-refine",
42        }
43    }
44}
45
46#[derive(Clone, Debug, Default, Serialize, Deserialize)]
47pub struct Latencies {
48    pub min: f64,
49    pub p01: f64,
50    pub p05: f64,
51    pub p10: f64,
52    pub p16: f64,
53    pub p50: f64,
54    pub p84: f64,
55    pub p90: f64,
56    pub p95: f64,
57    pub p99: f64,
58    pub p99_9: f64,
59    pub p99_99: f64,
60    pub p99_999: f64,
61    pub max: f64,
62    pub ctl: f64,
63}
64
65impl ops::AddAssign<&Latencies> for Latencies {
66    fn add_assign(&mut self, rhs: &Latencies) {
67        self.min += rhs.min;
68        self.p01 += rhs.p01;
69        self.p05 += rhs.p05;
70        self.p10 += rhs.p10;
71        self.p16 += rhs.p16;
72        self.p50 += rhs.p50;
73        self.p84 += rhs.p84;
74        self.p90 += rhs.p90;
75        self.p95 += rhs.p95;
76        self.p99 += rhs.p99;
77        self.p99_9 += rhs.p99_9;
78        self.p99_99 += rhs.p99_99;
79        self.p99_999 += rhs.p99_999;
80        self.max += rhs.max;
81        self.ctl += rhs.ctl;
82    }
83}
84
85impl<T: Into<f64>> ops::DivAssign<T> for Latencies {
86    fn div_assign(&mut self, rhs: T) {
87        let div = rhs.into();
88        self.min /= div;
89        self.p01 /= div;
90        self.p05 /= div;
91        self.p10 /= div;
92        self.p16 /= div;
93        self.p50 /= div;
94        self.p84 /= div;
95        self.p90 /= div;
96        self.p95 /= div;
97        self.p99 /= div;
98        self.p99_9 /= div;
99        self.p99_99 /= div;
100        self.p99_999 /= div;
101        self.max /= div;
102        self.ctl /= div;
103    }
104}
105
106const STAT_DOC: &str = "\
107//  rps: Request per second in the last control period
108//  concurrency: Current number of active worker threads
109//  concurrency_max: Current concurrency max from latency target
110//  file_addr_frac: Current file footprint fraction
111//  anon_addr_frac: Current anon footprint fraction
112//  nr_in_flight: The number of requests in flight
113//  nr_done: Total number of hashes calculated
114//  nr_workers: Number of worker threads
115//  nr_idle_workers: Number of idle workers
116//  lat.p*: Latency percentiles
117//  lat.ctl: Latency percentile used for rps control (params.lat_target_pct)
118";
119
120#[derive(Clone, Debug, Default, Serialize, Deserialize)]
121pub struct Stat {
122    pub rps: f64,
123    pub concurrency: f64,
124    pub concurrency_max: f64,
125    pub file_addr_frac: f64,
126    pub anon_addr_frac: f64,
127    pub nr_in_flight: u32,
128    pub nr_done: u64,
129    pub nr_workers: usize,
130    pub nr_idle_workers: usize,
131    pub lat: Latencies,
132
133    pub file_size: u64,
134    pub file_dist: Vec<u64>,
135    pub anon_size: usize,
136    pub anon_dist: Vec<u64>,
137}
138
139impl ops::AddAssign<&Stat> for Stat {
140    fn add_assign(&mut self, rhs: &Stat) {
141        self.rps += rhs.rps;
142        self.concurrency += rhs.concurrency;
143        self.concurrency_max += rhs.concurrency_max;
144        self.file_addr_frac += rhs.file_addr_frac;
145        self.anon_addr_frac += rhs.anon_addr_frac;
146        self.nr_in_flight += rhs.nr_in_flight;
147        self.nr_done += rhs.nr_done;
148        self.nr_workers += rhs.nr_workers;
149        self.nr_idle_workers += rhs.nr_idle_workers;
150        self.lat += &rhs.lat;
151    }
152}
153
154impl Stat {
155    pub fn avg<T: Into<f64>>(&mut self, div: T)
156    where
157        Latencies: ops::DivAssign<f64>,
158    {
159        let divf64 = div.into();
160        self.rps /= divf64;
161        self.concurrency /= divf64;
162        self.concurrency_max /= divf64;
163        self.file_addr_frac /= divf64;
164        self.anon_addr_frac /= divf64;
165        self.nr_in_flight = (self.nr_in_flight as f64 / divf64).round() as u32;
166        self.nr_done = (self.nr_done as f64 / divf64).round() as u64;
167        self.nr_workers = (self.nr_workers as f64 / divf64).round() as usize;
168        self.nr_idle_workers = (self.nr_idle_workers as f64 / divf64).round() as usize;
169        self.lat /= divf64;
170    }
171}
172
173const REPORT_DOC_HEADER: &str = "\
174//
175// rd-hashd runtime report
176//
177//  timestamp: The time this report was created at
178//  phase: The current phase
179//  rotational: Are testfiles and/or swap on hard disk drives?
180//  rotational_testfiles: Are testfiles on hard disk drives?
181//  rotational_swap: Is swap on hard disk drives?
182//  testfiles_progress: Testfiles preparation progress, 1.0 indicates completion
183//  params_modified: Modified timestamp of the loaded params file
184//  mem_probe_frac: Memory frac benchmark is currently probing
185//  mem_probe_at: The timestamp this memory probing started at
186";
187
188#[derive(Clone, Debug, Serialize, Deserialize)]
189pub struct Report {
190    pub timestamp: DateTime<Local>,
191    pub phase: Phase,
192    pub rotational: bool,
193    pub rotational_testfiles: bool,
194    pub rotational_swap: bool,
195    pub testfiles_progress: f64,
196    pub params_modified: DateTime<Local>,
197    pub mem_probe_size: usize,
198    pub mem_probe_at: DateTime<Local>,
199    #[serde(flatten)]
200    pub hasher: Stat,
201}
202
203impl Default for Report {
204    fn default() -> Self {
205        Self {
206            timestamp: DateTime::from(UNIX_EPOCH),
207            phase: Default::default(),
208            rotational: false,
209            rotational_testfiles: false,
210            rotational_swap: false,
211            testfiles_progress: 0.0,
212            params_modified: DateTime::from(UNIX_EPOCH),
213            mem_probe_size: 0,
214            mem_probe_at: DateTime::from(UNIX_EPOCH),
215            hasher: Default::default(),
216        }
217    }
218}
219
220impl JsonLoad for Report {}
221
222impl JsonSave for Report {
223    fn preamble() -> Option<String> {
224        Some(REPORT_DOC_HEADER.to_string() + STAT_DOC + "//\n")
225    }
226}