xref: /openbmc/qemu/tests/unit/test-throttle.c (revision b1be65f6)
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     <benoit.canet@nodalink.com>
9  *  Alberto Garcia   <berto@igalia.com>
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 "qemu/osdep.h"
16 #include <math.h>
17 #include "block/aio.h"
18 #include "qapi/error.h"
19 #include "qemu/throttle.h"
20 #include "qemu/error-report.h"
21 #include "qemu/main-loop.h"
22 #include "qemu/module.h"
23 #include "block/throttle-groups.h"
24 #include "sysemu/block-backend.h"
25 
26 static AioContext     *ctx;
27 static LeakyBucket    bkt;
28 static ThrottleConfig cfg;
29 static ThrottleGroupMember tgm;
30 static ThrottleState  ts;
31 static ThrottleTimers *tt;
32 
33 /* useful function */
34 static bool double_cmp(double x, double y)
35 {
36     return fabsl(x - y) < 1e-6;
37 }
38 
39 /* tests for single bucket operations */
40 static void test_leak_bucket(void)
41 {
42     throttle_config_init(&cfg);
43     bkt = cfg.buckets[THROTTLE_BPS_TOTAL];
44 
45     /* set initial value */
46     bkt.avg = 150;
47     bkt.max = 15;
48     bkt.level = 1.5;
49 
50     /* leak an op work of time */
51     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
52     g_assert(bkt.avg == 150);
53     g_assert(bkt.max == 15);
54     g_assert(double_cmp(bkt.level, 0.5));
55 
56     /* leak again emptying the bucket */
57     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
58     g_assert(bkt.avg == 150);
59     g_assert(bkt.max == 15);
60     g_assert(double_cmp(bkt.level, 0));
61 
62     /* check that the bucket level won't go lower */
63     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
64     g_assert(bkt.avg == 150);
65     g_assert(bkt.max == 15);
66     g_assert(double_cmp(bkt.level, 0));
67 
68     /* check that burst_level leaks correctly */
69     bkt.burst_level = 6;
70     bkt.max = 250;
71     bkt.burst_length = 2; /* otherwise burst_level will not leak */
72     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100);
73     g_assert(double_cmp(bkt.burst_level, 3.5));
74 
75     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100);
76     g_assert(double_cmp(bkt.burst_level, 1));
77 
78     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100);
79     g_assert(double_cmp(bkt.burst_level, 0));
80 
81     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100);
82     g_assert(double_cmp(bkt.burst_level, 0));
83 }
84 
85 static void test_compute_wait(void)
86 {
87     unsigned i;
88     int64_t wait;
89     int64_t result;
90 
91     throttle_config_init(&cfg);
92     bkt = cfg.buckets[THROTTLE_BPS_TOTAL];
93 
94     /* no operation limit set */
95     bkt.avg = 0;
96     bkt.max = 15;
97     bkt.level = 1.5;
98     wait = throttle_compute_wait(&bkt);
99     g_assert(!wait);
100 
101     /* zero delta */
102     bkt.avg = 150;
103     bkt.max = 15;
104     bkt.level = 15;
105     wait = throttle_compute_wait(&bkt);
106     g_assert(!wait);
107 
108     /* below zero delta */
109     bkt.avg = 150;
110     bkt.max = 15;
111     bkt.level = 9;
112     wait = throttle_compute_wait(&bkt);
113     g_assert(!wait);
114 
115     /* half an operation above max */
116     bkt.avg = 150;
117     bkt.max = 15;
118     bkt.level = 15.5;
119     wait = throttle_compute_wait(&bkt);
120     /* time required to do half an operation */
121     result = (int64_t)  NANOSECONDS_PER_SECOND / 150 / 2;
122     g_assert(wait == result);
123 
124     /* Perform I/O for 2.2 seconds at a rate of bkt.max */
125     bkt.burst_length = 2;
126     bkt.level = 0;
127     bkt.avg = 10;
128     bkt.max = 200;
129     for (i = 0; i < 22; i++) {
130         double units = bkt.max / 10;
131         bkt.level += units;
132         bkt.burst_level += units;
133         throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 10);
134         wait = throttle_compute_wait(&bkt);
135         g_assert(double_cmp(bkt.burst_level, 0));
136         g_assert(double_cmp(bkt.level, (i + 1) * (bkt.max - bkt.avg) / 10));
137         /* We can do bursts for the 2 seconds we have configured in
138          * burst_length. We have 100 extra milliseconds of burst
139          * because bkt.level has been leaking during this time.
140          * After that, we have to wait. */
141         result = i < 21 ? 0 : 1.8 * NANOSECONDS_PER_SECOND;
142         g_assert(wait == result);
143     }
144 }
145 
146 /* functions to test ThrottleState initialization/destroy methods */
147 static void read_timer_cb(void *opaque)
148 {
149 }
150 
151 static void write_timer_cb(void *opaque)
152 {
153 }
154 
155 static void test_init(void)
156 {
157     int i;
158 
159     tt = &tgm.throttle_timers;
160 
161     /* fill the structures with crap */
162     memset(&ts, 1, sizeof(ts));
163     memset(tt, 1, sizeof(*tt));
164 
165     /* init structures */
166     throttle_init(&ts);
167     throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
168                          read_timer_cb, write_timer_cb, &ts);
169 
170     /* check initialized fields */
171     g_assert(tt->clock_type == QEMU_CLOCK_VIRTUAL);
172     g_assert(tt->timers[THROTTLE_READ]);
173     g_assert(tt->timers[THROTTLE_WRITE]);
174 
175     /* check other fields where cleared */
176     g_assert(!ts.previous_leak);
177     g_assert(!ts.cfg.op_size);
178     for (i = 0; i < BUCKETS_COUNT; i++) {
179         g_assert(!ts.cfg.buckets[i].avg);
180         g_assert(!ts.cfg.buckets[i].max);
181         g_assert(!ts.cfg.buckets[i].level);
182     }
183 
184     throttle_timers_destroy(tt);
185 }
186 
187 static void test_init_readonly(void)
188 {
189     int i;
190 
191     tt = &tgm.throttle_timers;
192 
193     /* fill the structures with crap */
194     memset(&ts, 1, sizeof(ts));
195     memset(tt, 1, sizeof(*tt));
196 
197     /* init structures */
198     throttle_init(&ts);
199     throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
200                          read_timer_cb, NULL, &ts);
201 
202     /* check initialized fields */
203     g_assert(tt->clock_type == QEMU_CLOCK_VIRTUAL);
204     g_assert(tt->timers[THROTTLE_READ]);
205     g_assert(!tt->timers[THROTTLE_WRITE]);
206 
207     /* check other fields where cleared */
208     g_assert(!ts.previous_leak);
209     g_assert(!ts.cfg.op_size);
210     for (i = 0; i < BUCKETS_COUNT; i++) {
211         g_assert(!ts.cfg.buckets[i].avg);
212         g_assert(!ts.cfg.buckets[i].max);
213         g_assert(!ts.cfg.buckets[i].level);
214     }
215 
216     throttle_timers_destroy(tt);
217 }
218 
219 static void test_init_writeonly(void)
220 {
221     int i;
222 
223     tt = &tgm.throttle_timers;
224 
225     /* fill the structures with crap */
226     memset(&ts, 1, sizeof(ts));
227     memset(tt, 1, sizeof(*tt));
228 
229     /* init structures */
230     throttle_init(&ts);
231     throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
232                          NULL, write_timer_cb, &ts);
233 
234     /* check initialized fields */
235     g_assert(tt->clock_type == QEMU_CLOCK_VIRTUAL);
236     g_assert(!tt->timers[THROTTLE_READ]);
237     g_assert(tt->timers[THROTTLE_WRITE]);
238 
239     /* check other fields where cleared */
240     g_assert(!ts.previous_leak);
241     g_assert(!ts.cfg.op_size);
242     for (i = 0; i < BUCKETS_COUNT; i++) {
243         g_assert(!ts.cfg.buckets[i].avg);
244         g_assert(!ts.cfg.buckets[i].max);
245         g_assert(!ts.cfg.buckets[i].level);
246     }
247 
248     throttle_timers_destroy(tt);
249 }
250 
251 static void test_destroy(void)
252 {
253     int i;
254     throttle_init(&ts);
255     throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
256                          read_timer_cb, write_timer_cb, &ts);
257     throttle_timers_destroy(tt);
258     for (i = 0; i < THROTTLE_MAX; i++) {
259         g_assert(!tt->timers[i]);
260     }
261 }
262 
263 /* function to test throttle_config and throttle_get_config */
264 static void test_config_functions(void)
265 {
266     int i;
267     ThrottleConfig orig_cfg, final_cfg;
268 
269     orig_cfg.buckets[THROTTLE_BPS_TOTAL].avg = 153;
270     orig_cfg.buckets[THROTTLE_BPS_READ].avg  = 56;
271     orig_cfg.buckets[THROTTLE_BPS_WRITE].avg = 1;
272 
273     orig_cfg.buckets[THROTTLE_OPS_TOTAL].avg = 150;
274     orig_cfg.buckets[THROTTLE_OPS_READ].avg  = 69;
275     orig_cfg.buckets[THROTTLE_OPS_WRITE].avg = 23;
276 
277     orig_cfg.buckets[THROTTLE_BPS_TOTAL].max = 0;
278     orig_cfg.buckets[THROTTLE_BPS_READ].max  = 56;
279     orig_cfg.buckets[THROTTLE_BPS_WRITE].max = 120;
280 
281     orig_cfg.buckets[THROTTLE_OPS_TOTAL].max = 150;
282     orig_cfg.buckets[THROTTLE_OPS_READ].max  = 400;
283     orig_cfg.buckets[THROTTLE_OPS_WRITE].max = 500;
284 
285     orig_cfg.buckets[THROTTLE_BPS_TOTAL].level = 45;
286     orig_cfg.buckets[THROTTLE_BPS_READ].level  = 65;
287     orig_cfg.buckets[THROTTLE_BPS_WRITE].level = 23;
288 
289     orig_cfg.buckets[THROTTLE_OPS_TOTAL].level = 1;
290     orig_cfg.buckets[THROTTLE_OPS_READ].level  = 90;
291     orig_cfg.buckets[THROTTLE_OPS_WRITE].level = 75;
292 
293     orig_cfg.op_size = 1;
294 
295     throttle_init(&ts);
296     throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
297                          read_timer_cb, write_timer_cb, &ts);
298     /* structure reset by throttle_init previous_leak should be null */
299     g_assert(!ts.previous_leak);
300     throttle_config(&ts, QEMU_CLOCK_VIRTUAL, &orig_cfg);
301 
302     /* has previous leak been initialized by throttle_config ? */
303     g_assert(ts.previous_leak);
304 
305     /* get back the fixed configuration */
306     throttle_get_config(&ts, &final_cfg);
307 
308     throttle_timers_destroy(tt);
309 
310     g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].avg == 153);
311     g_assert(final_cfg.buckets[THROTTLE_BPS_READ].avg  == 56);
312     g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].avg == 1);
313 
314     g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].avg == 150);
315     g_assert(final_cfg.buckets[THROTTLE_OPS_READ].avg  == 69);
316     g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].avg == 23);
317 
318     g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].max == 0);
319     g_assert(final_cfg.buckets[THROTTLE_BPS_READ].max  == 56);
320     g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].max == 120);
321 
322     g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].max == 150);
323     g_assert(final_cfg.buckets[THROTTLE_OPS_READ].max  == 400);
324     g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].max == 500);
325 
326     g_assert(final_cfg.op_size == 1);
327 
328     /* check bucket have been cleared */
329     for (i = 0; i < BUCKETS_COUNT; i++) {
330         g_assert(!final_cfg.buckets[i].level);
331     }
332 }
333 
334 /* functions to test is throttle is enabled by a config */
335 static void set_cfg_value(bool is_max, int index, int value)
336 {
337     if (is_max) {
338         cfg.buckets[index].max = value;
339         /* If max is set, avg should never be 0 */
340         cfg.buckets[index].avg = MAX(cfg.buckets[index].avg, 1);
341     } else {
342         cfg.buckets[index].avg = value;
343     }
344 }
345 
346 static void test_enabled(void)
347 {
348     int i;
349 
350     throttle_config_init(&cfg);
351     g_assert(!throttle_enabled(&cfg));
352 
353     for (i = 0; i < BUCKETS_COUNT; i++) {
354         throttle_config_init(&cfg);
355         set_cfg_value(false, i, 150);
356         g_assert(throttle_is_valid(&cfg, NULL));
357         g_assert(throttle_enabled(&cfg));
358     }
359 
360     for (i = 0; i < BUCKETS_COUNT; i++) {
361         throttle_config_init(&cfg);
362         set_cfg_value(false, i, -150);
363         g_assert(!throttle_is_valid(&cfg, NULL));
364     }
365 }
366 
367 /* tests functions for throttle_conflicting */
368 
369 static void test_conflicts_for_one_set(bool is_max,
370                                        int total,
371                                        int read,
372                                        int write)
373 {
374     throttle_config_init(&cfg);
375     g_assert(throttle_is_valid(&cfg, NULL));
376 
377     set_cfg_value(is_max, total, 1);
378     set_cfg_value(is_max, read,  1);
379     g_assert(!throttle_is_valid(&cfg, NULL));
380 
381     throttle_config_init(&cfg);
382     set_cfg_value(is_max, total, 1);
383     set_cfg_value(is_max, write, 1);
384     g_assert(!throttle_is_valid(&cfg, NULL));
385 
386     throttle_config_init(&cfg);
387     set_cfg_value(is_max, total, 1);
388     set_cfg_value(is_max, read,  1);
389     set_cfg_value(is_max, write, 1);
390     g_assert(!throttle_is_valid(&cfg, NULL));
391 
392     throttle_config_init(&cfg);
393     set_cfg_value(is_max, total, 1);
394     g_assert(throttle_is_valid(&cfg, NULL));
395 
396     throttle_config_init(&cfg);
397     set_cfg_value(is_max, read,  1);
398     set_cfg_value(is_max, write, 1);
399     g_assert(throttle_is_valid(&cfg, NULL));
400 }
401 
402 static void test_conflicting_config(void)
403 {
404     /* bps average conflicts */
405     test_conflicts_for_one_set(false,
406                                THROTTLE_BPS_TOTAL,
407                                THROTTLE_BPS_READ,
408                                THROTTLE_BPS_WRITE);
409 
410     /* ops average conflicts */
411     test_conflicts_for_one_set(false,
412                                THROTTLE_OPS_TOTAL,
413                                THROTTLE_OPS_READ,
414                                THROTTLE_OPS_WRITE);
415 
416     /* bps average conflicts */
417     test_conflicts_for_one_set(true,
418                                THROTTLE_BPS_TOTAL,
419                                THROTTLE_BPS_READ,
420                                THROTTLE_BPS_WRITE);
421     /* ops average conflicts */
422     test_conflicts_for_one_set(true,
423                                THROTTLE_OPS_TOTAL,
424                                THROTTLE_OPS_READ,
425                                THROTTLE_OPS_WRITE);
426 }
427 /* functions to test the throttle_is_valid function */
428 static void test_is_valid_for_value(int value, bool should_be_valid)
429 {
430     int is_max, index;
431     for (is_max = 0; is_max < 2; is_max++) {
432         for (index = 0; index < BUCKETS_COUNT; index++) {
433             throttle_config_init(&cfg);
434             set_cfg_value(is_max, index, value);
435             g_assert(throttle_is_valid(&cfg, NULL) == should_be_valid);
436         }
437     }
438 }
439 
440 static void test_is_valid(void)
441 {
442     /* negative numbesr are invalid */
443     test_is_valid_for_value(-1, false);
444     /* zero is valid */
445     test_is_valid_for_value(0, true);
446     /* positives numbers are valid */
447     test_is_valid_for_value(1, true);
448 }
449 
450 static void test_ranges(void)
451 {
452     int i;
453 
454     for (i = 0; i < BUCKETS_COUNT; i++) {
455         LeakyBucket *b = &cfg.buckets[i];
456         throttle_config_init(&cfg);
457 
458         /* avg = 0 means throttling is disabled, but the config is valid */
459         b->avg = 0;
460         g_assert(throttle_is_valid(&cfg, NULL));
461         g_assert(!throttle_enabled(&cfg));
462 
463         /* These are valid configurations (values <= THROTTLE_VALUE_MAX) */
464         b->avg = 1;
465         g_assert(throttle_is_valid(&cfg, NULL));
466 
467         b->avg = THROTTLE_VALUE_MAX;
468         g_assert(throttle_is_valid(&cfg, NULL));
469 
470         b->avg = THROTTLE_VALUE_MAX;
471         b->max = THROTTLE_VALUE_MAX;
472         g_assert(throttle_is_valid(&cfg, NULL));
473 
474         /* Values over THROTTLE_VALUE_MAX are not allowed */
475         b->avg = THROTTLE_VALUE_MAX + 1;
476         g_assert(!throttle_is_valid(&cfg, NULL));
477 
478         b->avg = THROTTLE_VALUE_MAX;
479         b->max = THROTTLE_VALUE_MAX + 1;
480         g_assert(!throttle_is_valid(&cfg, NULL));
481 
482         /* burst_length must be between 1 and THROTTLE_VALUE_MAX */
483         b->avg = 1;
484         b->max = 1;
485         b->burst_length = 0;
486         g_assert(!throttle_is_valid(&cfg, NULL));
487 
488         b->avg = 1;
489         b->max = 1;
490         b->burst_length = 1;
491         g_assert(throttle_is_valid(&cfg, NULL));
492 
493         b->avg = 1;
494         b->max = 1;
495         b->burst_length = THROTTLE_VALUE_MAX;
496         g_assert(throttle_is_valid(&cfg, NULL));
497 
498         b->avg = 1;
499         b->max = 1;
500         b->burst_length = THROTTLE_VALUE_MAX + 1;
501         g_assert(!throttle_is_valid(&cfg, NULL));
502 
503         /* burst_length * max cannot exceed THROTTLE_VALUE_MAX */
504         b->avg = 1;
505         b->max = 2;
506         b->burst_length = THROTTLE_VALUE_MAX / 2;
507         g_assert(throttle_is_valid(&cfg, NULL));
508 
509         b->avg = 1;
510         b->max = 3;
511         b->burst_length = THROTTLE_VALUE_MAX / 2;
512         g_assert(!throttle_is_valid(&cfg, NULL));
513 
514         b->avg = 1;
515         b->max = THROTTLE_VALUE_MAX;
516         b->burst_length = 1;
517         g_assert(throttle_is_valid(&cfg, NULL));
518 
519         b->avg = 1;
520         b->max = THROTTLE_VALUE_MAX;
521         b->burst_length = 2;
522         g_assert(!throttle_is_valid(&cfg, NULL));
523     }
524 }
525 
526 static void test_max_is_missing_limit(void)
527 {
528     int i;
529 
530     for (i = 0; i < BUCKETS_COUNT; i++) {
531         throttle_config_init(&cfg);
532         cfg.buckets[i].max = 100;
533         cfg.buckets[i].avg = 0;
534         g_assert(!throttle_is_valid(&cfg, NULL));
535 
536         cfg.buckets[i].max = 0;
537         cfg.buckets[i].avg = 0;
538         g_assert(throttle_is_valid(&cfg, NULL));
539 
540         cfg.buckets[i].max = 0;
541         cfg.buckets[i].avg = 100;
542         g_assert(throttle_is_valid(&cfg, NULL));
543 
544         cfg.buckets[i].max = 30;
545         cfg.buckets[i].avg = 100;
546         g_assert(!throttle_is_valid(&cfg, NULL));
547 
548         cfg.buckets[i].max = 100;
549         cfg.buckets[i].avg = 100;
550         g_assert(throttle_is_valid(&cfg, NULL));
551     }
552 }
553 
554 static void test_iops_size_is_missing_limit(void)
555 {
556     /* A total/read/write iops limit is required */
557     throttle_config_init(&cfg);
558     cfg.op_size = 4096;
559     g_assert(!throttle_is_valid(&cfg, NULL));
560 }
561 
562 static void test_have_timer(void)
563 {
564     /* zero structures */
565     memset(&ts, 0, sizeof(ts));
566     memset(tt, 0, sizeof(*tt));
567 
568     /* no timer set should return false */
569     g_assert(!throttle_timers_are_initialized(tt));
570 
571     /* init structures */
572     throttle_init(&ts);
573     throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
574                          read_timer_cb, write_timer_cb, &ts);
575 
576     /* timer set by init should return true */
577     g_assert(throttle_timers_are_initialized(tt));
578 
579     throttle_timers_destroy(tt);
580 }
581 
582 static void test_detach_attach(void)
583 {
584     /* zero structures */
585     memset(&ts, 0, sizeof(ts));
586     memset(tt, 0, sizeof(*tt));
587 
588     /* init the structure */
589     throttle_init(&ts);
590     throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
591                          read_timer_cb, write_timer_cb, &ts);
592 
593     /* timer set by init should return true */
594     g_assert(throttle_timers_are_initialized(tt));
595 
596     /* timer should no longer exist after detaching */
597     throttle_timers_detach_aio_context(tt);
598     g_assert(!throttle_timers_are_initialized(tt));
599 
600     /* timer should exist again after attaching */
601     throttle_timers_attach_aio_context(tt, ctx);
602     g_assert(throttle_timers_are_initialized(tt));
603 
604     throttle_timers_destroy(tt);
605 }
606 
607 static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
608                 int size,                   /* size of the operation to do */
609                 double avg,                 /* io limit */
610                 uint64_t op_size,           /* ideal size of an io */
611                 double total_result,
612                 double read_result,
613                 double write_result)
614 {
615     BucketType to_test[2][3] = { { THROTTLE_BPS_TOTAL,
616                                    THROTTLE_BPS_READ,
617                                    THROTTLE_BPS_WRITE, },
618                                  { THROTTLE_OPS_TOTAL,
619                                    THROTTLE_OPS_READ,
620                                    THROTTLE_OPS_WRITE, } };
621     ThrottleConfig cfg;
622     BucketType index;
623     int i;
624 
625     throttle_config_init(&cfg);
626 
627     for (i = 0; i < 3; i++) {
628         index = to_test[is_ops][i];
629         cfg.buckets[index].avg = avg;
630     }
631 
632     cfg.op_size = op_size;
633 
634     throttle_init(&ts);
635     throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
636                          read_timer_cb, write_timer_cb, &ts);
637     throttle_config(&ts, QEMU_CLOCK_VIRTUAL, &cfg);
638 
639     /* account a read */
640     throttle_account(&ts, THROTTLE_READ, size);
641     /* account a write */
642     throttle_account(&ts, THROTTLE_WRITE, size);
643 
644     /* check total result */
645     index = to_test[is_ops][0];
646     if (!double_cmp(ts.cfg.buckets[index].level, total_result)) {
647         return false;
648     }
649 
650     /* check read result */
651     index = to_test[is_ops][1];
652     if (!double_cmp(ts.cfg.buckets[index].level, read_result)) {
653         return false;
654     }
655 
656     /* check write result */
657     index = to_test[is_ops][2];
658     if (!double_cmp(ts.cfg.buckets[index].level, write_result)) {
659         return false;
660     }
661 
662     throttle_timers_destroy(tt);
663 
664     return true;
665 }
666 
667 static void test_accounting(void)
668 {
669     /* tests for bps */
670 
671     /* op of size 1 */
672     g_assert(do_test_accounting(false,
673                                 1 * 512,
674                                 150,
675                                 0,
676                                 1024,
677                                 512,
678                                 512));
679 
680     /* op of size 2 */
681     g_assert(do_test_accounting(false,
682                                 2 * 512,
683                                 150,
684                                 0,
685                                 2048,
686                                 1024,
687                                 1024));
688 
689     /* op of size 2 and orthogonal parameter change */
690     g_assert(do_test_accounting(false,
691                                 2 * 512,
692                                 150,
693                                 17,
694                                 2048,
695                                 1024,
696                                 1024));
697 
698 
699     /* tests for ops */
700 
701     /* op of size 1 */
702     g_assert(do_test_accounting(true,
703                                 1 * 512,
704                                 150,
705                                 0,
706                                 2,
707                                 1,
708                                 1));
709 
710     /* op of size 2 */
711     g_assert(do_test_accounting(true,
712                                 2 *  512,
713                                 150,
714                                 0,
715                                 2,
716                                 1,
717                                 1));
718 
719     /* jumbo op accounting fragmentation : size 64 with op size of 13 units */
720     g_assert(do_test_accounting(true,
721                                 64 * 512,
722                                 150,
723                                 13 * 512,
724                                 (64.0 * 2) / 13,
725                                 (64.0 / 13),
726                                 (64.0 / 13)));
727 
728     /* same with orthogonal parameters changes */
729     g_assert(do_test_accounting(true,
730                                 64 * 512,
731                                 300,
732                                 13 * 512,
733                                 (64.0 * 2) / 13,
734                                 (64.0 / 13),
735                                 (64.0 / 13)));
736 }
737 
738 static void test_groups(void)
739 {
740     ThrottleConfig cfg1, cfg2;
741     BlockBackend *blk1, *blk2, *blk3;
742     BlockBackendPublic *blkp1, *blkp2, *blkp3;
743     ThrottleGroupMember *tgm1, *tgm2, *tgm3;
744 
745     /* No actual I/O is performed on these devices */
746     blk1 = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
747     blk2 = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
748     blk3 = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
749 
750     blkp1 = blk_get_public(blk1);
751     blkp2 = blk_get_public(blk2);
752     blkp3 = blk_get_public(blk3);
753 
754     tgm1 = &blkp1->throttle_group_member;
755     tgm2 = &blkp2->throttle_group_member;
756     tgm3 = &blkp3->throttle_group_member;
757 
758     g_assert(tgm1->throttle_state == NULL);
759     g_assert(tgm2->throttle_state == NULL);
760     g_assert(tgm3->throttle_state == NULL);
761 
762     throttle_group_register_tgm(tgm1, "bar", blk_get_aio_context(blk1));
763     throttle_group_register_tgm(tgm2, "foo", blk_get_aio_context(blk2));
764     throttle_group_register_tgm(tgm3, "bar", blk_get_aio_context(blk3));
765 
766     g_assert(tgm1->throttle_state != NULL);
767     g_assert(tgm2->throttle_state != NULL);
768     g_assert(tgm3->throttle_state != NULL);
769 
770     g_assert(!strcmp(throttle_group_get_name(tgm1), "bar"));
771     g_assert(!strcmp(throttle_group_get_name(tgm2), "foo"));
772     g_assert(tgm1->throttle_state == tgm3->throttle_state);
773 
774     /* Setting the config of a group member affects the whole group */
775     throttle_config_init(&cfg1);
776     cfg1.buckets[THROTTLE_BPS_READ].avg  = 500000;
777     cfg1.buckets[THROTTLE_BPS_WRITE].avg = 285000;
778     cfg1.buckets[THROTTLE_OPS_READ].avg  = 20000;
779     cfg1.buckets[THROTTLE_OPS_WRITE].avg = 12000;
780     throttle_group_config(tgm1, &cfg1);
781 
782     throttle_group_get_config(tgm1, &cfg1);
783     throttle_group_get_config(tgm3, &cfg2);
784     g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
785 
786     cfg2.buckets[THROTTLE_BPS_READ].avg  = 4547;
787     cfg2.buckets[THROTTLE_BPS_WRITE].avg = 1349;
788     cfg2.buckets[THROTTLE_OPS_READ].avg  = 123;
789     cfg2.buckets[THROTTLE_OPS_WRITE].avg = 86;
790     throttle_group_config(tgm3, &cfg1);
791 
792     throttle_group_get_config(tgm1, &cfg1);
793     throttle_group_get_config(tgm3, &cfg2);
794     g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
795 
796     throttle_group_unregister_tgm(tgm1);
797     throttle_group_unregister_tgm(tgm2);
798     throttle_group_unregister_tgm(tgm3);
799 
800     g_assert(tgm1->throttle_state == NULL);
801     g_assert(tgm2->throttle_state == NULL);
802     g_assert(tgm3->throttle_state == NULL);
803 }
804 
805 int main(int argc, char **argv)
806 {
807     qemu_init_main_loop(&error_fatal);
808     ctx = qemu_get_aio_context();
809     bdrv_init();
810     module_call_init(MODULE_INIT_QOM);
811 
812     do {} while (g_main_context_iteration(NULL, false));
813 
814     /* tests in the same order as the header function declarations */
815     g_test_init(&argc, &argv, NULL);
816     g_test_add_func("/throttle/leak_bucket",        test_leak_bucket);
817     g_test_add_func("/throttle/compute_wait",       test_compute_wait);
818     g_test_add_func("/throttle/init",               test_init);
819     g_test_add_func("/throttle/init_readonly",      test_init_readonly);
820     g_test_add_func("/throttle/init_writeonly",     test_init_writeonly);
821     g_test_add_func("/throttle/destroy",            test_destroy);
822     g_test_add_func("/throttle/have_timer",         test_have_timer);
823     g_test_add_func("/throttle/detach_attach",      test_detach_attach);
824     g_test_add_func("/throttle/config/enabled",     test_enabled);
825     g_test_add_func("/throttle/config/conflicting", test_conflicting_config);
826     g_test_add_func("/throttle/config/is_valid",    test_is_valid);
827     g_test_add_func("/throttle/config/ranges",      test_ranges);
828     g_test_add_func("/throttle/config/max",         test_max_is_missing_limit);
829     g_test_add_func("/throttle/config/iops_size",
830                     test_iops_size_is_missing_limit);
831     g_test_add_func("/throttle/config_functions",   test_config_functions);
832     g_test_add_func("/throttle/accounting",         test_accounting);
833     g_test_add_func("/throttle/groups",             test_groups);
834     return g_test_run();
835 }
836 
837