qdev: Use error_abort instead of using local_err
[qemu/kevin.git] / tests / test-throttle.c
blob000ae31af92743f6a85a2a9a7bf19991853a9ed6
1 /*
2 * Throttle infrastructure tests
4 * Copyright Nodalink, SARL. 2013
6 * Authors:
7 * BenoƮt Canet <benoit.canet@irqsave.net>
9 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
10 * See the COPYING.LIB file in the top-level directory.
13 #include <glib.h>
14 #include <math.h>
15 #include "block/aio.h"
16 #include "qemu/throttle.h"
18 static AioContext *ctx;
19 static LeakyBucket bkt;
20 static ThrottleConfig cfg;
21 static ThrottleState ts;
23 /* useful function */
24 static bool double_cmp(double x, double y)
26 return fabsl(x - y) < 1e-6;
29 /* tests for single bucket operations */
30 static void test_leak_bucket(void)
32 /* set initial value */
33 bkt.avg = 150;
34 bkt.max = 15;
35 bkt.level = 1.5;
37 /* leak an op work of time */
38 throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
39 g_assert(bkt.avg == 150);
40 g_assert(bkt.max == 15);
41 g_assert(double_cmp(bkt.level, 0.5));
43 /* leak again emptying the bucket */
44 throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
45 g_assert(bkt.avg == 150);
46 g_assert(bkt.max == 15);
47 g_assert(double_cmp(bkt.level, 0));
49 /* check that the bucket level won't go lower */
50 throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
51 g_assert(bkt.avg == 150);
52 g_assert(bkt.max == 15);
53 g_assert(double_cmp(bkt.level, 0));
56 static void test_compute_wait(void)
58 int64_t wait;
59 int64_t result;
61 /* no operation limit set */
62 bkt.avg = 0;
63 bkt.max = 15;
64 bkt.level = 1.5;
65 wait = throttle_compute_wait(&bkt);
66 g_assert(!wait);
68 /* zero delta */
69 bkt.avg = 150;
70 bkt.max = 15;
71 bkt.level = 15;
72 wait = throttle_compute_wait(&bkt);
73 g_assert(!wait);
75 /* below zero delta */
76 bkt.avg = 150;
77 bkt.max = 15;
78 bkt.level = 9;
79 wait = throttle_compute_wait(&bkt);
80 g_assert(!wait);
82 /* half an operation above max */
83 bkt.avg = 150;
84 bkt.max = 15;
85 bkt.level = 15.5;
86 wait = throttle_compute_wait(&bkt);
87 /* time required to do half an operation */
88 result = (int64_t) NANOSECONDS_PER_SECOND / 150 / 2;
89 g_assert(wait == result);
92 /* functions to test ThrottleState initialization/destroy methods */
93 static void read_timer_cb(void *opaque)
97 static void write_timer_cb(void *opaque)
101 static void test_init(void)
103 int i;
105 /* fill the structure with crap */
106 memset(&ts, 1, sizeof(ts));
108 /* init the structure */
109 throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL,
110 read_timer_cb, write_timer_cb, &ts);
112 /* check initialized fields */
113 g_assert(ts.clock_type == QEMU_CLOCK_VIRTUAL);
114 g_assert(ts.timers[0]);
115 g_assert(ts.timers[1]);
117 /* check other fields where cleared */
118 g_assert(!ts.previous_leak);
119 g_assert(!ts.cfg.op_size);
120 for (i = 0; i < BUCKETS_COUNT; i++) {
121 g_assert(!ts.cfg.buckets[i].avg);
122 g_assert(!ts.cfg.buckets[i].max);
123 g_assert(!ts.cfg.buckets[i].level);
126 throttle_destroy(&ts);
129 static void test_destroy(void)
131 int i;
132 throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL,
133 read_timer_cb, write_timer_cb, &ts);
134 throttle_destroy(&ts);
135 for (i = 0; i < 2; i++) {
136 g_assert(!ts.timers[i]);
140 /* function to test throttle_config and throttle_get_config */
141 static void test_config_functions(void)
143 int i;
144 ThrottleConfig orig_cfg, final_cfg;
146 orig_cfg.buckets[THROTTLE_BPS_TOTAL].avg = 153;
147 orig_cfg.buckets[THROTTLE_BPS_READ].avg = 56;
148 orig_cfg.buckets[THROTTLE_BPS_WRITE].avg = 1;
150 orig_cfg.buckets[THROTTLE_OPS_TOTAL].avg = 150;
151 orig_cfg.buckets[THROTTLE_OPS_READ].avg = 69;
152 orig_cfg.buckets[THROTTLE_OPS_WRITE].avg = 23;
154 orig_cfg.buckets[THROTTLE_BPS_TOTAL].max = 0; /* should be corrected */
155 orig_cfg.buckets[THROTTLE_BPS_READ].max = 1; /* should not be corrected */
156 orig_cfg.buckets[THROTTLE_BPS_WRITE].max = 120;
158 orig_cfg.buckets[THROTTLE_OPS_TOTAL].max = 150;
159 orig_cfg.buckets[THROTTLE_OPS_READ].max = 400;
160 orig_cfg.buckets[THROTTLE_OPS_WRITE].max = 500;
162 orig_cfg.buckets[THROTTLE_BPS_TOTAL].level = 45;
163 orig_cfg.buckets[THROTTLE_BPS_READ].level = 65;
164 orig_cfg.buckets[THROTTLE_BPS_WRITE].level = 23;
166 orig_cfg.buckets[THROTTLE_OPS_TOTAL].level = 1;
167 orig_cfg.buckets[THROTTLE_OPS_READ].level = 90;
168 orig_cfg.buckets[THROTTLE_OPS_WRITE].level = 75;
170 orig_cfg.op_size = 1;
172 throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL,
173 read_timer_cb, write_timer_cb, &ts);
174 /* structure reset by throttle_init previous_leak should be null */
175 g_assert(!ts.previous_leak);
176 throttle_config(&ts, &orig_cfg);
178 /* has previous leak been initialized by throttle_config ? */
179 g_assert(ts.previous_leak);
181 /* get back the fixed configuration */
182 throttle_get_config(&ts, &final_cfg);
184 throttle_destroy(&ts);
186 g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].avg == 153);
187 g_assert(final_cfg.buckets[THROTTLE_BPS_READ].avg == 56);
188 g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].avg == 1);
190 g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].avg == 150);
191 g_assert(final_cfg.buckets[THROTTLE_OPS_READ].avg == 69);
192 g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].avg == 23);
194 g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].max == 15.3);/* fixed */
195 g_assert(final_cfg.buckets[THROTTLE_BPS_READ].max == 1); /* not fixed */
196 g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].max == 120);
198 g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].max == 150);
199 g_assert(final_cfg.buckets[THROTTLE_OPS_READ].max == 400);
200 g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].max == 500);
202 g_assert(final_cfg.op_size == 1);
204 /* check bucket have been cleared */
205 for (i = 0; i < BUCKETS_COUNT; i++) {
206 g_assert(!final_cfg.buckets[i].level);
210 /* functions to test is throttle is enabled by a config */
211 static void set_cfg_value(bool is_max, int index, int value)
213 if (is_max) {
214 cfg.buckets[index].max = value;
215 } else {
216 cfg.buckets[index].avg = value;
220 static void test_enabled(void)
222 int i;
224 memset(&cfg, 0, sizeof(cfg));
225 g_assert(!throttle_enabled(&cfg));
227 for (i = 0; i < BUCKETS_COUNT; i++) {
228 memset(&cfg, 0, sizeof(cfg));
229 set_cfg_value(false, i, 150);
230 g_assert(throttle_enabled(&cfg));
233 for (i = 0; i < BUCKETS_COUNT; i++) {
234 memset(&cfg, 0, sizeof(cfg));
235 set_cfg_value(false, i, -150);
236 g_assert(!throttle_enabled(&cfg));
240 /* tests functions for throttle_conflicting */
242 static void test_conflicts_for_one_set(bool is_max,
243 int total,
244 int read,
245 int write)
247 memset(&cfg, 0, sizeof(cfg));
248 g_assert(!throttle_conflicting(&cfg));
250 set_cfg_value(is_max, total, 1);
251 set_cfg_value(is_max, read, 1);
252 g_assert(throttle_conflicting(&cfg));
254 memset(&cfg, 0, sizeof(cfg));
255 set_cfg_value(is_max, total, 1);
256 set_cfg_value(is_max, write, 1);
257 g_assert(throttle_conflicting(&cfg));
259 memset(&cfg, 0, sizeof(cfg));
260 set_cfg_value(is_max, total, 1);
261 set_cfg_value(is_max, read, 1);
262 set_cfg_value(is_max, write, 1);
263 g_assert(throttle_conflicting(&cfg));
265 memset(&cfg, 0, sizeof(cfg));
266 set_cfg_value(is_max, total, 1);
267 g_assert(!throttle_conflicting(&cfg));
269 memset(&cfg, 0, sizeof(cfg));
270 set_cfg_value(is_max, read, 1);
271 set_cfg_value(is_max, write, 1);
272 g_assert(!throttle_conflicting(&cfg));
275 static void test_conflicting_config(void)
277 /* bps average conflicts */
278 test_conflicts_for_one_set(false,
279 THROTTLE_BPS_TOTAL,
280 THROTTLE_BPS_READ,
281 THROTTLE_BPS_WRITE);
283 /* ops average conflicts */
284 test_conflicts_for_one_set(false,
285 THROTTLE_OPS_TOTAL,
286 THROTTLE_OPS_READ,
287 THROTTLE_OPS_WRITE);
289 /* bps average conflicts */
290 test_conflicts_for_one_set(true,
291 THROTTLE_BPS_TOTAL,
292 THROTTLE_BPS_READ,
293 THROTTLE_BPS_WRITE);
294 /* ops average conflicts */
295 test_conflicts_for_one_set(true,
296 THROTTLE_OPS_TOTAL,
297 THROTTLE_OPS_READ,
298 THROTTLE_OPS_WRITE);
300 /* functions to test the throttle_is_valid function */
301 static void test_is_valid_for_value(int value, bool should_be_valid)
303 int is_max, index;
304 for (is_max = 0; is_max < 2; is_max++) {
305 for (index = 0; index < BUCKETS_COUNT; index++) {
306 memset(&cfg, 0, sizeof(cfg));
307 set_cfg_value(is_max, index, value);
308 g_assert(throttle_is_valid(&cfg) == should_be_valid);
313 static void test_is_valid(void)
315 /* negative number are invalid */
316 test_is_valid_for_value(-1, false);
317 /* zero are valids */
318 test_is_valid_for_value(0, true);
319 /* positives numers are valids */
320 test_is_valid_for_value(1, true);
323 static void test_have_timer(void)
325 /* zero the structure */
326 memset(&ts, 0, sizeof(ts));
328 /* no timer set should return false */
329 g_assert(!throttle_have_timer(&ts));
331 /* init the structure */
332 throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL,
333 read_timer_cb, write_timer_cb, &ts);
335 /* timer set by init should return true */
336 g_assert(throttle_have_timer(&ts));
338 throttle_destroy(&ts);
341 static void test_detach_attach(void)
343 /* zero the structure */
344 memset(&ts, 0, sizeof(ts));
346 /* init the structure */
347 throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL,
348 read_timer_cb, write_timer_cb, &ts);
350 /* timer set by init should return true */
351 g_assert(throttle_have_timer(&ts));
353 /* timer should no longer exist after detaching */
354 throttle_detach_aio_context(&ts);
355 g_assert(!throttle_have_timer(&ts));
357 /* timer should exist again after attaching */
358 throttle_attach_aio_context(&ts, ctx);
359 g_assert(throttle_have_timer(&ts));
361 throttle_destroy(&ts);
364 static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
365 int size, /* size of the operation to do */
366 double avg, /* io limit */
367 uint64_t op_size, /* ideal size of an io */
368 double total_result,
369 double read_result,
370 double write_result)
372 BucketType to_test[2][3] = { { THROTTLE_BPS_TOTAL,
373 THROTTLE_BPS_READ,
374 THROTTLE_BPS_WRITE, },
375 { THROTTLE_OPS_TOTAL,
376 THROTTLE_OPS_READ,
377 THROTTLE_OPS_WRITE, } };
378 ThrottleConfig cfg;
379 BucketType index;
380 int i;
382 for (i = 0; i < 3; i++) {
383 BucketType index = to_test[is_ops][i];
384 cfg.buckets[index].avg = avg;
387 cfg.op_size = op_size;
389 throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL,
390 read_timer_cb, write_timer_cb, &ts);
391 throttle_config(&ts, &cfg);
393 /* account a read */
394 throttle_account(&ts, false, size);
395 /* account a write */
396 throttle_account(&ts, true, size);
398 /* check total result */
399 index = to_test[is_ops][0];
400 if (!double_cmp(ts.cfg.buckets[index].level, total_result)) {
401 return false;
404 /* check read result */
405 index = to_test[is_ops][1];
406 if (!double_cmp(ts.cfg.buckets[index].level, read_result)) {
407 return false;
410 /* check write result */
411 index = to_test[is_ops][2];
412 if (!double_cmp(ts.cfg.buckets[index].level, write_result)) {
413 return false;
416 throttle_destroy(&ts);
418 return true;
421 static void test_accounting(void)
423 /* tests for bps */
425 /* op of size 1 */
426 g_assert(do_test_accounting(false,
427 1 * 512,
428 150,
430 1024,
431 512,
432 512));
434 /* op of size 2 */
435 g_assert(do_test_accounting(false,
436 2 * 512,
437 150,
439 2048,
440 1024,
441 1024));
443 /* op of size 2 and orthogonal parameter change */
444 g_assert(do_test_accounting(false,
445 2 * 512,
446 150,
448 2048,
449 1024,
450 1024));
453 /* tests for ops */
455 /* op of size 1 */
456 g_assert(do_test_accounting(true,
457 1 * 512,
458 150,
462 1));
464 /* op of size 2 */
465 g_assert(do_test_accounting(true,
466 2 * 512,
467 150,
471 1));
473 /* jumbo op accounting fragmentation : size 64 with op size of 13 units */
474 g_assert(do_test_accounting(true,
475 64 * 512,
476 150,
477 13 * 512,
478 (64.0 * 2) / 13,
479 (64.0 / 13),
480 (64.0 / 13)));
482 /* same with orthogonal parameters changes */
483 g_assert(do_test_accounting(true,
484 64 * 512,
485 300,
486 13 * 512,
487 (64.0 * 2) / 13,
488 (64.0 / 13),
489 (64.0 / 13)));
492 int main(int argc, char **argv)
494 GSource *src;
496 init_clocks();
498 ctx = aio_context_new();
499 src = aio_get_g_source(ctx);
500 g_source_attach(src, NULL);
501 g_source_unref(src);
503 do {} while (g_main_context_iteration(NULL, false));
505 /* tests in the same order as the header function declarations */
506 g_test_init(&argc, &argv, NULL);
507 g_test_add_func("/throttle/leak_bucket", test_leak_bucket);
508 g_test_add_func("/throttle/compute_wait", test_compute_wait);
509 g_test_add_func("/throttle/init", test_init);
510 g_test_add_func("/throttle/destroy", test_destroy);
511 g_test_add_func("/throttle/have_timer", test_have_timer);
512 g_test_add_func("/throttle/detach_attach", test_detach_attach);
513 g_test_add_func("/throttle/config/enabled", test_enabled);
514 g_test_add_func("/throttle/config/conflicting", test_conflicting_config);
515 g_test_add_func("/throttle/config/is_valid", test_is_valid);
516 g_test_add_func("/throttle/config_functions", test_config_functions);
517 g_test_add_func("/throttle/accounting", test_accounting);
518 return g_test_run();