xref: /openbmc/qemu/tests/unit/test-throttle.c (revision 782ee711)
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[0]);
173     g_assert(tt->timers[1]);
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_destroy(void)
188 {
189     int i;
190     throttle_init(&ts);
191     throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
192                          read_timer_cb, write_timer_cb, &ts);
193     throttle_timers_destroy(tt);
194     for (i = 0; i < 2; i++) {
195         g_assert(!tt->timers[i]);
196     }
197 }
198 
199 /* function to test throttle_config and throttle_get_config */
200 static void test_config_functions(void)
201 {
202     int i;
203     ThrottleConfig orig_cfg, final_cfg;
204 
205     orig_cfg.buckets[THROTTLE_BPS_TOTAL].avg = 153;
206     orig_cfg.buckets[THROTTLE_BPS_READ].avg  = 56;
207     orig_cfg.buckets[THROTTLE_BPS_WRITE].avg = 1;
208 
209     orig_cfg.buckets[THROTTLE_OPS_TOTAL].avg = 150;
210     orig_cfg.buckets[THROTTLE_OPS_READ].avg  = 69;
211     orig_cfg.buckets[THROTTLE_OPS_WRITE].avg = 23;
212 
213     orig_cfg.buckets[THROTTLE_BPS_TOTAL].max = 0;
214     orig_cfg.buckets[THROTTLE_BPS_READ].max  = 56;
215     orig_cfg.buckets[THROTTLE_BPS_WRITE].max = 120;
216 
217     orig_cfg.buckets[THROTTLE_OPS_TOTAL].max = 150;
218     orig_cfg.buckets[THROTTLE_OPS_READ].max  = 400;
219     orig_cfg.buckets[THROTTLE_OPS_WRITE].max = 500;
220 
221     orig_cfg.buckets[THROTTLE_BPS_TOTAL].level = 45;
222     orig_cfg.buckets[THROTTLE_BPS_READ].level  = 65;
223     orig_cfg.buckets[THROTTLE_BPS_WRITE].level = 23;
224 
225     orig_cfg.buckets[THROTTLE_OPS_TOTAL].level = 1;
226     orig_cfg.buckets[THROTTLE_OPS_READ].level  = 90;
227     orig_cfg.buckets[THROTTLE_OPS_WRITE].level = 75;
228 
229     orig_cfg.op_size = 1;
230 
231     throttle_init(&ts);
232     throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
233                          read_timer_cb, write_timer_cb, &ts);
234     /* structure reset by throttle_init previous_leak should be null */
235     g_assert(!ts.previous_leak);
236     throttle_config(&ts, QEMU_CLOCK_VIRTUAL, &orig_cfg);
237 
238     /* has previous leak been initialized by throttle_config ? */
239     g_assert(ts.previous_leak);
240 
241     /* get back the fixed configuration */
242     throttle_get_config(&ts, &final_cfg);
243 
244     throttle_timers_destroy(tt);
245 
246     g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].avg == 153);
247     g_assert(final_cfg.buckets[THROTTLE_BPS_READ].avg  == 56);
248     g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].avg == 1);
249 
250     g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].avg == 150);
251     g_assert(final_cfg.buckets[THROTTLE_OPS_READ].avg  == 69);
252     g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].avg == 23);
253 
254     g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].max == 0);
255     g_assert(final_cfg.buckets[THROTTLE_BPS_READ].max  == 56);
256     g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].max == 120);
257 
258     g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].max == 150);
259     g_assert(final_cfg.buckets[THROTTLE_OPS_READ].max  == 400);
260     g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].max == 500);
261 
262     g_assert(final_cfg.op_size == 1);
263 
264     /* check bucket have been cleared */
265     for (i = 0; i < BUCKETS_COUNT; i++) {
266         g_assert(!final_cfg.buckets[i].level);
267     }
268 }
269 
270 /* functions to test is throttle is enabled by a config */
271 static void set_cfg_value(bool is_max, int index, int value)
272 {
273     if (is_max) {
274         cfg.buckets[index].max = value;
275         /* If max is set, avg should never be 0 */
276         cfg.buckets[index].avg = MAX(cfg.buckets[index].avg, 1);
277     } else {
278         cfg.buckets[index].avg = value;
279     }
280 }
281 
282 static void test_enabled(void)
283 {
284     int i;
285 
286     throttle_config_init(&cfg);
287     g_assert(!throttle_enabled(&cfg));
288 
289     for (i = 0; i < BUCKETS_COUNT; i++) {
290         throttle_config_init(&cfg);
291         set_cfg_value(false, i, 150);
292         g_assert(throttle_is_valid(&cfg, NULL));
293         g_assert(throttle_enabled(&cfg));
294     }
295 
296     for (i = 0; i < BUCKETS_COUNT; i++) {
297         throttle_config_init(&cfg);
298         set_cfg_value(false, i, -150);
299         g_assert(!throttle_is_valid(&cfg, NULL));
300     }
301 }
302 
303 /* tests functions for throttle_conflicting */
304 
305 static void test_conflicts_for_one_set(bool is_max,
306                                        int total,
307                                        int read,
308                                        int write)
309 {
310     throttle_config_init(&cfg);
311     g_assert(throttle_is_valid(&cfg, NULL));
312 
313     set_cfg_value(is_max, total, 1);
314     set_cfg_value(is_max, read,  1);
315     g_assert(!throttle_is_valid(&cfg, NULL));
316 
317     throttle_config_init(&cfg);
318     set_cfg_value(is_max, total, 1);
319     set_cfg_value(is_max, write, 1);
320     g_assert(!throttle_is_valid(&cfg, NULL));
321 
322     throttle_config_init(&cfg);
323     set_cfg_value(is_max, total, 1);
324     set_cfg_value(is_max, read,  1);
325     set_cfg_value(is_max, write, 1);
326     g_assert(!throttle_is_valid(&cfg, NULL));
327 
328     throttle_config_init(&cfg);
329     set_cfg_value(is_max, total, 1);
330     g_assert(throttle_is_valid(&cfg, NULL));
331 
332     throttle_config_init(&cfg);
333     set_cfg_value(is_max, read,  1);
334     set_cfg_value(is_max, write, 1);
335     g_assert(throttle_is_valid(&cfg, NULL));
336 }
337 
338 static void test_conflicting_config(void)
339 {
340     /* bps average conflicts */
341     test_conflicts_for_one_set(false,
342                                THROTTLE_BPS_TOTAL,
343                                THROTTLE_BPS_READ,
344                                THROTTLE_BPS_WRITE);
345 
346     /* ops average conflicts */
347     test_conflicts_for_one_set(false,
348                                THROTTLE_OPS_TOTAL,
349                                THROTTLE_OPS_READ,
350                                THROTTLE_OPS_WRITE);
351 
352     /* bps average conflicts */
353     test_conflicts_for_one_set(true,
354                                THROTTLE_BPS_TOTAL,
355                                THROTTLE_BPS_READ,
356                                THROTTLE_BPS_WRITE);
357     /* ops average conflicts */
358     test_conflicts_for_one_set(true,
359                                THROTTLE_OPS_TOTAL,
360                                THROTTLE_OPS_READ,
361                                THROTTLE_OPS_WRITE);
362 }
363 /* functions to test the throttle_is_valid function */
364 static void test_is_valid_for_value(int value, bool should_be_valid)
365 {
366     int is_max, index;
367     for (is_max = 0; is_max < 2; is_max++) {
368         for (index = 0; index < BUCKETS_COUNT; index++) {
369             throttle_config_init(&cfg);
370             set_cfg_value(is_max, index, value);
371             g_assert(throttle_is_valid(&cfg, NULL) == should_be_valid);
372         }
373     }
374 }
375 
376 static void test_is_valid(void)
377 {
378     /* negative numbesr are invalid */
379     test_is_valid_for_value(-1, false);
380     /* zero is valid */
381     test_is_valid_for_value(0, true);
382     /* positives numbers are valid */
383     test_is_valid_for_value(1, true);
384 }
385 
386 static void test_ranges(void)
387 {
388     int i;
389 
390     for (i = 0; i < BUCKETS_COUNT; i++) {
391         LeakyBucket *b = &cfg.buckets[i];
392         throttle_config_init(&cfg);
393 
394         /* avg = 0 means throttling is disabled, but the config is valid */
395         b->avg = 0;
396         g_assert(throttle_is_valid(&cfg, NULL));
397         g_assert(!throttle_enabled(&cfg));
398 
399         /* These are valid configurations (values <= THROTTLE_VALUE_MAX) */
400         b->avg = 1;
401         g_assert(throttle_is_valid(&cfg, NULL));
402 
403         b->avg = THROTTLE_VALUE_MAX;
404         g_assert(throttle_is_valid(&cfg, NULL));
405 
406         b->avg = THROTTLE_VALUE_MAX;
407         b->max = THROTTLE_VALUE_MAX;
408         g_assert(throttle_is_valid(&cfg, NULL));
409 
410         /* Values over THROTTLE_VALUE_MAX are not allowed */
411         b->avg = THROTTLE_VALUE_MAX + 1;
412         g_assert(!throttle_is_valid(&cfg, NULL));
413 
414         b->avg = THROTTLE_VALUE_MAX;
415         b->max = THROTTLE_VALUE_MAX + 1;
416         g_assert(!throttle_is_valid(&cfg, NULL));
417 
418         /* burst_length must be between 1 and THROTTLE_VALUE_MAX */
419         b->avg = 1;
420         b->max = 1;
421         b->burst_length = 0;
422         g_assert(!throttle_is_valid(&cfg, NULL));
423 
424         b->avg = 1;
425         b->max = 1;
426         b->burst_length = 1;
427         g_assert(throttle_is_valid(&cfg, NULL));
428 
429         b->avg = 1;
430         b->max = 1;
431         b->burst_length = THROTTLE_VALUE_MAX;
432         g_assert(throttle_is_valid(&cfg, NULL));
433 
434         b->avg = 1;
435         b->max = 1;
436         b->burst_length = THROTTLE_VALUE_MAX + 1;
437         g_assert(!throttle_is_valid(&cfg, NULL));
438 
439         /* burst_length * max cannot exceed THROTTLE_VALUE_MAX */
440         b->avg = 1;
441         b->max = 2;
442         b->burst_length = THROTTLE_VALUE_MAX / 2;
443         g_assert(throttle_is_valid(&cfg, NULL));
444 
445         b->avg = 1;
446         b->max = 3;
447         b->burst_length = THROTTLE_VALUE_MAX / 2;
448         g_assert(!throttle_is_valid(&cfg, NULL));
449 
450         b->avg = 1;
451         b->max = THROTTLE_VALUE_MAX;
452         b->burst_length = 1;
453         g_assert(throttle_is_valid(&cfg, NULL));
454 
455         b->avg = 1;
456         b->max = THROTTLE_VALUE_MAX;
457         b->burst_length = 2;
458         g_assert(!throttle_is_valid(&cfg, NULL));
459     }
460 }
461 
462 static void test_max_is_missing_limit(void)
463 {
464     int i;
465 
466     for (i = 0; i < BUCKETS_COUNT; i++) {
467         throttle_config_init(&cfg);
468         cfg.buckets[i].max = 100;
469         cfg.buckets[i].avg = 0;
470         g_assert(!throttle_is_valid(&cfg, NULL));
471 
472         cfg.buckets[i].max = 0;
473         cfg.buckets[i].avg = 0;
474         g_assert(throttle_is_valid(&cfg, NULL));
475 
476         cfg.buckets[i].max = 0;
477         cfg.buckets[i].avg = 100;
478         g_assert(throttle_is_valid(&cfg, NULL));
479 
480         cfg.buckets[i].max = 30;
481         cfg.buckets[i].avg = 100;
482         g_assert(!throttle_is_valid(&cfg, NULL));
483 
484         cfg.buckets[i].max = 100;
485         cfg.buckets[i].avg = 100;
486         g_assert(throttle_is_valid(&cfg, NULL));
487     }
488 }
489 
490 static void test_iops_size_is_missing_limit(void)
491 {
492     /* A total/read/write iops limit is required */
493     throttle_config_init(&cfg);
494     cfg.op_size = 4096;
495     g_assert(!throttle_is_valid(&cfg, NULL));
496 }
497 
498 static void test_have_timer(void)
499 {
500     /* zero structures */
501     memset(&ts, 0, sizeof(ts));
502     memset(tt, 0, sizeof(*tt));
503 
504     /* no timer set should return false */
505     g_assert(!throttle_timers_are_initialized(tt));
506 
507     /* init structures */
508     throttle_init(&ts);
509     throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
510                          read_timer_cb, write_timer_cb, &ts);
511 
512     /* timer set by init should return true */
513     g_assert(throttle_timers_are_initialized(tt));
514 
515     throttle_timers_destroy(tt);
516 }
517 
518 static void test_detach_attach(void)
519 {
520     /* zero structures */
521     memset(&ts, 0, sizeof(ts));
522     memset(tt, 0, sizeof(*tt));
523 
524     /* init the structure */
525     throttle_init(&ts);
526     throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
527                          read_timer_cb, write_timer_cb, &ts);
528 
529     /* timer set by init should return true */
530     g_assert(throttle_timers_are_initialized(tt));
531 
532     /* timer should no longer exist after detaching */
533     throttle_timers_detach_aio_context(tt);
534     g_assert(!throttle_timers_are_initialized(tt));
535 
536     /* timer should exist again after attaching */
537     throttle_timers_attach_aio_context(tt, ctx);
538     g_assert(throttle_timers_are_initialized(tt));
539 
540     throttle_timers_destroy(tt);
541 }
542 
543 static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
544                 int size,                   /* size of the operation to do */
545                 double avg,                 /* io limit */
546                 uint64_t op_size,           /* ideal size of an io */
547                 double total_result,
548                 double read_result,
549                 double write_result)
550 {
551     BucketType to_test[2][3] = { { THROTTLE_BPS_TOTAL,
552                                    THROTTLE_BPS_READ,
553                                    THROTTLE_BPS_WRITE, },
554                                  { THROTTLE_OPS_TOTAL,
555                                    THROTTLE_OPS_READ,
556                                    THROTTLE_OPS_WRITE, } };
557     ThrottleConfig cfg;
558     BucketType index;
559     int i;
560 
561     throttle_config_init(&cfg);
562 
563     for (i = 0; i < 3; i++) {
564         BucketType index = to_test[is_ops][i];
565         cfg.buckets[index].avg = avg;
566     }
567 
568     cfg.op_size = op_size;
569 
570     throttle_init(&ts);
571     throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
572                          read_timer_cb, write_timer_cb, &ts);
573     throttle_config(&ts, QEMU_CLOCK_VIRTUAL, &cfg);
574 
575     /* account a read */
576     throttle_account(&ts, false, size);
577     /* account a write */
578     throttle_account(&ts, true, size);
579 
580     /* check total result */
581     index = to_test[is_ops][0];
582     if (!double_cmp(ts.cfg.buckets[index].level, total_result)) {
583         return false;
584     }
585 
586     /* check read result */
587     index = to_test[is_ops][1];
588     if (!double_cmp(ts.cfg.buckets[index].level, read_result)) {
589         return false;
590     }
591 
592     /* check write result */
593     index = to_test[is_ops][2];
594     if (!double_cmp(ts.cfg.buckets[index].level, write_result)) {
595         return false;
596     }
597 
598     throttle_timers_destroy(tt);
599 
600     return true;
601 }
602 
603 static void test_accounting(void)
604 {
605     /* tests for bps */
606 
607     /* op of size 1 */
608     g_assert(do_test_accounting(false,
609                                 1 * 512,
610                                 150,
611                                 0,
612                                 1024,
613                                 512,
614                                 512));
615 
616     /* op of size 2 */
617     g_assert(do_test_accounting(false,
618                                 2 * 512,
619                                 150,
620                                 0,
621                                 2048,
622                                 1024,
623                                 1024));
624 
625     /* op of size 2 and orthogonal parameter change */
626     g_assert(do_test_accounting(false,
627                                 2 * 512,
628                                 150,
629                                 17,
630                                 2048,
631                                 1024,
632                                 1024));
633 
634 
635     /* tests for ops */
636 
637     /* op of size 1 */
638     g_assert(do_test_accounting(true,
639                                 1 * 512,
640                                 150,
641                                 0,
642                                 2,
643                                 1,
644                                 1));
645 
646     /* op of size 2 */
647     g_assert(do_test_accounting(true,
648                                 2 *  512,
649                                 150,
650                                 0,
651                                 2,
652                                 1,
653                                 1));
654 
655     /* jumbo op accounting fragmentation : size 64 with op size of 13 units */
656     g_assert(do_test_accounting(true,
657                                 64 * 512,
658                                 150,
659                                 13 * 512,
660                                 (64.0 * 2) / 13,
661                                 (64.0 / 13),
662                                 (64.0 / 13)));
663 
664     /* same with orthogonal parameters changes */
665     g_assert(do_test_accounting(true,
666                                 64 * 512,
667                                 300,
668                                 13 * 512,
669                                 (64.0 * 2) / 13,
670                                 (64.0 / 13),
671                                 (64.0 / 13)));
672 }
673 
674 static void test_groups(void)
675 {
676     ThrottleConfig cfg1, cfg2;
677     BlockBackend *blk1, *blk2, *blk3;
678     BlockBackendPublic *blkp1, *blkp2, *blkp3;
679     ThrottleGroupMember *tgm1, *tgm2, *tgm3;
680 
681     /* No actual I/O is performed on these devices */
682     blk1 = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
683     blk2 = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
684     blk3 = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
685 
686     blkp1 = blk_get_public(blk1);
687     blkp2 = blk_get_public(blk2);
688     blkp3 = blk_get_public(blk3);
689 
690     tgm1 = &blkp1->throttle_group_member;
691     tgm2 = &blkp2->throttle_group_member;
692     tgm3 = &blkp3->throttle_group_member;
693 
694     g_assert(tgm1->throttle_state == NULL);
695     g_assert(tgm2->throttle_state == NULL);
696     g_assert(tgm3->throttle_state == NULL);
697 
698     throttle_group_register_tgm(tgm1, "bar", blk_get_aio_context(blk1));
699     throttle_group_register_tgm(tgm2, "foo", blk_get_aio_context(blk2));
700     throttle_group_register_tgm(tgm3, "bar", blk_get_aio_context(blk3));
701 
702     g_assert(tgm1->throttle_state != NULL);
703     g_assert(tgm2->throttle_state != NULL);
704     g_assert(tgm3->throttle_state != NULL);
705 
706     g_assert(!strcmp(throttle_group_get_name(tgm1), "bar"));
707     g_assert(!strcmp(throttle_group_get_name(tgm2), "foo"));
708     g_assert(tgm1->throttle_state == tgm3->throttle_state);
709 
710     /* Setting the config of a group member affects the whole group */
711     throttle_config_init(&cfg1);
712     cfg1.buckets[THROTTLE_BPS_READ].avg  = 500000;
713     cfg1.buckets[THROTTLE_BPS_WRITE].avg = 285000;
714     cfg1.buckets[THROTTLE_OPS_READ].avg  = 20000;
715     cfg1.buckets[THROTTLE_OPS_WRITE].avg = 12000;
716     throttle_group_config(tgm1, &cfg1);
717 
718     throttle_group_get_config(tgm1, &cfg1);
719     throttle_group_get_config(tgm3, &cfg2);
720     g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
721 
722     cfg2.buckets[THROTTLE_BPS_READ].avg  = 4547;
723     cfg2.buckets[THROTTLE_BPS_WRITE].avg = 1349;
724     cfg2.buckets[THROTTLE_OPS_READ].avg  = 123;
725     cfg2.buckets[THROTTLE_OPS_WRITE].avg = 86;
726     throttle_group_config(tgm3, &cfg1);
727 
728     throttle_group_get_config(tgm1, &cfg1);
729     throttle_group_get_config(tgm3, &cfg2);
730     g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
731 
732     throttle_group_unregister_tgm(tgm1);
733     throttle_group_unregister_tgm(tgm2);
734     throttle_group_unregister_tgm(tgm3);
735 
736     g_assert(tgm1->throttle_state == NULL);
737     g_assert(tgm2->throttle_state == NULL);
738     g_assert(tgm3->throttle_state == NULL);
739 }
740 
741 int main(int argc, char **argv)
742 {
743     qemu_init_main_loop(&error_fatal);
744     ctx = qemu_get_aio_context();
745     bdrv_init();
746     module_call_init(MODULE_INIT_QOM);
747 
748     do {} while (g_main_context_iteration(NULL, false));
749 
750     /* tests in the same order as the header function declarations */
751     g_test_init(&argc, &argv, NULL);
752     g_test_add_func("/throttle/leak_bucket",        test_leak_bucket);
753     g_test_add_func("/throttle/compute_wait",       test_compute_wait);
754     g_test_add_func("/throttle/init",               test_init);
755     g_test_add_func("/throttle/destroy",            test_destroy);
756     g_test_add_func("/throttle/have_timer",         test_have_timer);
757     g_test_add_func("/throttle/detach_attach",      test_detach_attach);
758     g_test_add_func("/throttle/config/enabled",     test_enabled);
759     g_test_add_func("/throttle/config/conflicting", test_conflicting_config);
760     g_test_add_func("/throttle/config/is_valid",    test_is_valid);
761     g_test_add_func("/throttle/config/ranges",      test_ranges);
762     g_test_add_func("/throttle/config/max",         test_max_is_missing_limit);
763     g_test_add_func("/throttle/config/iops_size",
764                     test_iops_size_is_missing_limit);
765     g_test_add_func("/throttle/config_functions",   test_config_functions);
766     g_test_add_func("/throttle/accounting",         test_accounting);
767     g_test_add_func("/throttle/groups",             test_groups);
768     return g_test_run();
769 }
770 
771