stat: make add lat percentile functions inline
[fio.git] / engines / cmdprio.c
CommitLineData
e27b9ff0
NC
1/*
2 * IO priority handling helper functions common to the libaio and io_uring
3 * engines.
4 */
5
6#include "cmdprio.h"
7
8static int fio_cmdprio_bssplit_ddir(struct thread_options *to, void *cb_arg,
9 enum fio_ddir ddir, char *str, bool data)
10{
11 struct cmdprio *cmdprio = cb_arg;
12 struct split split;
13 unsigned int i;
14
15 if (ddir == DDIR_TRIM)
16 return 0;
17
18 memset(&split, 0, sizeof(split));
19
20 if (split_parse_ddir(to, &split, str, data, BSSPLIT_MAX))
21 return 1;
22 if (!split.nr)
23 return 0;
24
25 cmdprio->bssplit_nr[ddir] = split.nr;
26 cmdprio->bssplit[ddir] = malloc(split.nr * sizeof(struct bssplit));
27 if (!cmdprio->bssplit[ddir])
28 return 1;
29
30 for (i = 0; i < split.nr; i++) {
31 cmdprio->bssplit[ddir][i].bs = split.val1[i];
32 if (split.val2[i] == -1U) {
33 cmdprio->bssplit[ddir][i].perc = 0;
34 } else {
35 if (split.val2[i] > 100)
36 cmdprio->bssplit[ddir][i].perc = 100;
37 else
38 cmdprio->bssplit[ddir][i].perc = split.val2[i];
39 }
40 }
41
42 return 0;
43}
44
45int fio_cmdprio_bssplit_parse(struct thread_data *td, const char *input,
46 struct cmdprio *cmdprio)
47{
48 char *str, *p;
d6cbeab4 49 int ret = 0;
e27b9ff0
NC
50
51 p = str = strdup(input);
52
53 strip_blank_front(&str);
54 strip_blank_end(str);
55
d6cbeab4
NC
56 ret = str_split_parse(td, str, fio_cmdprio_bssplit_ddir, cmdprio,
57 false);
e27b9ff0
NC
58
59 free(p);
60 return ret;
61}
62
127715b6 63static int fio_cmdprio_percentage(struct cmdprio *cmdprio, struct io_u *io_u)
e27b9ff0
NC
64{
65 enum fio_ddir ddir = io_u->ddir;
d6cbeab4 66 struct cmdprio_options *options = cmdprio->options;
e27b9ff0
NC
67 int i;
68
97f2d484
NC
69 switch (cmdprio->mode) {
70 case CMDPRIO_MODE_PERC:
d6cbeab4 71 return options->percentage[ddir];
97f2d484
NC
72 case CMDPRIO_MODE_BSSPLIT:
73 for (i = 0; i < cmdprio->bssplit_nr[ddir]; i++) {
74 if (cmdprio->bssplit[ddir][i].bs == io_u->buflen)
75 return cmdprio->bssplit[ddir][i].perc;
76 }
77 break;
78 default:
79 /*
80 * An I/O engine should never call this function if cmdprio
81 * is not is use.
82 */
83 assert(0);
e27b9ff0
NC
84 }
85
86 return 0;
87}
88
127715b6
NC
89/**
90 * fio_cmdprio_set_ioprio - Set an io_u ioprio according to cmdprio options
91 *
92 * Generates a random percentage value to determine if an io_u ioprio needs
93 * to be set. If the random percentage value is within the user specified
94 * percentage of I/Os that should use a cmdprio priority value (rather than
95 * the default priority), then this function updates the io_u with an ioprio
96 * value as defined by the cmdprio/cmdprio_class or cmdprio_bssplit options.
97 *
98 * Return true if the io_u ioprio was changed and false otherwise.
99 */
100bool fio_cmdprio_set_ioprio(struct thread_data *td, struct cmdprio *cmdprio,
101 struct io_u *io_u)
102{
103 enum fio_ddir ddir = io_u->ddir;
d6cbeab4 104 struct cmdprio_options *options = cmdprio->options;
97f2d484 105 unsigned int p;
127715b6 106 unsigned int cmdprio_value =
d6cbeab4 107 ioprio_value(options->class[ddir], options->level[ddir]);
127715b6 108
97f2d484 109 p = fio_cmdprio_percentage(cmdprio, io_u);
127715b6
NC
110 if (p && rand_between(&td->prio_state, 0, 99) < p) {
111 io_u->ioprio = cmdprio_value;
112 if (!td->ioprio || cmdprio_value < td->ioprio) {
113 /*
114 * The async IO priority is higher (has a lower value)
115 * than the default priority (which is either 0 or the
116 * value set by "prio" and "prioclass" options).
117 */
118 io_u->flags |= IO_U_F_HIGH_PRIO;
119 }
120 return true;
121 }
122
123 if (td->ioprio && td->ioprio < cmdprio_value) {
124 /*
125 * The IO will be executed with the default priority (which is
126 * either 0 or the value set by "prio" and "prioclass options),
127 * and this priority is higher (has a lower value) than the
128 * async IO priority.
129 */
130 io_u->flags |= IO_U_F_HIGH_PRIO;
131 }
132
133 return false;
134}
135
d6cbeab4
NC
136static int fio_cmdprio_parse_and_gen_bssplit(struct thread_data *td,
137 struct cmdprio *cmdprio)
e27b9ff0 138{
d6cbeab4
NC
139 struct cmdprio_options *options = cmdprio->options;
140 int ret;
141
142 ret = fio_cmdprio_bssplit_parse(td, options->bssplit_str, cmdprio);
143 if (ret)
144 goto err;
145
146 return 0;
147
148err:
149 fio_cmdprio_cleanup(cmdprio);
150
151 return ret;
152}
153
154static int fio_cmdprio_parse_and_gen(struct thread_data *td,
155 struct cmdprio *cmdprio)
156{
157 struct cmdprio_options *options = cmdprio->options;
158 int i, ret;
159
160 switch (cmdprio->mode) {
161 case CMDPRIO_MODE_BSSPLIT:
162 ret = fio_cmdprio_parse_and_gen_bssplit(td, cmdprio);
163 break;
164 case CMDPRIO_MODE_PERC:
165 ret = 0;
166 break;
167 default:
168 assert(0);
169 return 1;
170 }
e27b9ff0
NC
171
172 /*
173 * If cmdprio_percentage/cmdprio_bssplit is set and cmdprio_class
174 * is not set, default to RT priority class.
175 */
a5af2a8b 176 for (i = 0; i < CMDPRIO_RWDIR_CNT; i++) {
d6cbeab4
NC
177 if (options->percentage[i] || cmdprio->bssplit_nr[i]) {
178 if (!options->class[i])
179 options->class[i] = IOPRIO_CLASS_RT;
e27b9ff0
NC
180 }
181 }
182
d6cbeab4
NC
183 return ret;
184}
185
186void fio_cmdprio_cleanup(struct cmdprio *cmdprio)
187{
188 int ddir;
189
190 for (ddir = 0; ddir < CMDPRIO_RWDIR_CNT; ddir++) {
191 free(cmdprio->bssplit[ddir]);
192 cmdprio->bssplit[ddir] = NULL;
193 cmdprio->bssplit_nr[ddir] = 0;
194 }
195
196 /*
197 * options points to a cmdprio_options struct that is part of td->eo.
198 * td->eo itself will be freed by free_ioengine().
199 */
200 cmdprio->options = NULL;
201}
202
203int fio_cmdprio_init(struct thread_data *td, struct cmdprio *cmdprio,
204 struct cmdprio_options *options)
205{
206 struct thread_options *to = &td->o;
207 bool has_cmdprio_percentage = false;
208 bool has_cmdprio_bssplit = false;
209 int i;
210
211 cmdprio->options = options;
212
213 if (options->bssplit_str && strlen(options->bssplit_str))
214 has_cmdprio_bssplit = true;
215
216 for (i = 0; i < CMDPRIO_RWDIR_CNT; i++) {
217 if (options->percentage[i])
218 has_cmdprio_percentage = true;
219 }
220
e27b9ff0
NC
221 /*
222 * Check for option conflicts
223 */
224 if (has_cmdprio_percentage && has_cmdprio_bssplit) {
225 log_err("%s: cmdprio_percentage and cmdprio_bssplit options "
226 "are mutually exclusive\n",
227 to->name);
228 return 1;
229 }
230
97f2d484
NC
231 if (has_cmdprio_bssplit)
232 cmdprio->mode = CMDPRIO_MODE_BSSPLIT;
233 else if (has_cmdprio_percentage)
234 cmdprio->mode = CMDPRIO_MODE_PERC;
235 else
236 cmdprio->mode = CMDPRIO_MODE_NONE;
e27b9ff0 237
d6cbeab4
NC
238 /* Nothing left to do if cmdprio is not used */
239 if (cmdprio->mode == CMDPRIO_MODE_NONE)
240 return 0;
241
242 return fio_cmdprio_parse_and_gen(td, cmdprio);
e27b9ff0 243}