1use anyhow::Result;
3use serde::{Deserialize, Serialize};
4
5use rd_util::*;
6
7#[derive(Clone, Debug, Serialize, Deserialize)]
8pub struct PidParams {
9 pub kp: f64,
10 pub ki: f64,
11 pub kd: f64,
12}
13
14const PARAMS_DOC: &str = "\
15//
16// rd-hashd runtime parameters
17//
18// All parameters can be updated while running and will be applied immediately.
19//
20// rd-hashd keeps calculating SHA1s of different parts of testfiles using
21// concurrent worker threads. The testfile indices and hash sizes are
22// determined using truncated normal distributions which gradually transforms
23// to uniform distributions as their standard deviations increase.
24//
25// All durations are in seconds and memory bytes. A _frac field should be <=
26// 1.0 and specifies a sub-proportion of some other value. A _ratio field is
27// similar but may be greater than 1.0.
28//
29// The concurrency level is modulated using two PID controllers to target the
30// specified latency and RPS so that neither is exceeded. The total number
31// of concurrent threads is limited by `concurrency_max`.
32//
33// The total size of testfiles is set up during startup and can't be changed
34// online. However, the portion which is actively used by rd-hashd can be
35// scaled down with `file_total_frac`.
36//
37// Anonymous memory total and access sizes are configured as proportions to
38// file access sizes.
39//
40// The total footprint for file accesses is scaled between
41// `file_addr_rps_base_frac` and 1.0 linearly if the current RPS is lower than
42// `rps_max`. If `rps_max` is 0, access footprint scaling is disabled. Anon
43// footprint is scaled the same way between 'anon_addr_rps_base_frac' and 1.0.
44//
45// Worker threads will sleep according to the sleep duration distribution and
46// their CPU consumption can be scaled up and down using `cpu_ratio`.
47//
48// control_period: PID control period, best left alone
49// concurrency_max: Maximum number of worker threads
50// lat_target_pct: Latency target percentile
51// lat_target: Latency target
52// rps_target: Request-per-second target
53// rps_max: Reference maximum RPS, used to scale the amount of used memory
54// chunk_pages: Memory access chunk size in pages
55// mem_frac: Memory footprint scaling factor - [0.0, 1.0]
56// file_frac: Page cache proportion of memory footprint - [0.0, 1.0]
57// file_size_mean: File access size average
58// file_size_stdev_ratio: Standard deviation of file access sizes
59// file_addr_stdev_ratio: Standard deviation of file access addresses
60// file_addr_rps_base_frac: Memory scaling starting point for file accesses
61// file_write_frac: The proportion of writes in file accesses
62// anon_size_ratio: Anon access size average - 1.0 means equal as file accesses
63// anon_size_stdev_ratio: Standard deviation of anon access sizes
64// anon_addr_stdev_ratio: Standard deviation of anon access addresses
65// anon_addr_rps_base_frac: Memory scaling starting point for anon accesses
66// anon_write_frac: The proportion of writes in anon accesses
67// sleep_mean: Worker sleep duration average
68// sleep_stdev_ratio: Standard deviation of sleep duration distribution
69// cpu_ratio: CPU usage scaling - 1.0 hashes the same number of bytes as accessed
70// log_bps: Log write bps at rps_max
71// fake_cpu_load: Sleep equivalent time durations instead of calculating SHA1s
72// acc_dist_slots: Access distribution report slots - 0 disables
73// lat_pid: PID controller parameters for latency convergence
74// rps_pid: PID controller parameters for RPS convergence
75//
76";
77
78#[derive(Clone, Debug, Serialize, Deserialize)]
80#[serde(default)]
81pub struct Params {
82 pub control_period: f64,
83 pub concurrency_max: u32,
84 pub lat_target_pct: f64,
85 pub lat_target: f64,
86 pub rps_target: u32,
87 pub rps_max: u32,
88 pub mem_frac: f64,
89 pub chunk_pages: usize,
90 pub file_frac: f64,
91 pub file_size_mean: usize,
92 pub file_size_stdev_ratio: f64,
93 pub file_addr_stdev_ratio: f64,
94 pub file_addr_rps_base_frac: f64,
95 pub file_write_frac: f64,
96 pub anon_size_ratio: f64,
97 pub anon_size_stdev_ratio: f64,
98 pub anon_addr_stdev_ratio: f64,
99 pub anon_addr_rps_base_frac: f64,
100 pub anon_write_frac: f64,
101 pub sleep_mean: f64,
102 pub sleep_stdev_ratio: f64,
103 pub cpu_ratio: f64,
104 pub log_bps: u64,
105 pub fake_cpu_load: bool,
106 pub acc_dist_slots: usize,
107 pub lat_pid: PidParams,
108 pub rps_pid: PidParams,
109}
110
111impl Params {
112 pub const FILE_FRAC_MIN: f64 = 0.001;
113
114 pub fn log_padding(&self) -> u64 {
115 if self.rps_max > 0 {
116 (self.log_bps as f64 / self.rps_max as f64).round() as u64
117 } else {
118 0
119 }
120 }
121}
122
123impl Default for Params {
124 fn default() -> Self {
125 Self {
126 control_period: 1.0,
127 concurrency_max: 65536,
128 lat_target_pct: 0.95,
129 lat_target: 75.0 * MSEC,
130 rps_target: 65536,
131 rps_max: 0,
132 chunk_pages: 25,
133 mem_frac: 0.80,
134 file_frac: 0.25,
135 file_size_mean: 1258291,
136 file_size_stdev_ratio: 0.45,
137 file_addr_stdev_ratio: 0.215,
138 file_addr_rps_base_frac: 0.5,
139 file_write_frac: 0.0,
140 anon_size_ratio: 2.3,
141 anon_size_stdev_ratio: 0.45,
142 anon_addr_stdev_ratio: 0.235,
143 anon_addr_rps_base_frac: 0.5,
144 anon_write_frac: 0.3,
145 sleep_mean: 20.0 * MSEC,
146 sleep_stdev_ratio: 0.33,
147 cpu_ratio: 0.93,
148 log_bps: 1100794,
149 fake_cpu_load: false,
150 acc_dist_slots: 0,
151 lat_pid: PidParams {
152 kp: 0.1,
153 ki: 0.01,
154 kd: 0.01,
155 },
156 rps_pid: PidParams {
157 kp: 0.25,
158 ki: 0.01,
159 kd: 0.01,
160 },
161 }
162 }
163}
164
165impl JsonLoad for Params {
166 fn loaded(&mut self, _prev: Option<&mut Self>) -> Result<()> {
167 self.file_frac = self.file_frac.max(Self::FILE_FRAC_MIN);
168 Ok(())
169 }
170}
171
172impl JsonSave for Params {
173 fn preamble() -> Option<String> {
174 Some(PARAMS_DOC.to_string())
175 }
176}