xref: /qemu/tests/unit/test-throttle.c (revision 6d0eb64d5c6d57017c52a4f36ccae1db79215ee1)
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 <math.h>
1713af91ebSStefan Hajnoczi #include "block/aio.h"
18da34e65cSMarkus Armbruster #include "qapi/error.h"
19f17cfe81SBenoît Canet #include "qemu/throttle.h"
202f78e491SChrysostomos Nanakos #include "qemu/error-report.h"
211fee955fSAlberto Garcia #include "block/throttle-groups.h"
2231dce3ccSKevin Wolf #include "sysemu/block-backend.h"
23f17cfe81SBenoît Canet 
24748bfb4eSStefan Weil static AioContext     *ctx;
25748bfb4eSStefan Weil static LeakyBucket    bkt;
26748bfb4eSStefan Weil static ThrottleConfig cfg;
27748bfb4eSStefan Weil static ThrottleState  ts;
280e5b0a2dSBenoît Canet static ThrottleTimers tt;
29f17cfe81SBenoît Canet 
3073f395faSStefan Weil /* useful function */
31f17cfe81SBenoît Canet static bool double_cmp(double x, double y)
32f17cfe81SBenoît Canet {
33f17cfe81SBenoît Canet     return fabsl(x - y) < 1e-6;
34f17cfe81SBenoît Canet }
35f17cfe81SBenoît Canet 
36f17cfe81SBenoît Canet /* tests for single bucket operations */
37f17cfe81SBenoît Canet static void test_leak_bucket(void)
38f17cfe81SBenoît Canet {
391588ab5dSAlberto Garcia     throttle_config_init(&cfg);
401588ab5dSAlberto Garcia     bkt = cfg.buckets[THROTTLE_BPS_TOTAL];
411588ab5dSAlberto Garcia 
42f17cfe81SBenoît Canet     /* set initial value */
43f17cfe81SBenoît Canet     bkt.avg = 150;
44f17cfe81SBenoît Canet     bkt.max = 15;
45f17cfe81SBenoît Canet     bkt.level = 1.5;
46f17cfe81SBenoît Canet 
47f17cfe81SBenoît Canet     /* leak an op work of time */
4813566fe3SStefan Hajnoczi     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
49f17cfe81SBenoît Canet     g_assert(bkt.avg == 150);
50f17cfe81SBenoît Canet     g_assert(bkt.max == 15);
51f17cfe81SBenoît Canet     g_assert(double_cmp(bkt.level, 0.5));
52f17cfe81SBenoît Canet 
53f17cfe81SBenoît Canet     /* leak again emptying the bucket */
5413566fe3SStefan Hajnoczi     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
55f17cfe81SBenoît Canet     g_assert(bkt.avg == 150);
56f17cfe81SBenoît Canet     g_assert(bkt.max == 15);
57f17cfe81SBenoît Canet     g_assert(double_cmp(bkt.level, 0));
58f17cfe81SBenoît Canet 
59f17cfe81SBenoît Canet     /* check that the bucket level won't go lower */
6013566fe3SStefan Hajnoczi     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
61f17cfe81SBenoît Canet     g_assert(bkt.avg == 150);
62f17cfe81SBenoît Canet     g_assert(bkt.max == 15);
63f17cfe81SBenoît Canet     g_assert(double_cmp(bkt.level, 0));
64eb8a1a1cSAlberto Garcia 
65eb8a1a1cSAlberto Garcia     /* check that burst_level leaks correctly */
66eb8a1a1cSAlberto Garcia     bkt.burst_level = 6;
67eb8a1a1cSAlberto Garcia     bkt.max = 250;
68eb8a1a1cSAlberto Garcia     bkt.burst_length = 2; /* otherwise burst_level will not leak */
69eb8a1a1cSAlberto Garcia     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100);
70eb8a1a1cSAlberto Garcia     g_assert(double_cmp(bkt.burst_level, 3.5));
71eb8a1a1cSAlberto Garcia 
72eb8a1a1cSAlberto Garcia     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100);
73eb8a1a1cSAlberto Garcia     g_assert(double_cmp(bkt.burst_level, 1));
74eb8a1a1cSAlberto Garcia 
75eb8a1a1cSAlberto Garcia     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100);
76eb8a1a1cSAlberto Garcia     g_assert(double_cmp(bkt.burst_level, 0));
77eb8a1a1cSAlberto Garcia 
78eb8a1a1cSAlberto Garcia     throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100);
79eb8a1a1cSAlberto Garcia     g_assert(double_cmp(bkt.burst_level, 0));
80f17cfe81SBenoît Canet }
81f17cfe81SBenoît Canet 
82f17cfe81SBenoît Canet static void test_compute_wait(void)
83f17cfe81SBenoît Canet {
84f9d05885SAlberto Garcia     unsigned i;
85f17cfe81SBenoît Canet     int64_t wait;
86f17cfe81SBenoît Canet     int64_t result;
87f17cfe81SBenoît Canet 
881588ab5dSAlberto Garcia     throttle_config_init(&cfg);
891588ab5dSAlberto Garcia     bkt = cfg.buckets[THROTTLE_BPS_TOTAL];
901588ab5dSAlberto Garcia 
91f17cfe81SBenoît Canet     /* no operation limit set */
92f17cfe81SBenoît Canet     bkt.avg = 0;
93f17cfe81SBenoît Canet     bkt.max = 15;
94f17cfe81SBenoît Canet     bkt.level = 1.5;
95f17cfe81SBenoît Canet     wait = throttle_compute_wait(&bkt);
96f17cfe81SBenoît Canet     g_assert(!wait);
97f17cfe81SBenoît Canet 
98f17cfe81SBenoît Canet     /* zero delta */
99f17cfe81SBenoît Canet     bkt.avg = 150;
100f17cfe81SBenoît Canet     bkt.max = 15;
101f17cfe81SBenoît Canet     bkt.level = 15;
102f17cfe81SBenoît Canet     wait = throttle_compute_wait(&bkt);
103f17cfe81SBenoît Canet     g_assert(!wait);
104f17cfe81SBenoît Canet 
105f17cfe81SBenoît Canet     /* below zero delta */
106f17cfe81SBenoît Canet     bkt.avg = 150;
107f17cfe81SBenoît Canet     bkt.max = 15;
108f17cfe81SBenoît Canet     bkt.level = 9;
109f17cfe81SBenoît Canet     wait = throttle_compute_wait(&bkt);
110f17cfe81SBenoît Canet     g_assert(!wait);
111f17cfe81SBenoît Canet 
112f17cfe81SBenoît Canet     /* half an operation above max */
113f17cfe81SBenoît Canet     bkt.avg = 150;
114f17cfe81SBenoît Canet     bkt.max = 15;
115f17cfe81SBenoît Canet     bkt.level = 15.5;
116f17cfe81SBenoît Canet     wait = throttle_compute_wait(&bkt);
117f17cfe81SBenoît Canet     /* time required to do half an operation */
11813566fe3SStefan Hajnoczi     result = (int64_t)  NANOSECONDS_PER_SECOND / 150 / 2;
119f17cfe81SBenoît Canet     g_assert(wait == result);
120f9d05885SAlberto Garcia 
121f9d05885SAlberto Garcia     /* Perform I/O for 2.2 seconds at a rate of bkt.max */
122f9d05885SAlberto Garcia     bkt.burst_length = 2;
123f9d05885SAlberto Garcia     bkt.level = 0;
124f9d05885SAlberto Garcia     bkt.avg = 10;
125f9d05885SAlberto Garcia     bkt.max = 200;
126f9d05885SAlberto Garcia     for (i = 0; i < 22; i++) {
127f9d05885SAlberto Garcia         double units = bkt.max / 10;
128f9d05885SAlberto Garcia         bkt.level += units;
129f9d05885SAlberto Garcia         bkt.burst_level += units;
130f9d05885SAlberto Garcia         throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 10);
131f9d05885SAlberto Garcia         wait = throttle_compute_wait(&bkt);
132f9d05885SAlberto Garcia         g_assert(double_cmp(bkt.burst_level, 0));
133f9d05885SAlberto Garcia         g_assert(double_cmp(bkt.level, (i + 1) * (bkt.max - bkt.avg) / 10));
134f9d05885SAlberto Garcia         /* We can do bursts for the 2 seconds we have configured in
135f9d05885SAlberto Garcia          * burst_length. We have 100 extra miliseconds of burst
136f9d05885SAlberto Garcia          * because bkt.level has been leaking during this time.
137f9d05885SAlberto Garcia          * After that, we have to wait. */
138f9d05885SAlberto Garcia         result = i < 21 ? 0 : 1.8 * NANOSECONDS_PER_SECOND;
139f9d05885SAlberto Garcia         g_assert(wait == result);
140f9d05885SAlberto Garcia     }
141f17cfe81SBenoît Canet }
142f17cfe81SBenoît Canet 
143f17cfe81SBenoît Canet /* functions to test ThrottleState initialization/destroy methods */
144f17cfe81SBenoît Canet static void read_timer_cb(void *opaque)
145f17cfe81SBenoît Canet {
146f17cfe81SBenoît Canet }
147f17cfe81SBenoît Canet 
148f17cfe81SBenoît Canet static void write_timer_cb(void *opaque)
149f17cfe81SBenoît Canet {
150f17cfe81SBenoît Canet }
151f17cfe81SBenoît Canet 
152f17cfe81SBenoît Canet static void test_init(void)
153f17cfe81SBenoît Canet {
154f17cfe81SBenoît Canet     int i;
155f17cfe81SBenoît Canet 
1560e5b0a2dSBenoît Canet     /* fill the structures with crap */
157f17cfe81SBenoît Canet     memset(&ts, 1, sizeof(ts));
1580e5b0a2dSBenoît Canet     memset(&tt, 1, sizeof(tt));
159f17cfe81SBenoît Canet 
1600e5b0a2dSBenoît Canet     /* init structures */
1610e5b0a2dSBenoît Canet     throttle_init(&ts);
1620e5b0a2dSBenoît Canet     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
16313af91ebSStefan Hajnoczi                          read_timer_cb, write_timer_cb, &ts);
164f17cfe81SBenoît Canet 
165f17cfe81SBenoît Canet     /* check initialized fields */
1660e5b0a2dSBenoît Canet     g_assert(tt.clock_type == QEMU_CLOCK_VIRTUAL);
1670e5b0a2dSBenoît Canet     g_assert(tt.timers[0]);
1680e5b0a2dSBenoît Canet     g_assert(tt.timers[1]);
169f17cfe81SBenoît Canet 
170f17cfe81SBenoît Canet     /* check other fields where cleared */
171f17cfe81SBenoît Canet     g_assert(!ts.previous_leak);
172f17cfe81SBenoît Canet     g_assert(!ts.cfg.op_size);
173f17cfe81SBenoît Canet     for (i = 0; i < BUCKETS_COUNT; i++) {
174f17cfe81SBenoît Canet         g_assert(!ts.cfg.buckets[i].avg);
175f17cfe81SBenoît Canet         g_assert(!ts.cfg.buckets[i].max);
176f17cfe81SBenoît Canet         g_assert(!ts.cfg.buckets[i].level);
177f17cfe81SBenoît Canet     }
178f17cfe81SBenoît Canet 
1790e5b0a2dSBenoît Canet     throttle_timers_destroy(&tt);
180f17cfe81SBenoît Canet }
181f17cfe81SBenoît Canet 
182f17cfe81SBenoît Canet static void test_destroy(void)
183f17cfe81SBenoît Canet {
184f17cfe81SBenoît Canet     int i;
1850e5b0a2dSBenoît Canet     throttle_init(&ts);
1860e5b0a2dSBenoît Canet     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
18713af91ebSStefan Hajnoczi                          read_timer_cb, write_timer_cb, &ts);
1880e5b0a2dSBenoît Canet     throttle_timers_destroy(&tt);
189f17cfe81SBenoît Canet     for (i = 0; i < 2; i++) {
1900e5b0a2dSBenoît Canet         g_assert(!tt.timers[i]);
191f17cfe81SBenoît Canet     }
192f17cfe81SBenoît Canet }
193f17cfe81SBenoît Canet 
194f17cfe81SBenoît Canet /* function to test throttle_config and throttle_get_config */
195f17cfe81SBenoît Canet static void test_config_functions(void)
196f17cfe81SBenoît Canet {
197f17cfe81SBenoît Canet     int i;
198f17cfe81SBenoît Canet     ThrottleConfig orig_cfg, final_cfg;
199f17cfe81SBenoît Canet 
200f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_TOTAL].avg = 153;
201f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_READ].avg  = 56;
202f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_WRITE].avg = 1;
203f17cfe81SBenoît Canet 
204f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_TOTAL].avg = 150;
205f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_READ].avg  = 69;
206f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_WRITE].avg = 23;
207f17cfe81SBenoît Canet 
208f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_TOTAL].max = 0; /* should be corrected */
209f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_READ].max  = 1; /* should not be corrected */
210f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_WRITE].max = 120;
211f17cfe81SBenoît Canet 
212f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_TOTAL].max = 150;
213f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_READ].max  = 400;
214f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_WRITE].max = 500;
215f17cfe81SBenoît Canet 
216f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_TOTAL].level = 45;
217f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_READ].level  = 65;
218f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_BPS_WRITE].level = 23;
219f17cfe81SBenoît Canet 
220f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_TOTAL].level = 1;
221f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_READ].level  = 90;
222f17cfe81SBenoît Canet     orig_cfg.buckets[THROTTLE_OPS_WRITE].level = 75;
223f17cfe81SBenoît Canet 
224f17cfe81SBenoît Canet     orig_cfg.op_size = 1;
225f17cfe81SBenoît Canet 
2260e5b0a2dSBenoît Canet     throttle_init(&ts);
2270e5b0a2dSBenoît Canet     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
22813af91ebSStefan Hajnoczi                          read_timer_cb, write_timer_cb, &ts);
229f17cfe81SBenoît Canet     /* structure reset by throttle_init previous_leak should be null */
230f17cfe81SBenoît Canet     g_assert(!ts.previous_leak);
2310e5b0a2dSBenoît Canet     throttle_config(&ts, &tt, &orig_cfg);
232f17cfe81SBenoît Canet 
233f17cfe81SBenoît Canet     /* has previous leak been initialized by throttle_config ? */
234f17cfe81SBenoît Canet     g_assert(ts.previous_leak);
235f17cfe81SBenoît Canet 
236f17cfe81SBenoît Canet     /* get back the fixed configuration */
237f17cfe81SBenoît Canet     throttle_get_config(&ts, &final_cfg);
238f17cfe81SBenoît Canet 
2390e5b0a2dSBenoît Canet     throttle_timers_destroy(&tt);
240f17cfe81SBenoît Canet 
241f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].avg == 153);
242f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_BPS_READ].avg  == 56);
243f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].avg == 1);
244f17cfe81SBenoît Canet 
245f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].avg == 150);
246f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_OPS_READ].avg  == 69);
247f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].avg == 23);
248f17cfe81SBenoît Canet 
249f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].max == 15.3);/* fixed */
250f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_BPS_READ].max  == 1);   /* not fixed */
251f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].max == 120);
252f17cfe81SBenoît Canet 
253f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].max == 150);
254f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_OPS_READ].max  == 400);
255f17cfe81SBenoît Canet     g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].max == 500);
256f17cfe81SBenoît Canet 
257f17cfe81SBenoît Canet     g_assert(final_cfg.op_size == 1);
258f17cfe81SBenoît Canet 
259f17cfe81SBenoît Canet     /* check bucket have been cleared */
260f17cfe81SBenoît Canet     for (i = 0; i < BUCKETS_COUNT; i++) {
261f17cfe81SBenoît Canet         g_assert(!final_cfg.buckets[i].level);
262f17cfe81SBenoît Canet     }
263f17cfe81SBenoît Canet }
264f17cfe81SBenoît Canet 
265f17cfe81SBenoît Canet /* functions to test is throttle is enabled by a config */
266f17cfe81SBenoît Canet static void set_cfg_value(bool is_max, int index, int value)
267f17cfe81SBenoît Canet {
268f17cfe81SBenoît Canet     if (is_max) {
269f17cfe81SBenoît Canet         cfg.buckets[index].max = value;
2706f9b6d57SAlberto Garcia         /* If max is set, avg should never be 0 */
2716f9b6d57SAlberto Garcia         cfg.buckets[index].avg = MAX(cfg.buckets[index].avg, 1);
272f17cfe81SBenoît Canet     } else {
273f17cfe81SBenoît Canet         cfg.buckets[index].avg = value;
274f17cfe81SBenoît Canet     }
275f17cfe81SBenoît Canet }
276f17cfe81SBenoît Canet 
277f17cfe81SBenoît Canet static void test_enabled(void)
278f17cfe81SBenoît Canet {
279f17cfe81SBenoît Canet     int i;
280f17cfe81SBenoît Canet 
2811588ab5dSAlberto Garcia     throttle_config_init(&cfg);
282f17cfe81SBenoît Canet     g_assert(!throttle_enabled(&cfg));
283f17cfe81SBenoît Canet 
284f17cfe81SBenoît Canet     for (i = 0; i < BUCKETS_COUNT; i++) {
2851588ab5dSAlberto Garcia         throttle_config_init(&cfg);
286f17cfe81SBenoît Canet         set_cfg_value(false, i, 150);
287f17cfe81SBenoît Canet         g_assert(throttle_enabled(&cfg));
288f17cfe81SBenoît Canet     }
289f17cfe81SBenoît Canet 
290f17cfe81SBenoît Canet     for (i = 0; i < BUCKETS_COUNT; i++) {
2911588ab5dSAlberto Garcia         throttle_config_init(&cfg);
292f17cfe81SBenoît Canet         set_cfg_value(false, i, -150);
293f17cfe81SBenoît Canet         g_assert(!throttle_enabled(&cfg));
294f17cfe81SBenoît Canet     }
295f17cfe81SBenoît Canet }
296f17cfe81SBenoît Canet 
297f17cfe81SBenoît Canet /* tests functions for throttle_conflicting */
298f17cfe81SBenoît Canet 
299f17cfe81SBenoît Canet static void test_conflicts_for_one_set(bool is_max,
300f17cfe81SBenoît Canet                                        int total,
301f17cfe81SBenoît Canet                                        int read,
302f17cfe81SBenoît Canet                                        int write)
303f17cfe81SBenoît Canet {
3041588ab5dSAlberto Garcia     throttle_config_init(&cfg);
305d5851089SAlberto Garcia     g_assert(throttle_is_valid(&cfg, NULL));
306f17cfe81SBenoît Canet 
307f17cfe81SBenoît Canet     set_cfg_value(is_max, total, 1);
308f17cfe81SBenoît Canet     set_cfg_value(is_max, read,  1);
309d5851089SAlberto Garcia     g_assert(!throttle_is_valid(&cfg, NULL));
310f17cfe81SBenoît Canet 
3111588ab5dSAlberto Garcia     throttle_config_init(&cfg);
312f17cfe81SBenoît Canet     set_cfg_value(is_max, total, 1);
313f17cfe81SBenoît Canet     set_cfg_value(is_max, write, 1);
314d5851089SAlberto Garcia     g_assert(!throttle_is_valid(&cfg, NULL));
315f17cfe81SBenoît Canet 
3161588ab5dSAlberto Garcia     throttle_config_init(&cfg);
317f17cfe81SBenoît Canet     set_cfg_value(is_max, total, 1);
318f17cfe81SBenoît Canet     set_cfg_value(is_max, read,  1);
319f17cfe81SBenoît Canet     set_cfg_value(is_max, write, 1);
320d5851089SAlberto Garcia     g_assert(!throttle_is_valid(&cfg, NULL));
321f17cfe81SBenoît Canet 
3221588ab5dSAlberto Garcia     throttle_config_init(&cfg);
323f17cfe81SBenoît Canet     set_cfg_value(is_max, total, 1);
324d5851089SAlberto Garcia     g_assert(throttle_is_valid(&cfg, NULL));
325f17cfe81SBenoît Canet 
3261588ab5dSAlberto Garcia     throttle_config_init(&cfg);
327f17cfe81SBenoît Canet     set_cfg_value(is_max, read,  1);
328f17cfe81SBenoît Canet     set_cfg_value(is_max, write, 1);
329d5851089SAlberto Garcia     g_assert(throttle_is_valid(&cfg, NULL));
330f17cfe81SBenoît Canet }
331f17cfe81SBenoît Canet 
332f17cfe81SBenoît Canet static void test_conflicting_config(void)
333f17cfe81SBenoît Canet {
334f17cfe81SBenoît Canet     /* bps average conflicts */
335f17cfe81SBenoît Canet     test_conflicts_for_one_set(false,
336f17cfe81SBenoît Canet                                THROTTLE_BPS_TOTAL,
337f17cfe81SBenoît Canet                                THROTTLE_BPS_READ,
338f17cfe81SBenoît Canet                                THROTTLE_BPS_WRITE);
339f17cfe81SBenoît Canet 
340f17cfe81SBenoît Canet     /* ops average conflicts */
341f17cfe81SBenoît Canet     test_conflicts_for_one_set(false,
342f17cfe81SBenoît Canet                                THROTTLE_OPS_TOTAL,
343f17cfe81SBenoît Canet                                THROTTLE_OPS_READ,
344f17cfe81SBenoît Canet                                THROTTLE_OPS_WRITE);
345f17cfe81SBenoît Canet 
346f17cfe81SBenoît Canet     /* bps average conflicts */
347f17cfe81SBenoît Canet     test_conflicts_for_one_set(true,
348f17cfe81SBenoît Canet                                THROTTLE_BPS_TOTAL,
349f17cfe81SBenoît Canet                                THROTTLE_BPS_READ,
350f17cfe81SBenoît Canet                                THROTTLE_BPS_WRITE);
351f17cfe81SBenoît Canet     /* ops average conflicts */
352f17cfe81SBenoît Canet     test_conflicts_for_one_set(true,
353f17cfe81SBenoît Canet                                THROTTLE_OPS_TOTAL,
354f17cfe81SBenoît Canet                                THROTTLE_OPS_READ,
355f17cfe81SBenoît Canet                                THROTTLE_OPS_WRITE);
356f17cfe81SBenoît Canet }
357f17cfe81SBenoît Canet /* functions to test the throttle_is_valid function */
358f17cfe81SBenoît Canet static void test_is_valid_for_value(int value, bool should_be_valid)
359f17cfe81SBenoît Canet {
360f17cfe81SBenoît Canet     int is_max, index;
361f17cfe81SBenoît Canet     for (is_max = 0; is_max < 2; is_max++) {
362f17cfe81SBenoît Canet         for (index = 0; index < BUCKETS_COUNT; index++) {
3631588ab5dSAlberto Garcia             throttle_config_init(&cfg);
364f17cfe81SBenoît Canet             set_cfg_value(is_max, index, value);
36503ba36c8SAlberto Garcia             g_assert(throttle_is_valid(&cfg, NULL) == should_be_valid);
366f17cfe81SBenoît Canet         }
367f17cfe81SBenoît Canet     }
368f17cfe81SBenoît Canet }
369f17cfe81SBenoît Canet 
370f17cfe81SBenoît Canet static void test_is_valid(void)
371f17cfe81SBenoît Canet {
372f17cfe81SBenoît Canet     /* negative number are invalid */
373f17cfe81SBenoît Canet     test_is_valid_for_value(-1, false);
374f17cfe81SBenoît Canet     /* zero are valids */
375f17cfe81SBenoît Canet     test_is_valid_for_value(0, true);
376f17cfe81SBenoît Canet     /* positives numers are valids */
377f17cfe81SBenoît Canet     test_is_valid_for_value(1, true);
378f17cfe81SBenoît Canet }
379f17cfe81SBenoît Canet 
38092e11a17SStefan Hajnoczi static void test_max_is_missing_limit(void)
38192e11a17SStefan Hajnoczi {
38292e11a17SStefan Hajnoczi     int i;
38392e11a17SStefan Hajnoczi 
38492e11a17SStefan Hajnoczi     for (i = 0; i < BUCKETS_COUNT; i++) {
3851588ab5dSAlberto Garcia         throttle_config_init(&cfg);
38692e11a17SStefan Hajnoczi         cfg.buckets[i].max = 100;
38792e11a17SStefan Hajnoczi         cfg.buckets[i].avg = 0;
388d5851089SAlberto Garcia         g_assert(!throttle_is_valid(&cfg, NULL));
38992e11a17SStefan Hajnoczi 
39092e11a17SStefan Hajnoczi         cfg.buckets[i].max = 0;
39192e11a17SStefan Hajnoczi         cfg.buckets[i].avg = 0;
392d5851089SAlberto Garcia         g_assert(throttle_is_valid(&cfg, NULL));
39392e11a17SStefan Hajnoczi 
39492e11a17SStefan Hajnoczi         cfg.buckets[i].max = 0;
39592e11a17SStefan Hajnoczi         cfg.buckets[i].avg = 100;
396d5851089SAlberto Garcia         g_assert(throttle_is_valid(&cfg, NULL));
3975fc8c052SAlberto Garcia 
3985fc8c052SAlberto Garcia         cfg.buckets[i].max = 30;
3995fc8c052SAlberto Garcia         cfg.buckets[i].avg = 100;
4005fc8c052SAlberto Garcia         g_assert(!throttle_is_valid(&cfg, NULL));
4015fc8c052SAlberto Garcia 
4025fc8c052SAlberto Garcia         cfg.buckets[i].max = 100;
4035fc8c052SAlberto Garcia         cfg.buckets[i].avg = 100;
4045fc8c052SAlberto Garcia         g_assert(throttle_is_valid(&cfg, NULL));
40592e11a17SStefan Hajnoczi     }
40692e11a17SStefan Hajnoczi }
40792e11a17SStefan Hajnoczi 
4088860eabdSStefan Hajnoczi static void test_iops_size_is_missing_limit(void)
4098860eabdSStefan Hajnoczi {
4108860eabdSStefan Hajnoczi     /* A total/read/write iops limit is required */
4118860eabdSStefan Hajnoczi     throttle_config_init(&cfg);
4128860eabdSStefan Hajnoczi     cfg.op_size = 4096;
4138860eabdSStefan Hajnoczi     g_assert(!throttle_is_valid(&cfg, NULL));
4148860eabdSStefan Hajnoczi }
4158860eabdSStefan Hajnoczi 
416f17cfe81SBenoît Canet static void test_have_timer(void)
417f17cfe81SBenoît Canet {
4180e5b0a2dSBenoît Canet     /* zero structures */
419f17cfe81SBenoît Canet     memset(&ts, 0, sizeof(ts));
4200e5b0a2dSBenoît Canet     memset(&tt, 0, sizeof(tt));
421f17cfe81SBenoît Canet 
42273f395faSStefan Weil     /* no timer set should return false */
4230e5b0a2dSBenoît Canet     g_assert(!throttle_timers_are_initialized(&tt));
424f17cfe81SBenoît Canet 
4250e5b0a2dSBenoît Canet     /* init structures */
4260e5b0a2dSBenoît Canet     throttle_init(&ts);
4270e5b0a2dSBenoît Canet     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
42813af91ebSStefan Hajnoczi                          read_timer_cb, write_timer_cb, &ts);
429f17cfe81SBenoît Canet 
430f17cfe81SBenoît Canet     /* timer set by init should return true */
4310e5b0a2dSBenoît Canet     g_assert(throttle_timers_are_initialized(&tt));
432f17cfe81SBenoît Canet 
4330e5b0a2dSBenoît Canet     throttle_timers_destroy(&tt);
434f17cfe81SBenoît Canet }
435f17cfe81SBenoît Canet 
43622524f72SStefan Hajnoczi static void test_detach_attach(void)
43722524f72SStefan Hajnoczi {
4380e5b0a2dSBenoît Canet     /* zero structures */
43922524f72SStefan Hajnoczi     memset(&ts, 0, sizeof(ts));
4400e5b0a2dSBenoît Canet     memset(&tt, 0, sizeof(tt));
44122524f72SStefan Hajnoczi 
44222524f72SStefan Hajnoczi     /* init the structure */
4430e5b0a2dSBenoît Canet     throttle_init(&ts);
4440e5b0a2dSBenoît Canet     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
44522524f72SStefan Hajnoczi                          read_timer_cb, write_timer_cb, &ts);
44622524f72SStefan Hajnoczi 
44722524f72SStefan Hajnoczi     /* timer set by init should return true */
4480e5b0a2dSBenoît Canet     g_assert(throttle_timers_are_initialized(&tt));
44922524f72SStefan Hajnoczi 
45022524f72SStefan Hajnoczi     /* timer should no longer exist after detaching */
4510e5b0a2dSBenoît Canet     throttle_timers_detach_aio_context(&tt);
4520e5b0a2dSBenoît Canet     g_assert(!throttle_timers_are_initialized(&tt));
45322524f72SStefan Hajnoczi 
45422524f72SStefan Hajnoczi     /* timer should exist again after attaching */
4550e5b0a2dSBenoît Canet     throttle_timers_attach_aio_context(&tt, ctx);
4560e5b0a2dSBenoît Canet     g_assert(throttle_timers_are_initialized(&tt));
45722524f72SStefan Hajnoczi 
4580e5b0a2dSBenoît Canet     throttle_timers_destroy(&tt);
45922524f72SStefan Hajnoczi }
46022524f72SStefan Hajnoczi 
461f17cfe81SBenoît Canet static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
462f17cfe81SBenoît Canet                 int size,                   /* size of the operation to do */
463f17cfe81SBenoît Canet                 double avg,                 /* io limit */
464f17cfe81SBenoît Canet                 uint64_t op_size,           /* ideal size of an io */
465f17cfe81SBenoît Canet                 double total_result,
466f17cfe81SBenoît Canet                 double read_result,
467f17cfe81SBenoît Canet                 double write_result)
468f17cfe81SBenoît Canet {
469f17cfe81SBenoît Canet     BucketType to_test[2][3] = { { THROTTLE_BPS_TOTAL,
470f17cfe81SBenoît Canet                                    THROTTLE_BPS_READ,
471f17cfe81SBenoît Canet                                    THROTTLE_BPS_WRITE, },
472f17cfe81SBenoît Canet                                  { THROTTLE_OPS_TOTAL,
473f17cfe81SBenoît Canet                                    THROTTLE_OPS_READ,
474f17cfe81SBenoît Canet                                    THROTTLE_OPS_WRITE, } };
475f17cfe81SBenoît Canet     ThrottleConfig cfg;
476f17cfe81SBenoît Canet     BucketType index;
477f17cfe81SBenoît Canet     int i;
478f17cfe81SBenoît Canet 
479f17cfe81SBenoît Canet     for (i = 0; i < 3; i++) {
480f17cfe81SBenoît Canet         BucketType index = to_test[is_ops][i];
481f17cfe81SBenoît Canet         cfg.buckets[index].avg = avg;
482f17cfe81SBenoît Canet     }
483f17cfe81SBenoît Canet 
484f17cfe81SBenoît Canet     cfg.op_size = op_size;
485f17cfe81SBenoît Canet 
4860e5b0a2dSBenoît Canet     throttle_init(&ts);
4870e5b0a2dSBenoît Canet     throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
48813af91ebSStefan Hajnoczi                          read_timer_cb, write_timer_cb, &ts);
4890e5b0a2dSBenoît Canet     throttle_config(&ts, &tt, &cfg);
490f17cfe81SBenoît Canet 
491f17cfe81SBenoît Canet     /* account a read */
492f17cfe81SBenoît Canet     throttle_account(&ts, false, size);
493f17cfe81SBenoît Canet     /* account a write */
494f17cfe81SBenoît Canet     throttle_account(&ts, true, size);
495f17cfe81SBenoît Canet 
496f17cfe81SBenoît Canet     /* check total result */
497f17cfe81SBenoît Canet     index = to_test[is_ops][0];
498f17cfe81SBenoît Canet     if (!double_cmp(ts.cfg.buckets[index].level, total_result)) {
499f17cfe81SBenoît Canet         return false;
500f17cfe81SBenoît Canet     }
501f17cfe81SBenoît Canet 
502f17cfe81SBenoît Canet     /* check read result */
503f17cfe81SBenoît Canet     index = to_test[is_ops][1];
504f17cfe81SBenoît Canet     if (!double_cmp(ts.cfg.buckets[index].level, read_result)) {
505f17cfe81SBenoît Canet         return false;
506f17cfe81SBenoît Canet     }
507f17cfe81SBenoît Canet 
508f17cfe81SBenoît Canet     /* check write result */
509f17cfe81SBenoît Canet     index = to_test[is_ops][2];
510f17cfe81SBenoît Canet     if (!double_cmp(ts.cfg.buckets[index].level, write_result)) {
511f17cfe81SBenoît Canet         return false;
512f17cfe81SBenoît Canet     }
513f17cfe81SBenoît Canet 
5140e5b0a2dSBenoît Canet     throttle_timers_destroy(&tt);
515f17cfe81SBenoît Canet 
516f17cfe81SBenoît Canet     return true;
517f17cfe81SBenoît Canet }
518f17cfe81SBenoît Canet 
519f17cfe81SBenoît Canet static void test_accounting(void)
520f17cfe81SBenoît Canet {
521f17cfe81SBenoît Canet     /* tests for bps */
522f17cfe81SBenoît Canet 
523f17cfe81SBenoît Canet     /* op of size 1 */
524f17cfe81SBenoît Canet     g_assert(do_test_accounting(false,
525f17cfe81SBenoît Canet                                 1 * 512,
526f17cfe81SBenoît Canet                                 150,
527f17cfe81SBenoît Canet                                 0,
528f17cfe81SBenoît Canet                                 1024,
529f17cfe81SBenoît Canet                                 512,
530f17cfe81SBenoît Canet                                 512));
531f17cfe81SBenoît Canet 
532f17cfe81SBenoît Canet     /* op of size 2 */
533f17cfe81SBenoît Canet     g_assert(do_test_accounting(false,
534f17cfe81SBenoît Canet                                 2 * 512,
535f17cfe81SBenoît Canet                                 150,
536f17cfe81SBenoît Canet                                 0,
537f17cfe81SBenoît Canet                                 2048,
538f17cfe81SBenoît Canet                                 1024,
539f17cfe81SBenoît Canet                                 1024));
540f17cfe81SBenoît Canet 
541f17cfe81SBenoît Canet     /* op of size 2 and orthogonal parameter change */
542f17cfe81SBenoît Canet     g_assert(do_test_accounting(false,
543f17cfe81SBenoît Canet                                 2 * 512,
544f17cfe81SBenoît Canet                                 150,
545f17cfe81SBenoît Canet                                 17,
546f17cfe81SBenoît Canet                                 2048,
547f17cfe81SBenoît Canet                                 1024,
548f17cfe81SBenoît Canet                                 1024));
549f17cfe81SBenoît Canet 
550f17cfe81SBenoît Canet 
551f17cfe81SBenoît Canet     /* tests for ops */
552f17cfe81SBenoît Canet 
553f17cfe81SBenoît Canet     /* op of size 1 */
554f17cfe81SBenoît Canet     g_assert(do_test_accounting(true,
555f17cfe81SBenoît Canet                                 1 * 512,
556f17cfe81SBenoît Canet                                 150,
557f17cfe81SBenoît Canet                                 0,
558f17cfe81SBenoît Canet                                 2,
559f17cfe81SBenoît Canet                                 1,
560f17cfe81SBenoît Canet                                 1));
561f17cfe81SBenoît Canet 
562f17cfe81SBenoît Canet     /* op of size 2 */
563f17cfe81SBenoît Canet     g_assert(do_test_accounting(true,
564f17cfe81SBenoît Canet                                 2 *  512,
565f17cfe81SBenoît Canet                                 150,
566f17cfe81SBenoît Canet                                 0,
567f17cfe81SBenoît Canet                                 2,
568f17cfe81SBenoît Canet                                 1,
569f17cfe81SBenoît Canet                                 1));
570f17cfe81SBenoît Canet 
571f17cfe81SBenoît Canet     /* jumbo op accounting fragmentation : size 64 with op size of 13 units */
572f17cfe81SBenoît Canet     g_assert(do_test_accounting(true,
573f17cfe81SBenoît Canet                                 64 * 512,
574f17cfe81SBenoît Canet                                 150,
575f17cfe81SBenoît Canet                                 13 * 512,
576f17cfe81SBenoît Canet                                 (64.0 * 2) / 13,
577f17cfe81SBenoît Canet                                 (64.0 / 13),
578f17cfe81SBenoît Canet                                 (64.0 / 13)));
579f17cfe81SBenoît Canet 
580f17cfe81SBenoît Canet     /* same with orthogonal parameters changes */
581f17cfe81SBenoît Canet     g_assert(do_test_accounting(true,
582f17cfe81SBenoît Canet                                 64 * 512,
583f17cfe81SBenoît Canet                                 300,
584f17cfe81SBenoît Canet                                 13 * 512,
585f17cfe81SBenoît Canet                                 (64.0 * 2) / 13,
586f17cfe81SBenoît Canet                                 (64.0 / 13),
587f17cfe81SBenoît Canet                                 (64.0 / 13)));
588f17cfe81SBenoît Canet }
589f17cfe81SBenoît Canet 
5901fee955fSAlberto Garcia static void test_groups(void)
5911fee955fSAlberto Garcia {
5921fee955fSAlberto Garcia     ThrottleConfig cfg1, cfg2;
593a5614993SKevin Wolf     BlockBackend *blk1, *blk2, *blk3;
59427ccdd52SKevin Wolf     BlockBackendPublic *blkp1, *blkp2, *blkp3;
5951fee955fSAlberto Garcia 
596*6d0eb64dSKevin Wolf     /* FIXME Use real permissions */
597*6d0eb64dSKevin Wolf     blk1 = blk_new(0, BLK_PERM_ALL);
598*6d0eb64dSKevin Wolf     blk2 = blk_new(0, BLK_PERM_ALL);
599*6d0eb64dSKevin Wolf     blk3 = blk_new(0, BLK_PERM_ALL);
600a5614993SKevin Wolf 
60127ccdd52SKevin Wolf     blkp1 = blk_get_public(blk1);
60227ccdd52SKevin Wolf     blkp2 = blk_get_public(blk2);
60327ccdd52SKevin Wolf     blkp3 = blk_get_public(blk3);
60427ccdd52SKevin Wolf 
60527ccdd52SKevin Wolf     g_assert(blkp1->throttle_state == NULL);
60627ccdd52SKevin Wolf     g_assert(blkp2->throttle_state == NULL);
60727ccdd52SKevin Wolf     g_assert(blkp3->throttle_state == NULL);
6081fee955fSAlberto Garcia 
60931dce3ccSKevin Wolf     throttle_group_register_blk(blk1, "bar");
61031dce3ccSKevin Wolf     throttle_group_register_blk(blk2, "foo");
61131dce3ccSKevin Wolf     throttle_group_register_blk(blk3, "bar");
6121fee955fSAlberto Garcia 
61327ccdd52SKevin Wolf     g_assert(blkp1->throttle_state != NULL);
61427ccdd52SKevin Wolf     g_assert(blkp2->throttle_state != NULL);
61527ccdd52SKevin Wolf     g_assert(blkp3->throttle_state != NULL);
6161fee955fSAlberto Garcia 
61749d2165dSKevin Wolf     g_assert(!strcmp(throttle_group_get_name(blk1), "bar"));
61849d2165dSKevin Wolf     g_assert(!strcmp(throttle_group_get_name(blk2), "foo"));
61927ccdd52SKevin Wolf     g_assert(blkp1->throttle_state == blkp3->throttle_state);
6201fee955fSAlberto Garcia 
6211fee955fSAlberto Garcia     /* Setting the config of a group member affects the whole group */
6221588ab5dSAlberto Garcia     throttle_config_init(&cfg1);
6231fee955fSAlberto Garcia     cfg1.buckets[THROTTLE_BPS_READ].avg  = 500000;
6241fee955fSAlberto Garcia     cfg1.buckets[THROTTLE_BPS_WRITE].avg = 285000;
6251fee955fSAlberto Garcia     cfg1.buckets[THROTTLE_OPS_READ].avg  = 20000;
6261fee955fSAlberto Garcia     cfg1.buckets[THROTTLE_OPS_WRITE].avg = 12000;
62797148076SKevin Wolf     throttle_group_config(blk1, &cfg1);
6281fee955fSAlberto Garcia 
62997148076SKevin Wolf     throttle_group_get_config(blk1, &cfg1);
63097148076SKevin Wolf     throttle_group_get_config(blk3, &cfg2);
6311fee955fSAlberto Garcia     g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
6321fee955fSAlberto Garcia 
6331fee955fSAlberto Garcia     cfg2.buckets[THROTTLE_BPS_READ].avg  = 4547;
6341fee955fSAlberto Garcia     cfg2.buckets[THROTTLE_BPS_WRITE].avg = 1349;
6351fee955fSAlberto Garcia     cfg2.buckets[THROTTLE_OPS_READ].avg  = 123;
6361fee955fSAlberto Garcia     cfg2.buckets[THROTTLE_OPS_WRITE].avg = 86;
63797148076SKevin Wolf     throttle_group_config(blk3, &cfg1);
6381fee955fSAlberto Garcia 
63997148076SKevin Wolf     throttle_group_get_config(blk1, &cfg1);
64097148076SKevin Wolf     throttle_group_get_config(blk3, &cfg2);
6411fee955fSAlberto Garcia     g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
6421fee955fSAlberto Garcia 
64331dce3ccSKevin Wolf     throttle_group_unregister_blk(blk1);
64431dce3ccSKevin Wolf     throttle_group_unregister_blk(blk2);
64531dce3ccSKevin Wolf     throttle_group_unregister_blk(blk3);
6461fee955fSAlberto Garcia 
64727ccdd52SKevin Wolf     g_assert(blkp1->throttle_state == NULL);
64827ccdd52SKevin Wolf     g_assert(blkp2->throttle_state == NULL);
64927ccdd52SKevin Wolf     g_assert(blkp3->throttle_state == NULL);
6501fee955fSAlberto Garcia }
6511fee955fSAlberto Garcia 
652f17cfe81SBenoît Canet int main(int argc, char **argv)
653f17cfe81SBenoît Canet {
65473eaa047SMarkus Armbruster     qemu_init_main_loop(&error_fatal);
6551fee955fSAlberto Garcia     ctx = qemu_get_aio_context();
6561fee955fSAlberto Garcia     bdrv_init();
65713af91ebSStefan Hajnoczi 
658f17cfe81SBenoît Canet     do {} while (g_main_context_iteration(NULL, false));
659f17cfe81SBenoît Canet 
660f17cfe81SBenoît Canet     /* tests in the same order as the header function declarations */
661f17cfe81SBenoît Canet     g_test_init(&argc, &argv, NULL);
662f17cfe81SBenoît Canet     g_test_add_func("/throttle/leak_bucket",        test_leak_bucket);
663f17cfe81SBenoît Canet     g_test_add_func("/throttle/compute_wait",       test_compute_wait);
664f17cfe81SBenoît Canet     g_test_add_func("/throttle/init",               test_init);
665f17cfe81SBenoît Canet     g_test_add_func("/throttle/destroy",            test_destroy);
666f17cfe81SBenoît Canet     g_test_add_func("/throttle/have_timer",         test_have_timer);
66722524f72SStefan Hajnoczi     g_test_add_func("/throttle/detach_attach",      test_detach_attach);
668f17cfe81SBenoît Canet     g_test_add_func("/throttle/config/enabled",     test_enabled);
669f17cfe81SBenoît Canet     g_test_add_func("/throttle/config/conflicting", test_conflicting_config);
670f17cfe81SBenoît Canet     g_test_add_func("/throttle/config/is_valid",    test_is_valid);
67192e11a17SStefan Hajnoczi     g_test_add_func("/throttle/config/max",         test_max_is_missing_limit);
6728860eabdSStefan Hajnoczi     g_test_add_func("/throttle/config/iops_size",
6738860eabdSStefan Hajnoczi                     test_iops_size_is_missing_limit);
674f17cfe81SBenoît Canet     g_test_add_func("/throttle/config_functions",   test_config_functions);
675f17cfe81SBenoît Canet     g_test_add_func("/throttle/accounting",         test_accounting);
6761fee955fSAlberto Garcia     g_test_add_func("/throttle/groups",             test_groups);
677f17cfe81SBenoît Canet     return g_test_run();
678f17cfe81SBenoît Canet }
679f17cfe81SBenoît Canet 
680