throttle: Merge all functions that check the configuration into one
[qemu/ar7.git] / tests / test-throttle.c
bloba0c17ac4883f56ba82fd0a273c43a0fc3bd45f66
1 /*
2 * Throttle infrastructure tests
4 * Copyright Nodalink, EURL. 2013-2014
5 * Copyright Igalia, S.L. 2015
7 * Authors:
8 * BenoƮt Canet <benoit.canet@nodalink.com>
9 * Alberto Garcia <berto@igalia.com>
11 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
12 * See the COPYING.LIB file in the top-level directory.
15 #include "qemu/osdep.h"
16 #include <glib.h>
17 #include <math.h>
18 #include "block/aio.h"
19 #include "qemu/throttle.h"
20 #include "qemu/error-report.h"
21 #include "block/throttle-groups.h"
23 static AioContext *ctx;
24 static LeakyBucket bkt;
25 static ThrottleConfig cfg;
26 static ThrottleState ts;
27 static ThrottleTimers tt;
29 /* useful function */
30 static bool double_cmp(double x, double y)
32 return fabsl(x - y) < 1e-6;
35 /* tests for single bucket operations */
36 static void test_leak_bucket(void)
38 /* set initial value */
39 bkt.avg = 150;
40 bkt.max = 15;
41 bkt.level = 1.5;
43 /* leak an op work of time */
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.5));
49 /* leak again emptying the bucket */
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));
55 /* check that the bucket level won't go lower */
56 throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
57 g_assert(bkt.avg == 150);
58 g_assert(bkt.max == 15);
59 g_assert(double_cmp(bkt.level, 0));
62 static void test_compute_wait(void)
64 int64_t wait;
65 int64_t result;
67 /* no operation limit set */
68 bkt.avg = 0;
69 bkt.max = 15;
70 bkt.level = 1.5;
71 wait = throttle_compute_wait(&bkt);
72 g_assert(!wait);
74 /* zero delta */
75 bkt.avg = 150;
76 bkt.max = 15;
77 bkt.level = 15;
78 wait = throttle_compute_wait(&bkt);
79 g_assert(!wait);
81 /* below zero delta */
82 bkt.avg = 150;
83 bkt.max = 15;
84 bkt.level = 9;
85 wait = throttle_compute_wait(&bkt);
86 g_assert(!wait);
88 /* half an operation above max */
89 bkt.avg = 150;
90 bkt.max = 15;
91 bkt.level = 15.5;
92 wait = throttle_compute_wait(&bkt);
93 /* time required to do half an operation */
94 result = (int64_t) NANOSECONDS_PER_SECOND / 150 / 2;
95 g_assert(wait == result);
98 /* functions to test ThrottleState initialization/destroy methods */
99 static void read_timer_cb(void *opaque)
103 static void write_timer_cb(void *opaque)
107 static void test_init(void)
109 int i;
111 /* fill the structures with crap */
112 memset(&ts, 1, sizeof(ts));
113 memset(&tt, 1, sizeof(tt));
115 /* init structures */
116 throttle_init(&ts);
117 throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
118 read_timer_cb, write_timer_cb, &ts);
120 /* check initialized fields */
121 g_assert(tt.clock_type == QEMU_CLOCK_VIRTUAL);
122 g_assert(tt.timers[0]);
123 g_assert(tt.timers[1]);
125 /* check other fields where cleared */
126 g_assert(!ts.previous_leak);
127 g_assert(!ts.cfg.op_size);
128 for (i = 0; i < BUCKETS_COUNT; i++) {
129 g_assert(!ts.cfg.buckets[i].avg);
130 g_assert(!ts.cfg.buckets[i].max);
131 g_assert(!ts.cfg.buckets[i].level);
134 throttle_timers_destroy(&tt);
137 static void test_destroy(void)
139 int i;
140 throttle_init(&ts);
141 throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
142 read_timer_cb, write_timer_cb, &ts);
143 throttle_timers_destroy(&tt);
144 for (i = 0; i < 2; i++) {
145 g_assert(!tt.timers[i]);
149 /* function to test throttle_config and throttle_get_config */
150 static void test_config_functions(void)
152 int i;
153 ThrottleConfig orig_cfg, final_cfg;
155 orig_cfg.buckets[THROTTLE_BPS_TOTAL].avg = 153;
156 orig_cfg.buckets[THROTTLE_BPS_READ].avg = 56;
157 orig_cfg.buckets[THROTTLE_BPS_WRITE].avg = 1;
159 orig_cfg.buckets[THROTTLE_OPS_TOTAL].avg = 150;
160 orig_cfg.buckets[THROTTLE_OPS_READ].avg = 69;
161 orig_cfg.buckets[THROTTLE_OPS_WRITE].avg = 23;
163 orig_cfg.buckets[THROTTLE_BPS_TOTAL].max = 0; /* should be corrected */
164 orig_cfg.buckets[THROTTLE_BPS_READ].max = 1; /* should not be corrected */
165 orig_cfg.buckets[THROTTLE_BPS_WRITE].max = 120;
167 orig_cfg.buckets[THROTTLE_OPS_TOTAL].max = 150;
168 orig_cfg.buckets[THROTTLE_OPS_READ].max = 400;
169 orig_cfg.buckets[THROTTLE_OPS_WRITE].max = 500;
171 orig_cfg.buckets[THROTTLE_BPS_TOTAL].level = 45;
172 orig_cfg.buckets[THROTTLE_BPS_READ].level = 65;
173 orig_cfg.buckets[THROTTLE_BPS_WRITE].level = 23;
175 orig_cfg.buckets[THROTTLE_OPS_TOTAL].level = 1;
176 orig_cfg.buckets[THROTTLE_OPS_READ].level = 90;
177 orig_cfg.buckets[THROTTLE_OPS_WRITE].level = 75;
179 orig_cfg.op_size = 1;
181 throttle_init(&ts);
182 throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
183 read_timer_cb, write_timer_cb, &ts);
184 /* structure reset by throttle_init previous_leak should be null */
185 g_assert(!ts.previous_leak);
186 throttle_config(&ts, &tt, &orig_cfg);
188 /* has previous leak been initialized by throttle_config ? */
189 g_assert(ts.previous_leak);
191 /* get back the fixed configuration */
192 throttle_get_config(&ts, &final_cfg);
194 throttle_timers_destroy(&tt);
196 g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].avg == 153);
197 g_assert(final_cfg.buckets[THROTTLE_BPS_READ].avg == 56);
198 g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].avg == 1);
200 g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].avg == 150);
201 g_assert(final_cfg.buckets[THROTTLE_OPS_READ].avg == 69);
202 g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].avg == 23);
204 g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].max == 15.3);/* fixed */
205 g_assert(final_cfg.buckets[THROTTLE_BPS_READ].max == 1); /* not fixed */
206 g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].max == 120);
208 g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].max == 150);
209 g_assert(final_cfg.buckets[THROTTLE_OPS_READ].max == 400);
210 g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].max == 500);
212 g_assert(final_cfg.op_size == 1);
214 /* check bucket have been cleared */
215 for (i = 0; i < BUCKETS_COUNT; i++) {
216 g_assert(!final_cfg.buckets[i].level);
220 /* functions to test is throttle is enabled by a config */
221 static void set_cfg_value(bool is_max, int index, int value)
223 if (is_max) {
224 cfg.buckets[index].max = value;
225 /* If max is set, avg should never be 0 */
226 cfg.buckets[index].avg = MAX(cfg.buckets[index].avg, 1);
227 } else {
228 cfg.buckets[index].avg = value;
232 static void test_enabled(void)
234 int i;
236 memset(&cfg, 0, sizeof(cfg));
237 g_assert(!throttle_enabled(&cfg));
239 for (i = 0; i < BUCKETS_COUNT; i++) {
240 memset(&cfg, 0, sizeof(cfg));
241 set_cfg_value(false, i, 150);
242 g_assert(throttle_enabled(&cfg));
245 for (i = 0; i < BUCKETS_COUNT; i++) {
246 memset(&cfg, 0, sizeof(cfg));
247 set_cfg_value(false, i, -150);
248 g_assert(!throttle_enabled(&cfg));
252 /* tests functions for throttle_conflicting */
254 static void test_conflicts_for_one_set(bool is_max,
255 int total,
256 int read,
257 int write)
259 memset(&cfg, 0, sizeof(cfg));
260 g_assert(throttle_is_valid(&cfg, NULL));
262 set_cfg_value(is_max, total, 1);
263 set_cfg_value(is_max, read, 1);
264 g_assert(!throttle_is_valid(&cfg, NULL));
266 memset(&cfg, 0, sizeof(cfg));
267 set_cfg_value(is_max, total, 1);
268 set_cfg_value(is_max, write, 1);
269 g_assert(!throttle_is_valid(&cfg, NULL));
271 memset(&cfg, 0, sizeof(cfg));
272 set_cfg_value(is_max, total, 1);
273 set_cfg_value(is_max, read, 1);
274 set_cfg_value(is_max, write, 1);
275 g_assert(!throttle_is_valid(&cfg, NULL));
277 memset(&cfg, 0, sizeof(cfg));
278 set_cfg_value(is_max, total, 1);
279 g_assert(throttle_is_valid(&cfg, NULL));
281 memset(&cfg, 0, sizeof(cfg));
282 set_cfg_value(is_max, read, 1);
283 set_cfg_value(is_max, write, 1);
284 g_assert(throttle_is_valid(&cfg, NULL));
287 static void test_conflicting_config(void)
289 /* bps average conflicts */
290 test_conflicts_for_one_set(false,
291 THROTTLE_BPS_TOTAL,
292 THROTTLE_BPS_READ,
293 THROTTLE_BPS_WRITE);
295 /* ops average conflicts */
296 test_conflicts_for_one_set(false,
297 THROTTLE_OPS_TOTAL,
298 THROTTLE_OPS_READ,
299 THROTTLE_OPS_WRITE);
301 /* bps average conflicts */
302 test_conflicts_for_one_set(true,
303 THROTTLE_BPS_TOTAL,
304 THROTTLE_BPS_READ,
305 THROTTLE_BPS_WRITE);
306 /* ops average conflicts */
307 test_conflicts_for_one_set(true,
308 THROTTLE_OPS_TOTAL,
309 THROTTLE_OPS_READ,
310 THROTTLE_OPS_WRITE);
312 /* functions to test the throttle_is_valid function */
313 static void test_is_valid_for_value(int value, bool should_be_valid)
315 int is_max, index;
316 for (is_max = 0; is_max < 2; is_max++) {
317 for (index = 0; index < BUCKETS_COUNT; index++) {
318 memset(&cfg, 0, sizeof(cfg));
319 set_cfg_value(is_max, index, value);
320 g_assert(throttle_is_valid(&cfg, NULL) == should_be_valid);
325 static void test_is_valid(void)
327 /* negative number are invalid */
328 test_is_valid_for_value(-1, false);
329 /* zero are valids */
330 test_is_valid_for_value(0, true);
331 /* positives numers are valids */
332 test_is_valid_for_value(1, true);
335 static void test_max_is_missing_limit(void)
337 int i;
339 for (i = 0; i < BUCKETS_COUNT; i++) {
340 memset(&cfg, 0, sizeof(cfg));
341 cfg.buckets[i].max = 100;
342 cfg.buckets[i].avg = 0;
343 g_assert(!throttle_is_valid(&cfg, NULL));
345 cfg.buckets[i].max = 0;
346 cfg.buckets[i].avg = 0;
347 g_assert(throttle_is_valid(&cfg, NULL));
349 cfg.buckets[i].max = 0;
350 cfg.buckets[i].avg = 100;
351 g_assert(throttle_is_valid(&cfg, NULL));
355 static void test_have_timer(void)
357 /* zero structures */
358 memset(&ts, 0, sizeof(ts));
359 memset(&tt, 0, sizeof(tt));
361 /* no timer set should return false */
362 g_assert(!throttle_timers_are_initialized(&tt));
364 /* init structures */
365 throttle_init(&ts);
366 throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
367 read_timer_cb, write_timer_cb, &ts);
369 /* timer set by init should return true */
370 g_assert(throttle_timers_are_initialized(&tt));
372 throttle_timers_destroy(&tt);
375 static void test_detach_attach(void)
377 /* zero structures */
378 memset(&ts, 0, sizeof(ts));
379 memset(&tt, 0, sizeof(tt));
381 /* init the structure */
382 throttle_init(&ts);
383 throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
384 read_timer_cb, write_timer_cb, &ts);
386 /* timer set by init should return true */
387 g_assert(throttle_timers_are_initialized(&tt));
389 /* timer should no longer exist after detaching */
390 throttle_timers_detach_aio_context(&tt);
391 g_assert(!throttle_timers_are_initialized(&tt));
393 /* timer should exist again after attaching */
394 throttle_timers_attach_aio_context(&tt, ctx);
395 g_assert(throttle_timers_are_initialized(&tt));
397 throttle_timers_destroy(&tt);
400 static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
401 int size, /* size of the operation to do */
402 double avg, /* io limit */
403 uint64_t op_size, /* ideal size of an io */
404 double total_result,
405 double read_result,
406 double write_result)
408 BucketType to_test[2][3] = { { THROTTLE_BPS_TOTAL,
409 THROTTLE_BPS_READ,
410 THROTTLE_BPS_WRITE, },
411 { THROTTLE_OPS_TOTAL,
412 THROTTLE_OPS_READ,
413 THROTTLE_OPS_WRITE, } };
414 ThrottleConfig cfg;
415 BucketType index;
416 int i;
418 for (i = 0; i < 3; i++) {
419 BucketType index = to_test[is_ops][i];
420 cfg.buckets[index].avg = avg;
423 cfg.op_size = op_size;
425 throttle_init(&ts);
426 throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
427 read_timer_cb, write_timer_cb, &ts);
428 throttle_config(&ts, &tt, &cfg);
430 /* account a read */
431 throttle_account(&ts, false, size);
432 /* account a write */
433 throttle_account(&ts, true, size);
435 /* check total result */
436 index = to_test[is_ops][0];
437 if (!double_cmp(ts.cfg.buckets[index].level, total_result)) {
438 return false;
441 /* check read result */
442 index = to_test[is_ops][1];
443 if (!double_cmp(ts.cfg.buckets[index].level, read_result)) {
444 return false;
447 /* check write result */
448 index = to_test[is_ops][2];
449 if (!double_cmp(ts.cfg.buckets[index].level, write_result)) {
450 return false;
453 throttle_timers_destroy(&tt);
455 return true;
458 static void test_accounting(void)
460 /* tests for bps */
462 /* op of size 1 */
463 g_assert(do_test_accounting(false,
464 1 * 512,
465 150,
467 1024,
468 512,
469 512));
471 /* op of size 2 */
472 g_assert(do_test_accounting(false,
473 2 * 512,
474 150,
476 2048,
477 1024,
478 1024));
480 /* op of size 2 and orthogonal parameter change */
481 g_assert(do_test_accounting(false,
482 2 * 512,
483 150,
485 2048,
486 1024,
487 1024));
490 /* tests for ops */
492 /* op of size 1 */
493 g_assert(do_test_accounting(true,
494 1 * 512,
495 150,
499 1));
501 /* op of size 2 */
502 g_assert(do_test_accounting(true,
503 2 * 512,
504 150,
508 1));
510 /* jumbo op accounting fragmentation : size 64 with op size of 13 units */
511 g_assert(do_test_accounting(true,
512 64 * 512,
513 150,
514 13 * 512,
515 (64.0 * 2) / 13,
516 (64.0 / 13),
517 (64.0 / 13)));
519 /* same with orthogonal parameters changes */
520 g_assert(do_test_accounting(true,
521 64 * 512,
522 300,
523 13 * 512,
524 (64.0 * 2) / 13,
525 (64.0 / 13),
526 (64.0 / 13)));
529 static void test_groups(void)
531 ThrottleConfig cfg1, cfg2;
532 BlockDriverState *bdrv1, *bdrv2, *bdrv3;
534 bdrv1 = bdrv_new();
535 bdrv2 = bdrv_new();
536 bdrv3 = bdrv_new();
538 g_assert(bdrv1->throttle_state == NULL);
539 g_assert(bdrv2->throttle_state == NULL);
540 g_assert(bdrv3->throttle_state == NULL);
542 throttle_group_register_bs(bdrv1, "bar");
543 throttle_group_register_bs(bdrv2, "foo");
544 throttle_group_register_bs(bdrv3, "bar");
546 g_assert(bdrv1->throttle_state != NULL);
547 g_assert(bdrv2->throttle_state != NULL);
548 g_assert(bdrv3->throttle_state != NULL);
550 g_assert(!strcmp(throttle_group_get_name(bdrv1), "bar"));
551 g_assert(!strcmp(throttle_group_get_name(bdrv2), "foo"));
552 g_assert(bdrv1->throttle_state == bdrv3->throttle_state);
554 /* Setting the config of a group member affects the whole group */
555 memset(&cfg1, 0, sizeof(cfg1));
556 cfg1.buckets[THROTTLE_BPS_READ].avg = 500000;
557 cfg1.buckets[THROTTLE_BPS_WRITE].avg = 285000;
558 cfg1.buckets[THROTTLE_OPS_READ].avg = 20000;
559 cfg1.buckets[THROTTLE_OPS_WRITE].avg = 12000;
560 throttle_group_config(bdrv1, &cfg1);
562 throttle_group_get_config(bdrv1, &cfg1);
563 throttle_group_get_config(bdrv3, &cfg2);
564 g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
566 cfg2.buckets[THROTTLE_BPS_READ].avg = 4547;
567 cfg2.buckets[THROTTLE_BPS_WRITE].avg = 1349;
568 cfg2.buckets[THROTTLE_OPS_READ].avg = 123;
569 cfg2.buckets[THROTTLE_OPS_WRITE].avg = 86;
570 throttle_group_config(bdrv3, &cfg1);
572 throttle_group_get_config(bdrv1, &cfg1);
573 throttle_group_get_config(bdrv3, &cfg2);
574 g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
576 throttle_group_unregister_bs(bdrv1);
577 throttle_group_unregister_bs(bdrv2);
578 throttle_group_unregister_bs(bdrv3);
580 g_assert(bdrv1->throttle_state == NULL);
581 g_assert(bdrv2->throttle_state == NULL);
582 g_assert(bdrv3->throttle_state == NULL);
585 int main(int argc, char **argv)
587 qemu_init_main_loop(&error_fatal);
588 ctx = qemu_get_aio_context();
589 bdrv_init();
591 do {} while (g_main_context_iteration(NULL, false));
593 /* tests in the same order as the header function declarations */
594 g_test_init(&argc, &argv, NULL);
595 g_test_add_func("/throttle/leak_bucket", test_leak_bucket);
596 g_test_add_func("/throttle/compute_wait", test_compute_wait);
597 g_test_add_func("/throttle/init", test_init);
598 g_test_add_func("/throttle/destroy", test_destroy);
599 g_test_add_func("/throttle/have_timer", test_have_timer);
600 g_test_add_func("/throttle/detach_attach", test_detach_attach);
601 g_test_add_func("/throttle/config/enabled", test_enabled);
602 g_test_add_func("/throttle/config/conflicting", test_conflicting_config);
603 g_test_add_func("/throttle/config/is_valid", test_is_valid);
604 g_test_add_func("/throttle/config/max", test_max_is_missing_limit);
605 g_test_add_func("/throttle/config_functions", test_config_functions);
606 g_test_add_func("/throttle/accounting", test_accounting);
607 g_test_add_func("/throttle/groups", test_groups);
608 return g_test_run();