]> Git Repo - qemu.git/blob - tests/test-throttle.c
Merge remote-tracking branch 'remotes/ehabkost/tags/x86-pull-request' into staging
[qemu.git] / tests / test-throttle.c
1 /*
2  * Throttle infrastructure tests
3  *
4  * Copyright Nodalink, EURL. 2013-2014
5  * Copyright Igalia, S.L. 2015
6  *
7  * Authors:
8  *  BenoĆ®t Canet     <[email protected]>
9  *  Alberto Garcia   <[email protected]>
10  *
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.
13  */
14
15 #include <glib.h>
16 #include <math.h>
17 #include "block/aio.h"
18 #include "qemu/throttle.h"
19 #include "qemu/error-report.h"
20 #include "block/throttle-groups.h"
21
22 static AioContext     *ctx;
23 static LeakyBucket    bkt;
24 static ThrottleConfig cfg;
25 static ThrottleState  ts;
26 static ThrottleTimers tt;
27
28 /* useful function */
29 static bool double_cmp(double x, double y)
30 {
31     return fabsl(x - y) < 1e-6;
32 }
33
34 /* tests for single bucket operations */
35 static void test_leak_bucket(void)
36 {
37     /* set initial value */
38     bkt.avg = 150;
39     bkt.max = 15;
40     bkt.level = 1.5;
41
42     /* leak an op work of time */
43     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
44     g_assert(bkt.avg == 150);
45     g_assert(bkt.max == 15);
46     g_assert(double_cmp(bkt.level, 0.5));
47
48     /* leak again emptying the bucket */
49     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
50     g_assert(bkt.avg == 150);
51     g_assert(bkt.max == 15);
52     g_assert(double_cmp(bkt.level, 0));
53
54     /* check that the bucket level won't go lower */
55     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
56     g_assert(bkt.avg == 150);
57     g_assert(bkt.max == 15);
58     g_assert(double_cmp(bkt.level, 0));
59 }
60
61 static void test_compute_wait(void)
62 {
63     int64_t wait;
64     int64_t result;
65
66     /* no operation limit set */
67     bkt.avg = 0;
68     bkt.max = 15;
69     bkt.level = 1.5;
70     wait = throttle_compute_wait(&bkt);
71     g_assert(!wait);
72
73     /* zero delta */
74     bkt.avg = 150;
75     bkt.max = 15;
76     bkt.level = 15;
77     wait = throttle_compute_wait(&bkt);
78     g_assert(!wait);
79
80     /* below zero delta */
81     bkt.avg = 150;
82     bkt.max = 15;
83     bkt.level = 9;
84     wait = throttle_compute_wait(&bkt);
85     g_assert(!wait);
86
87     /* half an operation above max */
88     bkt.avg = 150;
89     bkt.max = 15;
90     bkt.level = 15.5;
91     wait = throttle_compute_wait(&bkt);
92     /* time required to do half an operation */
93     result = (int64_t)  NANOSECONDS_PER_SECOND / 150 / 2;
94     g_assert(wait == result);
95 }
96
97 /* functions to test ThrottleState initialization/destroy methods */
98 static void read_timer_cb(void *opaque)
99 {
100 }
101
102 static void write_timer_cb(void *opaque)
103 {
104 }
105
106 static void test_init(void)
107 {
108     int i;
109
110     /* fill the structures with crap */
111     memset(&ts, 1, sizeof(ts));
112     memset(&tt, 1, sizeof(tt));
113
114     /* init structures */
115     throttle_init(&ts);
116     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
117                          read_timer_cb, write_timer_cb, &ts);
118
119     /* check initialized fields */
120     g_assert(tt.clock_type == QEMU_CLOCK_VIRTUAL);
121     g_assert(tt.timers[0]);
122     g_assert(tt.timers[1]);
123
124     /* check other fields where cleared */
125     g_assert(!ts.previous_leak);
126     g_assert(!ts.cfg.op_size);
127     for (i = 0; i < BUCKETS_COUNT; i++) {
128         g_assert(!ts.cfg.buckets[i].avg);
129         g_assert(!ts.cfg.buckets[i].max);
130         g_assert(!ts.cfg.buckets[i].level);
131     }
132
133     throttle_timers_destroy(&tt);
134 }
135
136 static void test_destroy(void)
137 {
138     int i;
139     throttle_init(&ts);
140     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
141                          read_timer_cb, write_timer_cb, &ts);
142     throttle_timers_destroy(&tt);
143     for (i = 0; i < 2; i++) {
144         g_assert(!tt.timers[i]);
145     }
146 }
147
148 /* function to test throttle_config and throttle_get_config */
149 static void test_config_functions(void)
150 {
151     int i;
152     ThrottleConfig orig_cfg, final_cfg;
153
154     orig_cfg.buckets[THROTTLE_BPS_TOTAL].avg = 153;
155     orig_cfg.buckets[THROTTLE_BPS_READ].avg  = 56;
156     orig_cfg.buckets[THROTTLE_BPS_WRITE].avg = 1;
157
158     orig_cfg.buckets[THROTTLE_OPS_TOTAL].avg = 150;
159     orig_cfg.buckets[THROTTLE_OPS_READ].avg  = 69;
160     orig_cfg.buckets[THROTTLE_OPS_WRITE].avg = 23;
161
162     orig_cfg.buckets[THROTTLE_BPS_TOTAL].max = 0; /* should be corrected */
163     orig_cfg.buckets[THROTTLE_BPS_READ].max  = 1; /* should not be corrected */
164     orig_cfg.buckets[THROTTLE_BPS_WRITE].max = 120;
165
166     orig_cfg.buckets[THROTTLE_OPS_TOTAL].max = 150;
167     orig_cfg.buckets[THROTTLE_OPS_READ].max  = 400;
168     orig_cfg.buckets[THROTTLE_OPS_WRITE].max = 500;
169
170     orig_cfg.buckets[THROTTLE_BPS_TOTAL].level = 45;
171     orig_cfg.buckets[THROTTLE_BPS_READ].level  = 65;
172     orig_cfg.buckets[THROTTLE_BPS_WRITE].level = 23;
173
174     orig_cfg.buckets[THROTTLE_OPS_TOTAL].level = 1;
175     orig_cfg.buckets[THROTTLE_OPS_READ].level  = 90;
176     orig_cfg.buckets[THROTTLE_OPS_WRITE].level = 75;
177
178     orig_cfg.op_size = 1;
179
180     throttle_init(&ts);
181     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
182                          read_timer_cb, write_timer_cb, &ts);
183     /* structure reset by throttle_init previous_leak should be null */
184     g_assert(!ts.previous_leak);
185     throttle_config(&ts, &tt, &orig_cfg);
186
187     /* has previous leak been initialized by throttle_config ? */
188     g_assert(ts.previous_leak);
189
190     /* get back the fixed configuration */
191     throttle_get_config(&ts, &final_cfg);
192
193     throttle_timers_destroy(&tt);
194
195     g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].avg == 153);
196     g_assert(final_cfg.buckets[THROTTLE_BPS_READ].avg  == 56);
197     g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].avg == 1);
198
199     g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].avg == 150);
200     g_assert(final_cfg.buckets[THROTTLE_OPS_READ].avg  == 69);
201     g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].avg == 23);
202
203     g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].max == 15.3);/* fixed */
204     g_assert(final_cfg.buckets[THROTTLE_BPS_READ].max  == 1);   /* not fixed */
205     g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].max == 120);
206
207     g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].max == 150);
208     g_assert(final_cfg.buckets[THROTTLE_OPS_READ].max  == 400);
209     g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].max == 500);
210
211     g_assert(final_cfg.op_size == 1);
212
213     /* check bucket have been cleared */
214     for (i = 0; i < BUCKETS_COUNT; i++) {
215         g_assert(!final_cfg.buckets[i].level);
216     }
217 }
218
219 /* functions to test is throttle is enabled by a config */
220 static void set_cfg_value(bool is_max, int index, int value)
221 {
222     if (is_max) {
223         cfg.buckets[index].max = value;
224     } else {
225         cfg.buckets[index].avg = value;
226     }
227 }
228
229 static void test_enabled(void)
230 {
231     int i;
232
233     memset(&cfg, 0, sizeof(cfg));
234     g_assert(!throttle_enabled(&cfg));
235
236     for (i = 0; i < BUCKETS_COUNT; i++) {
237         memset(&cfg, 0, sizeof(cfg));
238         set_cfg_value(false, i, 150);
239         g_assert(throttle_enabled(&cfg));
240     }
241
242     for (i = 0; i < BUCKETS_COUNT; i++) {
243         memset(&cfg, 0, sizeof(cfg));
244         set_cfg_value(false, i, -150);
245         g_assert(!throttle_enabled(&cfg));
246     }
247 }
248
249 /* tests functions for throttle_conflicting */
250
251 static void test_conflicts_for_one_set(bool is_max,
252                                        int total,
253                                        int read,
254                                        int write)
255 {
256     memset(&cfg, 0, sizeof(cfg));
257     g_assert(!throttle_conflicting(&cfg));
258
259     set_cfg_value(is_max, total, 1);
260     set_cfg_value(is_max, read,  1);
261     g_assert(throttle_conflicting(&cfg));
262
263     memset(&cfg, 0, sizeof(cfg));
264     set_cfg_value(is_max, total, 1);
265     set_cfg_value(is_max, write, 1);
266     g_assert(throttle_conflicting(&cfg));
267
268     memset(&cfg, 0, sizeof(cfg));
269     set_cfg_value(is_max, total, 1);
270     set_cfg_value(is_max, read,  1);
271     set_cfg_value(is_max, write, 1);
272     g_assert(throttle_conflicting(&cfg));
273
274     memset(&cfg, 0, sizeof(cfg));
275     set_cfg_value(is_max, total, 1);
276     g_assert(!throttle_conflicting(&cfg));
277
278     memset(&cfg, 0, sizeof(cfg));
279     set_cfg_value(is_max, read,  1);
280     set_cfg_value(is_max, write, 1);
281     g_assert(!throttle_conflicting(&cfg));
282 }
283
284 static void test_conflicting_config(void)
285 {
286     /* bps average conflicts */
287     test_conflicts_for_one_set(false,
288                                THROTTLE_BPS_TOTAL,
289                                THROTTLE_BPS_READ,
290                                THROTTLE_BPS_WRITE);
291
292     /* ops average conflicts */
293     test_conflicts_for_one_set(false,
294                                THROTTLE_OPS_TOTAL,
295                                THROTTLE_OPS_READ,
296                                THROTTLE_OPS_WRITE);
297
298     /* bps average conflicts */
299     test_conflicts_for_one_set(true,
300                                THROTTLE_BPS_TOTAL,
301                                THROTTLE_BPS_READ,
302                                THROTTLE_BPS_WRITE);
303     /* ops average conflicts */
304     test_conflicts_for_one_set(true,
305                                THROTTLE_OPS_TOTAL,
306                                THROTTLE_OPS_READ,
307                                THROTTLE_OPS_WRITE);
308 }
309 /* functions to test the throttle_is_valid function */
310 static void test_is_valid_for_value(int value, bool should_be_valid)
311 {
312     int is_max, index;
313     for (is_max = 0; is_max < 2; is_max++) {
314         for (index = 0; index < BUCKETS_COUNT; index++) {
315             memset(&cfg, 0, sizeof(cfg));
316             set_cfg_value(is_max, index, value);
317             g_assert(throttle_is_valid(&cfg) == should_be_valid);
318         }
319     }
320 }
321
322 static void test_is_valid(void)
323 {
324     /* negative number are invalid */
325     test_is_valid_for_value(-1, false);
326     /* zero are valids */
327     test_is_valid_for_value(0, true);
328     /* positives numers are valids */
329     test_is_valid_for_value(1, true);
330 }
331
332 static void test_max_is_missing_limit(void)
333 {
334     int i;
335
336     for (i = 0; i < BUCKETS_COUNT; i++) {
337         memset(&cfg, 0, sizeof(cfg));
338         cfg.buckets[i].max = 100;
339         cfg.buckets[i].avg = 0;
340         g_assert(throttle_max_is_missing_limit(&cfg));
341
342         cfg.buckets[i].max = 0;
343         cfg.buckets[i].avg = 0;
344         g_assert(!throttle_max_is_missing_limit(&cfg));
345
346         cfg.buckets[i].max = 0;
347         cfg.buckets[i].avg = 100;
348         g_assert(!throttle_max_is_missing_limit(&cfg));
349     }
350 }
351
352 static void test_have_timer(void)
353 {
354     /* zero structures */
355     memset(&ts, 0, sizeof(ts));
356     memset(&tt, 0, sizeof(tt));
357
358     /* no timer set should return false */
359     g_assert(!throttle_timers_are_initialized(&tt));
360
361     /* init structures */
362     throttle_init(&ts);
363     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
364                          read_timer_cb, write_timer_cb, &ts);
365
366     /* timer set by init should return true */
367     g_assert(throttle_timers_are_initialized(&tt));
368
369     throttle_timers_destroy(&tt);
370 }
371
372 static void test_detach_attach(void)
373 {
374     /* zero structures */
375     memset(&ts, 0, sizeof(ts));
376     memset(&tt, 0, sizeof(tt));
377
378     /* init the structure */
379     throttle_init(&ts);
380     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
381                          read_timer_cb, write_timer_cb, &ts);
382
383     /* timer set by init should return true */
384     g_assert(throttle_timers_are_initialized(&tt));
385
386     /* timer should no longer exist after detaching */
387     throttle_timers_detach_aio_context(&tt);
388     g_assert(!throttle_timers_are_initialized(&tt));
389
390     /* timer should exist again after attaching */
391     throttle_timers_attach_aio_context(&tt, ctx);
392     g_assert(throttle_timers_are_initialized(&tt));
393
394     throttle_timers_destroy(&tt);
395 }
396
397 static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
398                 int size,                   /* size of the operation to do */
399                 double avg,                 /* io limit */
400                 uint64_t op_size,           /* ideal size of an io */
401                 double total_result,
402                 double read_result,
403                 double write_result)
404 {
405     BucketType to_test[2][3] = { { THROTTLE_BPS_TOTAL,
406                                    THROTTLE_BPS_READ,
407                                    THROTTLE_BPS_WRITE, },
408                                  { THROTTLE_OPS_TOTAL,
409                                    THROTTLE_OPS_READ,
410                                    THROTTLE_OPS_WRITE, } };
411     ThrottleConfig cfg;
412     BucketType index;
413     int i;
414
415     for (i = 0; i < 3; i++) {
416         BucketType index = to_test[is_ops][i];
417         cfg.buckets[index].avg = avg;
418     }
419
420     cfg.op_size = op_size;
421
422     throttle_init(&ts);
423     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
424                          read_timer_cb, write_timer_cb, &ts);
425     throttle_config(&ts, &tt, &cfg);
426
427     /* account a read */
428     throttle_account(&ts, false, size);
429     /* account a write */
430     throttle_account(&ts, true, size);
431
432     /* check total result */
433     index = to_test[is_ops][0];
434     if (!double_cmp(ts.cfg.buckets[index].level, total_result)) {
435         return false;
436     }
437
438     /* check read result */
439     index = to_test[is_ops][1];
440     if (!double_cmp(ts.cfg.buckets[index].level, read_result)) {
441         return false;
442     }
443
444     /* check write result */
445     index = to_test[is_ops][2];
446     if (!double_cmp(ts.cfg.buckets[index].level, write_result)) {
447         return false;
448     }
449
450     throttle_timers_destroy(&tt);
451
452     return true;
453 }
454
455 static void test_accounting(void)
456 {
457     /* tests for bps */
458
459     /* op of size 1 */
460     g_assert(do_test_accounting(false,
461                                 1 * 512,
462                                 150,
463                                 0,
464                                 1024,
465                                 512,
466                                 512));
467
468     /* op of size 2 */
469     g_assert(do_test_accounting(false,
470                                 2 * 512,
471                                 150,
472                                 0,
473                                 2048,
474                                 1024,
475                                 1024));
476
477     /* op of size 2 and orthogonal parameter change */
478     g_assert(do_test_accounting(false,
479                                 2 * 512,
480                                 150,
481                                 17,
482                                 2048,
483                                 1024,
484                                 1024));
485
486
487     /* tests for ops */
488
489     /* op of size 1 */
490     g_assert(do_test_accounting(true,
491                                 1 * 512,
492                                 150,
493                                 0,
494                                 2,
495                                 1,
496                                 1));
497
498     /* op of size 2 */
499     g_assert(do_test_accounting(true,
500                                 2 *  512,
501                                 150,
502                                 0,
503                                 2,
504                                 1,
505                                 1));
506
507     /* jumbo op accounting fragmentation : size 64 with op size of 13 units */
508     g_assert(do_test_accounting(true,
509                                 64 * 512,
510                                 150,
511                                 13 * 512,
512                                 (64.0 * 2) / 13,
513                                 (64.0 / 13),
514                                 (64.0 / 13)));
515
516     /* same with orthogonal parameters changes */
517     g_assert(do_test_accounting(true,
518                                 64 * 512,
519                                 300,
520                                 13 * 512,
521                                 (64.0 * 2) / 13,
522                                 (64.0 / 13),
523                                 (64.0 / 13)));
524 }
525
526 static void test_groups(void)
527 {
528     ThrottleConfig cfg1, cfg2;
529     BlockDriverState *bdrv1, *bdrv2, *bdrv3;
530
531     bdrv1 = bdrv_new();
532     bdrv2 = bdrv_new();
533     bdrv3 = bdrv_new();
534
535     g_assert(bdrv1->throttle_state == NULL);
536     g_assert(bdrv2->throttle_state == NULL);
537     g_assert(bdrv3->throttle_state == NULL);
538
539     throttle_group_register_bs(bdrv1, "bar");
540     throttle_group_register_bs(bdrv2, "foo");
541     throttle_group_register_bs(bdrv3, "bar");
542
543     g_assert(bdrv1->throttle_state != NULL);
544     g_assert(bdrv2->throttle_state != NULL);
545     g_assert(bdrv3->throttle_state != NULL);
546
547     g_assert(!strcmp(throttle_group_get_name(bdrv1), "bar"));
548     g_assert(!strcmp(throttle_group_get_name(bdrv2), "foo"));
549     g_assert(bdrv1->throttle_state == bdrv3->throttle_state);
550
551     /* Setting the config of a group member affects the whole group */
552     memset(&cfg1, 0, sizeof(cfg1));
553     cfg1.buckets[THROTTLE_BPS_READ].avg  = 500000;
554     cfg1.buckets[THROTTLE_BPS_WRITE].avg = 285000;
555     cfg1.buckets[THROTTLE_OPS_READ].avg  = 20000;
556     cfg1.buckets[THROTTLE_OPS_WRITE].avg = 12000;
557     throttle_group_config(bdrv1, &cfg1);
558
559     throttle_group_get_config(bdrv1, &cfg1);
560     throttle_group_get_config(bdrv3, &cfg2);
561     g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
562
563     cfg2.buckets[THROTTLE_BPS_READ].avg  = 4547;
564     cfg2.buckets[THROTTLE_BPS_WRITE].avg = 1349;
565     cfg2.buckets[THROTTLE_OPS_READ].avg  = 123;
566     cfg2.buckets[THROTTLE_OPS_WRITE].avg = 86;
567     throttle_group_config(bdrv3, &cfg1);
568
569     throttle_group_get_config(bdrv1, &cfg1);
570     throttle_group_get_config(bdrv3, &cfg2);
571     g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
572
573     throttle_group_unregister_bs(bdrv1);
574     throttle_group_unregister_bs(bdrv2);
575     throttle_group_unregister_bs(bdrv3);
576
577     g_assert(bdrv1->throttle_state == NULL);
578     g_assert(bdrv2->throttle_state == NULL);
579     g_assert(bdrv3->throttle_state == NULL);
580 }
581
582 int main(int argc, char **argv)
583 {
584     Error *local_error = NULL;
585
586     qemu_init_main_loop(&local_error);
587     ctx = qemu_get_aio_context();
588
589     if (!ctx) {
590         error_report("Failed to create AIO Context: '%s'",
591                      local_error ? error_get_pretty(local_error) :
592                      "Failed to initialize the QEMU main loop");
593         if (local_error) {
594             error_free(local_error);
595         }
596         exit(1);
597     }
598
599     bdrv_init();
600
601     do {} while (g_main_context_iteration(NULL, false));
602
603     /* tests in the same order as the header function declarations */
604     g_test_init(&argc, &argv, NULL);
605     g_test_add_func("/throttle/leak_bucket",        test_leak_bucket);
606     g_test_add_func("/throttle/compute_wait",       test_compute_wait);
607     g_test_add_func("/throttle/init",               test_init);
608     g_test_add_func("/throttle/destroy",            test_destroy);
609     g_test_add_func("/throttle/have_timer",         test_have_timer);
610     g_test_add_func("/throttle/detach_attach",      test_detach_attach);
611     g_test_add_func("/throttle/config/enabled",     test_enabled);
612     g_test_add_func("/throttle/config/conflicting", test_conflicting_config);
613     g_test_add_func("/throttle/config/is_valid",    test_is_valid);
614     g_test_add_func("/throttle/config/max",         test_max_is_missing_limit);
615     g_test_add_func("/throttle/config_functions",   test_config_functions);
616     g_test_add_func("/throttle/accounting",         test_accounting);
617     g_test_add_func("/throttle/groups",             test_groups);
618     return g_test_run();
619 }
620
This page took 0.05934 seconds and 4 git commands to generate.