1 /* 2 * Throttle infrastructure tests 3 * 4 * Copyright Nodalink, EURL. 2013-2014 5 * Copyright Igalia, S.L. 2015 6 * 7 * Authors: 8 * Benoît Canet <benoit.canet@nodalink.com> 9 * Alberto Garcia <berto@igalia.com> 10 * 11 * This work is licensed under the terms of the GNU LGPL, version 2 or later. 12 * See the COPYING.LIB file in the top-level directory. 13 */ 14 15 #include "qemu/osdep.h" 16 #include <math.h> 17 #include "block/aio.h" 18 #include "qapi/error.h" 19 #include "qemu/throttle.h" 20 #include "qemu/error-report.h" 21 #include "qemu/main-loop.h" 22 #include "qemu/module.h" 23 #include "block/throttle-groups.h" 24 #include "sysemu/block-backend.h" 25 26 static AioContext *ctx; 27 static LeakyBucket bkt; 28 static ThrottleConfig cfg; 29 static ThrottleGroupMember tgm; 30 static ThrottleState ts; 31 static ThrottleTimers *tt; 32 33 /* useful function */ 34 static bool double_cmp(double x, double y) 35 { 36 return fabsl(x - y) < 1e-6; 37 } 38 39 /* tests for single bucket operations */ 40 static void test_leak_bucket(void) 41 { 42 throttle_config_init(&cfg); 43 bkt = cfg.buckets[THROTTLE_BPS_TOTAL]; 44 45 /* set initial value */ 46 bkt.avg = 150; 47 bkt.max = 15; 48 bkt.level = 1.5; 49 50 /* leak an op work of time */ 51 throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150); 52 g_assert(bkt.avg == 150); 53 g_assert(bkt.max == 15); 54 g_assert(double_cmp(bkt.level, 0.5)); 55 56 /* leak again emptying the bucket */ 57 throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150); 58 g_assert(bkt.avg == 150); 59 g_assert(bkt.max == 15); 60 g_assert(double_cmp(bkt.level, 0)); 61 62 /* check that the bucket level won't go lower */ 63 throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150); 64 g_assert(bkt.avg == 150); 65 g_assert(bkt.max == 15); 66 g_assert(double_cmp(bkt.level, 0)); 67 68 /* check that burst_level leaks correctly */ 69 bkt.burst_level = 6; 70 bkt.max = 250; 71 bkt.burst_length = 2; /* otherwise burst_level will not leak */ 72 throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100); 73 g_assert(double_cmp(bkt.burst_level, 3.5)); 74 75 throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100); 76 g_assert(double_cmp(bkt.burst_level, 1)); 77 78 throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100); 79 g_assert(double_cmp(bkt.burst_level, 0)); 80 81 throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100); 82 g_assert(double_cmp(bkt.burst_level, 0)); 83 } 84 85 static void test_compute_wait(void) 86 { 87 unsigned i; 88 int64_t wait; 89 int64_t result; 90 91 throttle_config_init(&cfg); 92 bkt = cfg.buckets[THROTTLE_BPS_TOTAL]; 93 94 /* no operation limit set */ 95 bkt.avg = 0; 96 bkt.max = 15; 97 bkt.level = 1.5; 98 wait = throttle_compute_wait(&bkt); 99 g_assert(!wait); 100 101 /* zero delta */ 102 bkt.avg = 150; 103 bkt.max = 15; 104 bkt.level = 15; 105 wait = throttle_compute_wait(&bkt); 106 g_assert(!wait); 107 108 /* below zero delta */ 109 bkt.avg = 150; 110 bkt.max = 15; 111 bkt.level = 9; 112 wait = throttle_compute_wait(&bkt); 113 g_assert(!wait); 114 115 /* half an operation above max */ 116 bkt.avg = 150; 117 bkt.max = 15; 118 bkt.level = 15.5; 119 wait = throttle_compute_wait(&bkt); 120 /* time required to do half an operation */ 121 result = (int64_t) NANOSECONDS_PER_SECOND / 150 / 2; 122 g_assert(wait == result); 123 124 /* Perform I/O for 2.2 seconds at a rate of bkt.max */ 125 bkt.burst_length = 2; 126 bkt.level = 0; 127 bkt.avg = 10; 128 bkt.max = 200; 129 for (i = 0; i < 22; i++) { 130 double units = bkt.max / 10.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 */ 147 static void read_timer_cb(void *opaque) 148 { 149 } 150 151 static void write_timer_cb(void *opaque) 152 { 153 } 154 155 static void test_init(void) 156 { 157 int i; 158 159 tt = &tgm.throttle_timers; 160 161 /* fill the structures with crap */ 162 memset(&ts, 1, sizeof(ts)); 163 memset(tt, 1, sizeof(*tt)); 164 165 /* init structures */ 166 throttle_init(&ts); 167 throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL, 168 read_timer_cb, write_timer_cb, &ts); 169 170 /* check initialized fields */ 171 g_assert(tt->clock_type == QEMU_CLOCK_VIRTUAL); 172 g_assert(tt->timers[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 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 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 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 */ 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 */ 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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