xref: /qemu/tests/unit/test-throttle.c (revision 1588ab5d0b96301b893d63aa342faad0e37a02ff)
1f17cfe81SBenoît Canet /*
2f17cfe81SBenoît Canet  * Throttle infrastructure tests
3f17cfe81SBenoît Canet  *
41fee955fSAlberto Garcia  * Copyright Nodalink, EURL. 2013-2014
51fee955fSAlberto Garcia  * Copyright Igalia, S.L. 2015
6f17cfe81SBenoît Canet  *
7f17cfe81SBenoît Canet  * Authors:
81fee955fSAlberto Garcia  *  Benoît Canet     <benoit.canet@nodalink.com>
91fee955fSAlberto Garcia  *  Alberto Garcia   <berto@igalia.com>
10f17cfe81SBenoît Canet  *
11f17cfe81SBenoît Canet  * This work is licensed under the terms of the GNU LGPL, version 2 or later.
12f17cfe81SBenoît Canet  * See the COPYING.LIB file in the top-level directory.
13f17cfe81SBenoît Canet  */
14f17cfe81SBenoît Canet 
15681c28a3SPeter Maydell #include "qemu/osdep.h"
16f17cfe81SBenoît Canet #include <glib.h>
17f17cfe81SBenoît Canet #include <math.h>
1813af91ebSStefan Hajnoczi #include "block/aio.h"
19f17cfe81SBenoît Canet #include "qemu/throttle.h"
202f78e491SChrysostomos Nanakos #include "qemu/error-report.h"
211fee955fSAlberto Garcia #include "block/throttle-groups.h"
22f17cfe81SBenoît Canet 
23748bfb4eSStefan Weil static AioContext     *ctx;
24748bfb4eSStefan Weil static LeakyBucket    bkt;
25748bfb4eSStefan Weil static ThrottleConfig cfg;
26748bfb4eSStefan Weil static ThrottleState  ts;
270e5b0a2dSBenoît Canet static ThrottleTimers tt;
28f17cfe81SBenoît Canet 
2973f395faSStefan Weil /* useful function */
30f17cfe81SBenoît Canet static bool double_cmp(double x, double y)
31f17cfe81SBenoît Canet {
32f17cfe81SBenoît Canet     return fabsl(x - y) < 1e-6;
33f17cfe81SBenoît Canet }
34f17cfe81SBenoît Canet 
35f17cfe81SBenoît Canet /* tests for single bucket operations */
36f17cfe81SBenoît Canet static void test_leak_bucket(void)
37f17cfe81SBenoît Canet {
38*1588ab5dSAlberto Garcia     throttle_config_init(&cfg);
39*1588ab5dSAlberto Garcia     bkt = cfg.buckets[THROTTLE_BPS_TOTAL];
40*1588ab5dSAlberto Garcia 
41f17cfe81SBenoît Canet     /* set initial value */
42f17cfe81SBenoît Canet     bkt.avg = 150;
43f17cfe81SBenoît Canet     bkt.max = 15;
44f17cfe81SBenoît Canet     bkt.level = 1.5;
45f17cfe81SBenoît Canet 
46f17cfe81SBenoît Canet     /* leak an op work of time */
4713566fe3SStefan Hajnoczi     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
48f17cfe81SBenoît Canet     g_assert(bkt.avg == 150);
49f17cfe81SBenoît Canet     g_assert(bkt.max == 15);
50f17cfe81SBenoît Canet     g_assert(double_cmp(bkt.level, 0.5));
51f17cfe81SBenoît Canet 
52f17cfe81SBenoît Canet     /* leak again emptying the bucket */
5313566fe3SStefan Hajnoczi     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
54f17cfe81SBenoît Canet     g_assert(bkt.avg == 150);
55f17cfe81SBenoît Canet     g_assert(bkt.max == 15);
56f17cfe81SBenoît Canet     g_assert(double_cmp(bkt.level, 0));
57f17cfe81SBenoît Canet 
58f17cfe81SBenoît Canet     /* check that the bucket level won't go lower */
5913566fe3SStefan Hajnoczi     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
60f17cfe81SBenoît Canet     g_assert(bkt.avg == 150);
61f17cfe81SBenoît Canet     g_assert(bkt.max == 15);
62f17cfe81SBenoît Canet     g_assert(double_cmp(bkt.level, 0));
63f17cfe81SBenoît Canet }
64f17cfe81SBenoît Canet 
65f17cfe81SBenoît Canet static void test_compute_wait(void)
66f17cfe81SBenoît Canet {
67f17cfe81SBenoît Canet     int64_t wait;
68f17cfe81SBenoît Canet     int64_t result;
69f17cfe81SBenoît Canet 
70*1588ab5dSAlberto Garcia     throttle_config_init(&cfg);
71*1588ab5dSAlberto Garcia     bkt = cfg.buckets[THROTTLE_BPS_TOTAL];
72*1588ab5dSAlberto Garcia 
73f17cfe81SBenoît Canet     /* no operation limit set */
74f17cfe81SBenoît Canet     bkt.avg = 0;
75f17cfe81SBenoît Canet     bkt.max = 15;
76f17cfe81SBenoît Canet     bkt.level = 1.5;
77f17cfe81SBenoît Canet     wait = throttle_compute_wait(&bkt);
78f17cfe81SBenoît Canet     g_assert(!wait);
79f17cfe81SBenoît Canet 
80f17cfe81SBenoît Canet     /* zero delta */
81f17cfe81SBenoît Canet     bkt.avg = 150;
82f17cfe81SBenoît Canet     bkt.max = 15;
83f17cfe81SBenoît Canet     bkt.level = 15;
84f17cfe81SBenoît Canet     wait = throttle_compute_wait(&bkt);
85f17cfe81SBenoît Canet     g_assert(!wait);
86f17cfe81SBenoît Canet 
87f17cfe81SBenoît Canet     /* below zero delta */
88f17cfe81SBenoît Canet     bkt.avg = 150;
89f17cfe81SBenoît Canet     bkt.max = 15;
90f17cfe81SBenoît Canet     bkt.level = 9;
91f17cfe81SBenoît Canet     wait = throttle_compute_wait(&bkt);
92f17cfe81SBenoît Canet     g_assert(!wait);
93f17cfe81SBenoît Canet 
94f17cfe81SBenoît Canet     /* half an operation above max */
95f17cfe81SBenoît Canet     bkt.avg = 150;
96f17cfe81SBenoît Canet     bkt.max = 15;
97f17cfe81SBenoît Canet     bkt.level = 15.5;
98f17cfe81SBenoît Canet     wait = throttle_compute_wait(&bkt);
99f17cfe81SBenoît Canet     /* time required to do half an operation */
10013566fe3SStefan Hajnoczi     result = (int64_t)  NANOSECONDS_PER_SECOND / 150 / 2;
101f17cfe81SBenoît Canet     g_assert(wait == result);
102f17cfe81SBenoît Canet }
103f17cfe81SBenoît Canet 
104f17cfe81SBenoît Canet /* functions to test ThrottleState initialization/destroy methods */
105f17cfe81SBenoît Canet static void read_timer_cb(void *opaque)
106f17cfe81SBenoît Canet {
107f17cfe81SBenoît Canet }
108f17cfe81SBenoît Canet 
109f17cfe81SBenoît Canet static void write_timer_cb(void *opaque)
110f17cfe81SBenoît Canet {
111f17cfe81SBenoît Canet }
112f17cfe81SBenoît Canet 
113f17cfe81SBenoît Canet static void test_init(void)
114f17cfe81SBenoît Canet {
115f17cfe81SBenoît Canet     int i;
116f17cfe81SBenoît Canet 
1170e5b0a2dSBenoît Canet     /* fill the structures with crap */
118f17cfe81SBenoît Canet     memset(&ts, 1, sizeof(ts));
1190e5b0a2dSBenoît Canet     memset(&tt, 1, sizeof(tt));
120f17cfe81SBenoît Canet 
1210e5b0a2dSBenoît Canet     /* init structures */
1220e5b0a2dSBenoît Canet     throttle_init(&ts);
1230e5b0a2dSBenoît Canet     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
12413af91ebSStefan Hajnoczi                          read_timer_cb, write_timer_cb, &ts);
125f17cfe81SBenoît Canet 
126f17cfe81SBenoît Canet     /* check initialized fields */
1270e5b0a2dSBenoît Canet     g_assert(tt.clock_type == QEMU_CLOCK_VIRTUAL);
1280e5b0a2dSBenoît Canet     g_assert(tt.timers[0]);
1290e5b0a2dSBenoît Canet     g_assert(tt.timers[1]);
130f17cfe81SBenoît Canet 
131f17cfe81SBenoît Canet     /* check other fields where cleared */
132f17cfe81SBenoît Canet     g_assert(!ts.previous_leak);
133f17cfe81SBenoît Canet     g_assert(!ts.cfg.op_size);
134f17cfe81SBenoît Canet     for (i = 0; i < BUCKETS_COUNT; i++) {
135f17cfe81SBenoît Canet         g_assert(!ts.cfg.buckets[i].avg);
136f17cfe81SBenoît Canet         g_assert(!ts.cfg.buckets[i].max);
137f17cfe81SBenoît Canet         g_assert(!ts.cfg.buckets[i].level);
138f17cfe81SBenoît Canet     }
139f17cfe81SBenoît Canet 
1400e5b0a2dSBenoît Canet     throttle_timers_destroy(&tt);
141f17cfe81SBenoît Canet }
142f17cfe81SBenoît Canet 
143f17cfe81SBenoît Canet static void test_destroy(void)
144f17cfe81SBenoît Canet {
145f17cfe81SBenoît Canet     int i;
1460e5b0a2dSBenoît Canet     throttle_init(&ts);
1470e5b0a2dSBenoît Canet     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
14813af91ebSStefan Hajnoczi                          read_timer_cb, write_timer_cb, &ts);
1490e5b0a2dSBenoît Canet     throttle_timers_destroy(&tt);
150f17cfe81SBenoît Canet     for (i = 0; i < 2; i++) {
1510e5b0a2dSBenoît Canet         g_assert(!tt.timers[i]);
152f17cfe81SBenoît Canet     }
153f17cfe81SBenoît Canet }
154f17cfe81SBenoît Canet 
155f17cfe81SBenoît Canet /* function to test throttle_config and throttle_get_config */
156f17cfe81SBenoît Canet static void test_config_functions(void)
157f17cfe81SBenoît Canet {
158f17cfe81SBenoît Canet     int i;
159f17cfe81SBenoît Canet     ThrottleConfig orig_cfg, final_cfg;
160f17cfe81SBenoît Canet 
161f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_TOTAL].avg = 153;
162f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_READ].avg  = 56;
163f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_WRITE].avg = 1;
164f17cfe81SBenoît Canet 
165f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_TOTAL].avg = 150;
166f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_READ].avg  = 69;
167f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_WRITE].avg = 23;
168f17cfe81SBenoît Canet 
169f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_TOTAL].max = 0; /* should be corrected */
170f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_READ].max  = 1; /* should not be corrected */
171f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_WRITE].max = 120;
172f17cfe81SBenoît Canet 
173f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_TOTAL].max = 150;
174f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_READ].max  = 400;
175f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_WRITE].max = 500;
176f17cfe81SBenoît Canet 
177f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_TOTAL].level = 45;
178f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_READ].level  = 65;
179f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_WRITE].level = 23;
180f17cfe81SBenoît Canet 
181f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_TOTAL].level = 1;
182f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_READ].level  = 90;
183f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_WRITE].level = 75;
184f17cfe81SBenoît Canet 
185f17cfe81SBenoît Canet     orig_cfg.op_size = 1;
186f17cfe81SBenoît Canet 
1870e5b0a2dSBenoît Canet     throttle_init(&ts);
1880e5b0a2dSBenoît Canet     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
18913af91ebSStefan Hajnoczi                          read_timer_cb, write_timer_cb, &ts);
190f17cfe81SBenoît Canet     /* structure reset by throttle_init previous_leak should be null */
191f17cfe81SBenoît Canet     g_assert(!ts.previous_leak);
1920e5b0a2dSBenoît Canet     throttle_config(&ts, &tt, &orig_cfg);
193f17cfe81SBenoît Canet 
194f17cfe81SBenoît Canet     /* has previous leak been initialized by throttle_config ? */
195f17cfe81SBenoît Canet     g_assert(ts.previous_leak);
196f17cfe81SBenoît Canet 
197f17cfe81SBenoît Canet     /* get back the fixed configuration */
198f17cfe81SBenoît Canet     throttle_get_config(&ts, &final_cfg);
199f17cfe81SBenoît Canet 
2000e5b0a2dSBenoît Canet     throttle_timers_destroy(&tt);
201f17cfe81SBenoît Canet 
202f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].avg == 153);
203f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_BPS_READ].avg  == 56);
204f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].avg == 1);
205f17cfe81SBenoît Canet 
206f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].avg == 150);
207f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_OPS_READ].avg  == 69);
208f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].avg == 23);
209f17cfe81SBenoît Canet 
210f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].max == 15.3);/* fixed */
211f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_BPS_READ].max  == 1);   /* not fixed */
212f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].max == 120);
213f17cfe81SBenoît Canet 
214f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].max == 150);
215f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_OPS_READ].max  == 400);
216f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].max == 500);
217f17cfe81SBenoît Canet 
218f17cfe81SBenoît Canet     g_assert(final_cfg.op_size == 1);
219f17cfe81SBenoît Canet 
220f17cfe81SBenoît Canet     /* check bucket have been cleared */
221f17cfe81SBenoît Canet     for (i = 0; i < BUCKETS_COUNT; i++) {
222f17cfe81SBenoît Canet         g_assert(!final_cfg.buckets[i].level);
223f17cfe81SBenoît Canet     }
224f17cfe81SBenoît Canet }
225f17cfe81SBenoît Canet 
226f17cfe81SBenoît Canet /* functions to test is throttle is enabled by a config */
227f17cfe81SBenoît Canet static void set_cfg_value(bool is_max, int index, int value)
228f17cfe81SBenoît Canet {
229f17cfe81SBenoît Canet     if (is_max) {
230f17cfe81SBenoît Canet         cfg.buckets[index].max = value;
2316f9b6d57SAlberto Garcia         /* If max is set, avg should never be 0 */
2326f9b6d57SAlberto Garcia         cfg.buckets[index].avg = MAX(cfg.buckets[index].avg, 1);
233f17cfe81SBenoît Canet     } else {
234f17cfe81SBenoît Canet         cfg.buckets[index].avg = value;
235f17cfe81SBenoît Canet     }
236f17cfe81SBenoît Canet }
237f17cfe81SBenoît Canet 
238f17cfe81SBenoît Canet static void test_enabled(void)
239f17cfe81SBenoît Canet {
240f17cfe81SBenoît Canet     int i;
241f17cfe81SBenoît Canet 
242*1588ab5dSAlberto Garcia     throttle_config_init(&cfg);
243f17cfe81SBenoît Canet     g_assert(!throttle_enabled(&cfg));
244f17cfe81SBenoît Canet 
245f17cfe81SBenoît Canet     for (i = 0; i < BUCKETS_COUNT; i++) {
246*1588ab5dSAlberto Garcia         throttle_config_init(&cfg);
247f17cfe81SBenoît Canet         set_cfg_value(false, i, 150);
248f17cfe81SBenoît Canet         g_assert(throttle_enabled(&cfg));
249f17cfe81SBenoît Canet     }
250f17cfe81SBenoît Canet 
251f17cfe81SBenoît Canet     for (i = 0; i < BUCKETS_COUNT; i++) {
252*1588ab5dSAlberto Garcia         throttle_config_init(&cfg);
253f17cfe81SBenoît Canet         set_cfg_value(false, i, -150);
254f17cfe81SBenoît Canet         g_assert(!throttle_enabled(&cfg));
255f17cfe81SBenoît Canet     }
256f17cfe81SBenoît Canet }
257f17cfe81SBenoît Canet 
258f17cfe81SBenoît Canet /* tests functions for throttle_conflicting */
259f17cfe81SBenoît Canet 
260f17cfe81SBenoît Canet static void test_conflicts_for_one_set(bool is_max,
261f17cfe81SBenoît Canet                                        int total,
262f17cfe81SBenoît Canet                                        int read,
263f17cfe81SBenoît Canet                                        int write)
264f17cfe81SBenoît Canet {
265*1588ab5dSAlberto Garcia     throttle_config_init(&cfg);
266d5851089SAlberto Garcia     g_assert(throttle_is_valid(&cfg, NULL));
267f17cfe81SBenoît Canet 
268f17cfe81SBenoît Canet     set_cfg_value(is_max, total, 1);
269f17cfe81SBenoît Canet     set_cfg_value(is_max, read,  1);
270d5851089SAlberto Garcia     g_assert(!throttle_is_valid(&cfg, NULL));
271f17cfe81SBenoît Canet 
272*1588ab5dSAlberto Garcia     throttle_config_init(&cfg);
273f17cfe81SBenoît Canet     set_cfg_value(is_max, total, 1);
274f17cfe81SBenoît Canet     set_cfg_value(is_max, write, 1);
275d5851089SAlberto Garcia     g_assert(!throttle_is_valid(&cfg, NULL));
276f17cfe81SBenoît Canet 
277*1588ab5dSAlberto Garcia     throttle_config_init(&cfg);
278f17cfe81SBenoît Canet     set_cfg_value(is_max, total, 1);
279f17cfe81SBenoît Canet     set_cfg_value(is_max, read,  1);
280f17cfe81SBenoît Canet     set_cfg_value(is_max, write, 1);
281d5851089SAlberto Garcia     g_assert(!throttle_is_valid(&cfg, NULL));
282f17cfe81SBenoît Canet 
283*1588ab5dSAlberto Garcia     throttle_config_init(&cfg);
284f17cfe81SBenoît Canet     set_cfg_value(is_max, total, 1);
285d5851089SAlberto Garcia     g_assert(throttle_is_valid(&cfg, NULL));
286f17cfe81SBenoît Canet 
287*1588ab5dSAlberto Garcia     throttle_config_init(&cfg);
288f17cfe81SBenoît Canet     set_cfg_value(is_max, read,  1);
289f17cfe81SBenoît Canet     set_cfg_value(is_max, write, 1);
290d5851089SAlberto Garcia     g_assert(throttle_is_valid(&cfg, NULL));
291f17cfe81SBenoît Canet }
292f17cfe81SBenoît Canet 
293f17cfe81SBenoît Canet static void test_conflicting_config(void)
294f17cfe81SBenoît Canet {
295f17cfe81SBenoît Canet     /* bps average conflicts */
296f17cfe81SBenoît Canet     test_conflicts_for_one_set(false,
297f17cfe81SBenoît Canet                                THROTTLE_BPS_TOTAL,
298f17cfe81SBenoît Canet                                THROTTLE_BPS_READ,
299f17cfe81SBenoît Canet                                THROTTLE_BPS_WRITE);
300f17cfe81SBenoît Canet 
301f17cfe81SBenoît Canet     /* ops average conflicts */
302f17cfe81SBenoît Canet     test_conflicts_for_one_set(false,
303f17cfe81SBenoît Canet                                THROTTLE_OPS_TOTAL,
304f17cfe81SBenoît Canet                                THROTTLE_OPS_READ,
305f17cfe81SBenoît Canet                                THROTTLE_OPS_WRITE);
306f17cfe81SBenoît Canet 
307f17cfe81SBenoît Canet     /* bps average conflicts */
308f17cfe81SBenoît Canet     test_conflicts_for_one_set(true,
309f17cfe81SBenoît Canet                                THROTTLE_BPS_TOTAL,
310f17cfe81SBenoît Canet                                THROTTLE_BPS_READ,
311f17cfe81SBenoît Canet                                THROTTLE_BPS_WRITE);
312f17cfe81SBenoît Canet     /* ops average conflicts */
313f17cfe81SBenoît Canet     test_conflicts_for_one_set(true,
314f17cfe81SBenoît Canet                                THROTTLE_OPS_TOTAL,
315f17cfe81SBenoît Canet                                THROTTLE_OPS_READ,
316f17cfe81SBenoît Canet                                THROTTLE_OPS_WRITE);
317f17cfe81SBenoît Canet }
318f17cfe81SBenoît Canet /* functions to test the throttle_is_valid function */
319f17cfe81SBenoît Canet static void test_is_valid_for_value(int value, bool should_be_valid)
320f17cfe81SBenoît Canet {
321f17cfe81SBenoît Canet     int is_max, index;
322f17cfe81SBenoît Canet     for (is_max = 0; is_max < 2; is_max++) {
323f17cfe81SBenoît Canet         for (index = 0; index < BUCKETS_COUNT; index++) {
324*1588ab5dSAlberto Garcia             throttle_config_init(&cfg);
325f17cfe81SBenoît Canet             set_cfg_value(is_max, index, value);
32603ba36c8SAlberto Garcia             g_assert(throttle_is_valid(&cfg, NULL) == should_be_valid);
327f17cfe81SBenoît Canet         }
328f17cfe81SBenoît Canet     }
329f17cfe81SBenoît Canet }
330f17cfe81SBenoît Canet 
331f17cfe81SBenoît Canet static void test_is_valid(void)
332f17cfe81SBenoît Canet {
333f17cfe81SBenoît Canet     /* negative number are invalid */
334f17cfe81SBenoît Canet     test_is_valid_for_value(-1, false);
335f17cfe81SBenoît Canet     /* zero are valids */
336f17cfe81SBenoît Canet     test_is_valid_for_value(0, true);
337f17cfe81SBenoît Canet     /* positives numers are valids */
338f17cfe81SBenoît Canet     test_is_valid_for_value(1, true);
339f17cfe81SBenoît Canet }
340f17cfe81SBenoît Canet 
34192e11a17SStefan Hajnoczi static void test_max_is_missing_limit(void)
34292e11a17SStefan Hajnoczi {
34392e11a17SStefan Hajnoczi     int i;
34492e11a17SStefan Hajnoczi 
34592e11a17SStefan Hajnoczi     for (i = 0; i < BUCKETS_COUNT; i++) {
346*1588ab5dSAlberto Garcia         throttle_config_init(&cfg);
34792e11a17SStefan Hajnoczi         cfg.buckets[i].max = 100;
34892e11a17SStefan Hajnoczi         cfg.buckets[i].avg = 0;
349d5851089SAlberto Garcia         g_assert(!throttle_is_valid(&cfg, NULL));
35092e11a17SStefan Hajnoczi 
35192e11a17SStefan Hajnoczi         cfg.buckets[i].max = 0;
35292e11a17SStefan Hajnoczi         cfg.buckets[i].avg = 0;
353d5851089SAlberto Garcia         g_assert(throttle_is_valid(&cfg, NULL));
35492e11a17SStefan Hajnoczi 
35592e11a17SStefan Hajnoczi         cfg.buckets[i].max = 0;
35692e11a17SStefan Hajnoczi         cfg.buckets[i].avg = 100;
357d5851089SAlberto Garcia         g_assert(throttle_is_valid(&cfg, NULL));
35892e11a17SStefan Hajnoczi     }
35992e11a17SStefan Hajnoczi }
36092e11a17SStefan Hajnoczi 
361f17cfe81SBenoît Canet static void test_have_timer(void)
362f17cfe81SBenoît Canet {
3630e5b0a2dSBenoît Canet     /* zero structures */
364f17cfe81SBenoît Canet     memset(&ts, 0, sizeof(ts));
3650e5b0a2dSBenoît Canet     memset(&tt, 0, sizeof(tt));
366f17cfe81SBenoît Canet 
36773f395faSStefan Weil     /* no timer set should return false */
3680e5b0a2dSBenoît Canet     g_assert(!throttle_timers_are_initialized(&tt));
369f17cfe81SBenoît Canet 
3700e5b0a2dSBenoît Canet     /* init structures */
3710e5b0a2dSBenoît Canet     throttle_init(&ts);
3720e5b0a2dSBenoît Canet     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
37313af91ebSStefan Hajnoczi                          read_timer_cb, write_timer_cb, &ts);
374f17cfe81SBenoît Canet 
375f17cfe81SBenoît Canet     /* timer set by init should return true */
3760e5b0a2dSBenoît Canet     g_assert(throttle_timers_are_initialized(&tt));
377f17cfe81SBenoît Canet 
3780e5b0a2dSBenoît Canet     throttle_timers_destroy(&tt);
379f17cfe81SBenoît Canet }
380f17cfe81SBenoît Canet 
38122524f72SStefan Hajnoczi static void test_detach_attach(void)
38222524f72SStefan Hajnoczi {
3830e5b0a2dSBenoît Canet     /* zero structures */
38422524f72SStefan Hajnoczi     memset(&ts, 0, sizeof(ts));
3850e5b0a2dSBenoît Canet     memset(&tt, 0, sizeof(tt));
38622524f72SStefan Hajnoczi 
38722524f72SStefan Hajnoczi     /* init the structure */
3880e5b0a2dSBenoît Canet     throttle_init(&ts);
3890e5b0a2dSBenoît Canet     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
39022524f72SStefan Hajnoczi                          read_timer_cb, write_timer_cb, &ts);
39122524f72SStefan Hajnoczi 
39222524f72SStefan Hajnoczi     /* timer set by init should return true */
3930e5b0a2dSBenoît Canet     g_assert(throttle_timers_are_initialized(&tt));
39422524f72SStefan Hajnoczi 
39522524f72SStefan Hajnoczi     /* timer should no longer exist after detaching */
3960e5b0a2dSBenoît Canet     throttle_timers_detach_aio_context(&tt);
3970e5b0a2dSBenoît Canet     g_assert(!throttle_timers_are_initialized(&tt));
39822524f72SStefan Hajnoczi 
39922524f72SStefan Hajnoczi     /* timer should exist again after attaching */
4000e5b0a2dSBenoît Canet     throttle_timers_attach_aio_context(&tt, ctx);
4010e5b0a2dSBenoît Canet     g_assert(throttle_timers_are_initialized(&tt));
40222524f72SStefan Hajnoczi 
4030e5b0a2dSBenoît Canet     throttle_timers_destroy(&tt);
40422524f72SStefan Hajnoczi }
40522524f72SStefan Hajnoczi 
406f17cfe81SBenoît Canet static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
407f17cfe81SBenoît Canet                 int size,                   /* size of the operation to do */
408f17cfe81SBenoît Canet                 double avg,                 /* io limit */
409f17cfe81SBenoît Canet                 uint64_t op_size,           /* ideal size of an io */
410f17cfe81SBenoît Canet                 double total_result,
411f17cfe81SBenoît Canet                 double read_result,
412f17cfe81SBenoît Canet                 double write_result)
413f17cfe81SBenoît Canet {
414f17cfe81SBenoît Canet     BucketType to_test[2][3] = { { THROTTLE_BPS_TOTAL,
415f17cfe81SBenoît Canet                                    THROTTLE_BPS_READ,
416f17cfe81SBenoît Canet                                    THROTTLE_BPS_WRITE, },
417f17cfe81SBenoît Canet                                  { THROTTLE_OPS_TOTAL,
418f17cfe81SBenoît Canet                                    THROTTLE_OPS_READ,
419f17cfe81SBenoît Canet                                    THROTTLE_OPS_WRITE, } };
420f17cfe81SBenoît Canet     ThrottleConfig cfg;
421f17cfe81SBenoît Canet     BucketType index;
422f17cfe81SBenoît Canet     int i;
423f17cfe81SBenoît Canet 
424f17cfe81SBenoît Canet     for (i = 0; i < 3; i++) {
425f17cfe81SBenoît Canet         BucketType index = to_test[is_ops][i];
426f17cfe81SBenoît Canet         cfg.buckets[index].avg = avg;
427f17cfe81SBenoît Canet     }
428f17cfe81SBenoît Canet 
429f17cfe81SBenoît Canet     cfg.op_size = op_size;
430f17cfe81SBenoît Canet 
4310e5b0a2dSBenoît Canet     throttle_init(&ts);
4320e5b0a2dSBenoît Canet     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
43313af91ebSStefan Hajnoczi                          read_timer_cb, write_timer_cb, &ts);
4340e5b0a2dSBenoît Canet     throttle_config(&ts, &tt, &cfg);
435f17cfe81SBenoît Canet 
436f17cfe81SBenoît Canet     /* account a read */
437f17cfe81SBenoît Canet     throttle_account(&ts, false, size);
438f17cfe81SBenoît Canet     /* account a write */
439f17cfe81SBenoît Canet     throttle_account(&ts, true, size);
440f17cfe81SBenoît Canet 
441f17cfe81SBenoît Canet     /* check total result */
442f17cfe81SBenoît Canet     index = to_test[is_ops][0];
443f17cfe81SBenoît Canet     if (!double_cmp(ts.cfg.buckets[index].level, total_result)) {
444f17cfe81SBenoît Canet         return false;
445f17cfe81SBenoît Canet     }
446f17cfe81SBenoît Canet 
447f17cfe81SBenoît Canet     /* check read result */
448f17cfe81SBenoît Canet     index = to_test[is_ops][1];
449f17cfe81SBenoît Canet     if (!double_cmp(ts.cfg.buckets[index].level, read_result)) {
450f17cfe81SBenoît Canet         return false;
451f17cfe81SBenoît Canet     }
452f17cfe81SBenoît Canet 
453f17cfe81SBenoît Canet     /* check write result */
454f17cfe81SBenoît Canet     index = to_test[is_ops][2];
455f17cfe81SBenoît Canet     if (!double_cmp(ts.cfg.buckets[index].level, write_result)) {
456f17cfe81SBenoît Canet         return false;
457f17cfe81SBenoît Canet     }
458f17cfe81SBenoît Canet 
4590e5b0a2dSBenoît Canet     throttle_timers_destroy(&tt);
460f17cfe81SBenoît Canet 
461f17cfe81SBenoît Canet     return true;
462f17cfe81SBenoît Canet }
463f17cfe81SBenoît Canet 
464f17cfe81SBenoît Canet static void test_accounting(void)
465f17cfe81SBenoît Canet {
466f17cfe81SBenoît Canet     /* tests for bps */
467f17cfe81SBenoît Canet 
468f17cfe81SBenoît Canet     /* op of size 1 */
469f17cfe81SBenoît Canet     g_assert(do_test_accounting(false,
470f17cfe81SBenoît Canet                                 1 * 512,
471f17cfe81SBenoît Canet                                 150,
472f17cfe81SBenoît Canet                                 0,
473f17cfe81SBenoît Canet                                 1024,
474f17cfe81SBenoît Canet                                 512,
475f17cfe81SBenoît Canet                                 512));
476f17cfe81SBenoît Canet 
477f17cfe81SBenoît Canet     /* op of size 2 */
478f17cfe81SBenoît Canet     g_assert(do_test_accounting(false,
479f17cfe81SBenoît Canet                                 2 * 512,
480f17cfe81SBenoît Canet                                 150,
481f17cfe81SBenoît Canet                                 0,
482f17cfe81SBenoît Canet                                 2048,
483f17cfe81SBenoît Canet                                 1024,
484f17cfe81SBenoît Canet                                 1024));
485f17cfe81SBenoît Canet 
486f17cfe81SBenoît Canet     /* op of size 2 and orthogonal parameter change */
487f17cfe81SBenoît Canet     g_assert(do_test_accounting(false,
488f17cfe81SBenoît Canet                                 2 * 512,
489f17cfe81SBenoît Canet                                 150,
490f17cfe81SBenoît Canet                                 17,
491f17cfe81SBenoît Canet                                 2048,
492f17cfe81SBenoît Canet                                 1024,
493f17cfe81SBenoît Canet                                 1024));
494f17cfe81SBenoît Canet 
495f17cfe81SBenoît Canet 
496f17cfe81SBenoît Canet     /* tests for ops */
497f17cfe81SBenoît Canet 
498f17cfe81SBenoît Canet     /* op of size 1 */
499f17cfe81SBenoît Canet     g_assert(do_test_accounting(true,
500f17cfe81SBenoît Canet                                 1 * 512,
501f17cfe81SBenoît Canet                                 150,
502f17cfe81SBenoît Canet                                 0,
503f17cfe81SBenoît Canet                                 2,
504f17cfe81SBenoît Canet                                 1,
505f17cfe81SBenoît Canet                                 1));
506f17cfe81SBenoît Canet 
507f17cfe81SBenoît Canet     /* op of size 2 */
508f17cfe81SBenoît Canet     g_assert(do_test_accounting(true,
509f17cfe81SBenoît Canet                                 2 *  512,
510f17cfe81SBenoît Canet                                 150,
511f17cfe81SBenoît Canet                                 0,
512f17cfe81SBenoît Canet                                 2,
513f17cfe81SBenoît Canet                                 1,
514f17cfe81SBenoît Canet                                 1));
515f17cfe81SBenoît Canet 
516f17cfe81SBenoît Canet     /* jumbo op accounting fragmentation : size 64 with op size of 13 units */
517f17cfe81SBenoît Canet     g_assert(do_test_accounting(true,
518f17cfe81SBenoît Canet                                 64 * 512,
519f17cfe81SBenoît Canet                                 150,
520f17cfe81SBenoît Canet                                 13 * 512,
521f17cfe81SBenoît Canet                                 (64.0 * 2) / 13,
522f17cfe81SBenoît Canet                                 (64.0 / 13),
523f17cfe81SBenoît Canet                                 (64.0 / 13)));
524f17cfe81SBenoît Canet 
525f17cfe81SBenoît Canet     /* same with orthogonal parameters changes */
526f17cfe81SBenoît Canet     g_assert(do_test_accounting(true,
527f17cfe81SBenoît Canet                                 64 * 512,
528f17cfe81SBenoît Canet                                 300,
529f17cfe81SBenoît Canet                                 13 * 512,
530f17cfe81SBenoît Canet                                 (64.0 * 2) / 13,
531f17cfe81SBenoît Canet                                 (64.0 / 13),
532f17cfe81SBenoît Canet                                 (64.0 / 13)));
533f17cfe81SBenoît Canet }
534f17cfe81SBenoît Canet 
5351fee955fSAlberto Garcia static void test_groups(void)
5361fee955fSAlberto Garcia {
5371fee955fSAlberto Garcia     ThrottleConfig cfg1, cfg2;
5381fee955fSAlberto Garcia     BlockDriverState *bdrv1, *bdrv2, *bdrv3;
5391fee955fSAlberto Garcia 
5401fee955fSAlberto Garcia     bdrv1 = bdrv_new();
5411fee955fSAlberto Garcia     bdrv2 = bdrv_new();
5421fee955fSAlberto Garcia     bdrv3 = bdrv_new();
5431fee955fSAlberto Garcia 
5441fee955fSAlberto Garcia     g_assert(bdrv1->throttle_state == NULL);
5451fee955fSAlberto Garcia     g_assert(bdrv2->throttle_state == NULL);
5461fee955fSAlberto Garcia     g_assert(bdrv3->throttle_state == NULL);
5471fee955fSAlberto Garcia 
5481fee955fSAlberto Garcia     throttle_group_register_bs(bdrv1, "bar");
5491fee955fSAlberto Garcia     throttle_group_register_bs(bdrv2, "foo");
5501fee955fSAlberto Garcia     throttle_group_register_bs(bdrv3, "bar");
5511fee955fSAlberto Garcia 
5521fee955fSAlberto Garcia     g_assert(bdrv1->throttle_state != NULL);
5531fee955fSAlberto Garcia     g_assert(bdrv2->throttle_state != NULL);
5541fee955fSAlberto Garcia     g_assert(bdrv3->throttle_state != NULL);
5551fee955fSAlberto Garcia 
5561fee955fSAlberto Garcia     g_assert(!strcmp(throttle_group_get_name(bdrv1), "bar"));
5571fee955fSAlberto Garcia     g_assert(!strcmp(throttle_group_get_name(bdrv2), "foo"));
5581fee955fSAlberto Garcia     g_assert(bdrv1->throttle_state == bdrv3->throttle_state);
5591fee955fSAlberto Garcia 
5601fee955fSAlberto Garcia     /* Setting the config of a group member affects the whole group */
561*1588ab5dSAlberto Garcia     throttle_config_init(&cfg1);
5621fee955fSAlberto Garcia     cfg1.buckets[THROTTLE_BPS_READ].avg  = 500000;
5631fee955fSAlberto Garcia     cfg1.buckets[THROTTLE_BPS_WRITE].avg = 285000;
5641fee955fSAlberto Garcia     cfg1.buckets[THROTTLE_OPS_READ].avg  = 20000;
5651fee955fSAlberto Garcia     cfg1.buckets[THROTTLE_OPS_WRITE].avg = 12000;
5661fee955fSAlberto Garcia     throttle_group_config(bdrv1, &cfg1);
5671fee955fSAlberto Garcia 
5681fee955fSAlberto Garcia     throttle_group_get_config(bdrv1, &cfg1);
5691fee955fSAlberto Garcia     throttle_group_get_config(bdrv3, &cfg2);
5701fee955fSAlberto Garcia     g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
5711fee955fSAlberto Garcia 
5721fee955fSAlberto Garcia     cfg2.buckets[THROTTLE_BPS_READ].avg  = 4547;
5731fee955fSAlberto Garcia     cfg2.buckets[THROTTLE_BPS_WRITE].avg = 1349;
5741fee955fSAlberto Garcia     cfg2.buckets[THROTTLE_OPS_READ].avg  = 123;
5751fee955fSAlberto Garcia     cfg2.buckets[THROTTLE_OPS_WRITE].avg = 86;
5761fee955fSAlberto Garcia     throttle_group_config(bdrv3, &cfg1);
5771fee955fSAlberto Garcia 
5781fee955fSAlberto Garcia     throttle_group_get_config(bdrv1, &cfg1);
5791fee955fSAlberto Garcia     throttle_group_get_config(bdrv3, &cfg2);
5801fee955fSAlberto Garcia     g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
5811fee955fSAlberto Garcia 
5821fee955fSAlberto Garcia     throttle_group_unregister_bs(bdrv1);
5831fee955fSAlberto Garcia     throttle_group_unregister_bs(bdrv2);
5841fee955fSAlberto Garcia     throttle_group_unregister_bs(bdrv3);
5851fee955fSAlberto Garcia 
5861fee955fSAlberto Garcia     g_assert(bdrv1->throttle_state == NULL);
5871fee955fSAlberto Garcia     g_assert(bdrv2->throttle_state == NULL);
5881fee955fSAlberto Garcia     g_assert(bdrv3->throttle_state == NULL);
5891fee955fSAlberto Garcia }
5901fee955fSAlberto Garcia 
591f17cfe81SBenoît Canet int main(int argc, char **argv)
592f17cfe81SBenoît Canet {
59373eaa047SMarkus Armbruster     qemu_init_main_loop(&error_fatal);
5941fee955fSAlberto Garcia     ctx = qemu_get_aio_context();
5951fee955fSAlberto Garcia     bdrv_init();
59613af91ebSStefan Hajnoczi 
597f17cfe81SBenoît Canet     do {} while (g_main_context_iteration(NULL, false));
598f17cfe81SBenoît Canet 
599f17cfe81SBenoît Canet     /* tests in the same order as the header function declarations */
600f17cfe81SBenoît Canet     g_test_init(&argc, &argv, NULL);
601f17cfe81SBenoît Canet     g_test_add_func("/throttle/leak_bucket",        test_leak_bucket);
602f17cfe81SBenoît Canet     g_test_add_func("/throttle/compute_wait",       test_compute_wait);
603f17cfe81SBenoît Canet     g_test_add_func("/throttle/init",               test_init);
604f17cfe81SBenoît Canet     g_test_add_func("/throttle/destroy",            test_destroy);
605f17cfe81SBenoît Canet     g_test_add_func("/throttle/have_timer",         test_have_timer);
60622524f72SStefan Hajnoczi     g_test_add_func("/throttle/detach_attach",      test_detach_attach);
607f17cfe81SBenoît Canet     g_test_add_func("/throttle/config/enabled",     test_enabled);
608f17cfe81SBenoît Canet     g_test_add_func("/throttle/config/conflicting", test_conflicting_config);
609f17cfe81SBenoît Canet     g_test_add_func("/throttle/config/is_valid",    test_is_valid);
61092e11a17SStefan Hajnoczi     g_test_add_func("/throttle/config/max",         test_max_is_missing_limit);
611f17cfe81SBenoît Canet     g_test_add_func("/throttle/config_functions",   test_config_functions);
612f17cfe81SBenoît Canet     g_test_add_func("/throttle/accounting",         test_accounting);
6131fee955fSAlberto Garcia     g_test_add_func("/throttle/groups",             test_groups);
614f17cfe81SBenoît Canet     return g_test_run();
615f17cfe81SBenoît Canet }
616f17cfe81SBenoît Canet 
617