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