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