qemu/tests/unit/test-throttle.c
<<
>>
Prefs
   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
  26static AioContext     *ctx;
  27static LeakyBucket    bkt;
  28static ThrottleConfig cfg;
  29static ThrottleGroupMember tgm;
  30static ThrottleState  ts;
  31static ThrottleTimers *tt;
  32
  33/* useful function */
  34static bool double_cmp(double x, double y)
  35{
  36    return fabsl(x - y) < 1e-6;
  37}
  38
  39/* tests for single bucket operations */
  40static 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
  85static 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;
 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));
 137        /* We can do bursts for the 2 seconds we have configured in
 138         * burst_length. We have 100 extra miliseconds 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 */
 147static void read_timer_cb(void *opaque)
 148{
 149}
 150
 151static void write_timer_cb(void *opaque)
 152{
 153}
 154
 155static 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[0]);
 173    g_assert(tt->timers[1]);
 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
 187static void test_destroy(void)
 188{
 189    int i;
 190    throttle_init(&ts);
 191    throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
 192                         read_timer_cb, write_timer_cb, &ts);
 193    throttle_timers_destroy(tt);
 194    for (i = 0; i < 2; i++) {
 195        g_assert(!tt->timers[i]);
 196    }
 197}
 198
 199/* function to test throttle_config and throttle_get_config */
 200static void test_config_functions(void)
 201{
 202    int i;
 203    ThrottleConfig orig_cfg, final_cfg;
 204
 205    orig_cfg.buckets[THROTTLE_BPS_TOTAL].avg = 153;
 206    orig_cfg.buckets[THROTTLE_BPS_READ].avg  = 56;
 207    orig_cfg.buckets[THROTTLE_BPS_WRITE].avg = 1;
 208
 209    orig_cfg.buckets[THROTTLE_OPS_TOTAL].avg = 150;
 210    orig_cfg.buckets[THROTTLE_OPS_READ].avg  = 69;
 211    orig_cfg.buckets[THROTTLE_OPS_WRITE].avg = 23;
 212
 213    orig_cfg.buckets[THROTTLE_BPS_TOTAL].max = 0;
 214    orig_cfg.buckets[THROTTLE_BPS_READ].max  = 56;
 215    orig_cfg.buckets[THROTTLE_BPS_WRITE].max = 120;
 216
 217    orig_cfg.buckets[THROTTLE_OPS_TOTAL].max = 150;
 218    orig_cfg.buckets[THROTTLE_OPS_READ].max  = 400;
 219    orig_cfg.buckets[THROTTLE_OPS_WRITE].max = 500;
 220
 221    orig_cfg.buckets[THROTTLE_BPS_TOTAL].level = 45;
 222    orig_cfg.buckets[THROTTLE_BPS_READ].level  = 65;
 223    orig_cfg.buckets[THROTTLE_BPS_WRITE].level = 23;
 224
 225    orig_cfg.buckets[THROTTLE_OPS_TOTAL].level = 1;
 226    orig_cfg.buckets[THROTTLE_OPS_READ].level  = 90;
 227    orig_cfg.buckets[THROTTLE_OPS_WRITE].level = 75;
 228
 229    orig_cfg.op_size = 1;
 230
 231    throttle_init(&ts);
 232    throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
 233                         read_timer_cb, write_timer_cb, &ts);
 234    /* structure reset by throttle_init previous_leak should be null */
 235    g_assert(!ts.previous_leak);
 236    throttle_config(&ts, QEMU_CLOCK_VIRTUAL, &orig_cfg);
 237
 238    /* has previous leak been initialized by throttle_config ? */
 239    g_assert(ts.previous_leak);
 240
 241    /* get back the fixed configuration */
 242    throttle_get_config(&ts, &final_cfg);
 243
 244    throttle_timers_destroy(tt);
 245
 246    g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].avg == 153);
 247    g_assert(final_cfg.buckets[THROTTLE_BPS_READ].avg  == 56);
 248    g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].avg == 1);
 249
 250    g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].avg == 150);
 251    g_assert(final_cfg.buckets[THROTTLE_OPS_READ].avg  == 69);
 252    g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].avg == 23);
 253
 254    g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].max == 0);
 255    g_assert(final_cfg.buckets[THROTTLE_BPS_READ].max  == 56);
 256    g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].max == 120);
 257
 258    g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].max == 150);
 259    g_assert(final_cfg.buckets[THROTTLE_OPS_READ].max  == 400);
 260    g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].max == 500);
 261
 262    g_assert(final_cfg.op_size == 1);
 263
 264    /* check bucket have been cleared */
 265    for (i = 0; i < BUCKETS_COUNT; i++) {
 266        g_assert(!final_cfg.buckets[i].level);
 267    }
 268}
 269
 270/* functions to test is throttle is enabled by a config */
 271static void set_cfg_value(bool is_max, int index, int value)
 272{
 273    if (is_max) {
 274        cfg.buckets[index].max = value;
 275        /* If max is set, avg should never be 0 */
 276        cfg.buckets[index].avg = MAX(cfg.buckets[index].avg, 1);
 277    } else {
 278        cfg.buckets[index].avg = value;
 279    }
 280}
 281
 282static void test_enabled(void)
 283{
 284    int i;
 285
 286    throttle_config_init(&cfg);
 287    g_assert(!throttle_enabled(&cfg));
 288
 289    for (i = 0; i < BUCKETS_COUNT; i++) {
 290        throttle_config_init(&cfg);
 291        set_cfg_value(false, i, 150);
 292        g_assert(throttle_is_valid(&cfg, NULL));
 293        g_assert(throttle_enabled(&cfg));
 294    }
 295
 296    for (i = 0; i < BUCKETS_COUNT; i++) {
 297        throttle_config_init(&cfg);
 298        set_cfg_value(false, i, -150);
 299        g_assert(!throttle_is_valid(&cfg, NULL));
 300    }
 301}
 302
 303/* tests functions for throttle_conflicting */
 304
 305static void test_conflicts_for_one_set(bool is_max,
 306                                       int total,
 307                                       int read,
 308                                       int write)
 309{
 310    throttle_config_init(&cfg);
 311    g_assert(throttle_is_valid(&cfg, NULL));
 312
 313    set_cfg_value(is_max, total, 1);
 314    set_cfg_value(is_max, read,  1);
 315    g_assert(!throttle_is_valid(&cfg, NULL));
 316
 317    throttle_config_init(&cfg);
 318    set_cfg_value(is_max, total, 1);
 319    set_cfg_value(is_max, write, 1);
 320    g_assert(!throttle_is_valid(&cfg, NULL));
 321
 322    throttle_config_init(&cfg);
 323    set_cfg_value(is_max, total, 1);
 324    set_cfg_value(is_max, read,  1);
 325    set_cfg_value(is_max, write, 1);
 326    g_assert(!throttle_is_valid(&cfg, NULL));
 327
 328    throttle_config_init(&cfg);
 329    set_cfg_value(is_max, total, 1);
 330    g_assert(throttle_is_valid(&cfg, NULL));
 331
 332    throttle_config_init(&cfg);
 333    set_cfg_value(is_max, read,  1);
 334    set_cfg_value(is_max, write, 1);
 335    g_assert(throttle_is_valid(&cfg, NULL));
 336}
 337
 338static void test_conflicting_config(void)
 339{
 340    /* bps average conflicts */
 341    test_conflicts_for_one_set(false,
 342                               THROTTLE_BPS_TOTAL,
 343                               THROTTLE_BPS_READ,
 344                               THROTTLE_BPS_WRITE);
 345
 346    /* ops average conflicts */
 347    test_conflicts_for_one_set(false,
 348                               THROTTLE_OPS_TOTAL,
 349                               THROTTLE_OPS_READ,
 350                               THROTTLE_OPS_WRITE);
 351
 352    /* bps average conflicts */
 353    test_conflicts_for_one_set(true,
 354                               THROTTLE_BPS_TOTAL,
 355                               THROTTLE_BPS_READ,
 356                               THROTTLE_BPS_WRITE);
 357    /* ops average conflicts */
 358    test_conflicts_for_one_set(true,
 359                               THROTTLE_OPS_TOTAL,
 360                               THROTTLE_OPS_READ,
 361                               THROTTLE_OPS_WRITE);
 362}
 363/* functions to test the throttle_is_valid function */
 364static void test_is_valid_for_value(int value, bool should_be_valid)
 365{
 366    int is_max, index;
 367    for (is_max = 0; is_max < 2; is_max++) {
 368        for (index = 0; index < BUCKETS_COUNT; index++) {
 369            throttle_config_init(&cfg);
 370            set_cfg_value(is_max, index, value);
 371            g_assert(throttle_is_valid(&cfg, NULL) == should_be_valid);
 372        }
 373    }
 374}
 375
 376static void test_is_valid(void)
 377{
 378    /* negative number are invalid */
 379    test_is_valid_for_value(-1, false);
 380    /* zero are valids */
 381    test_is_valid_for_value(0, true);
 382    /* positives numers are valids */
 383    test_is_valid_for_value(1, true);
 384}
 385
 386static void test_ranges(void)
 387{
 388    int i;
 389
 390    for (i = 0; i < BUCKETS_COUNT; i++) {
 391        LeakyBucket *b = &cfg.buckets[i];
 392        throttle_config_init(&cfg);
 393
 394        /* avg = 0 means throttling is disabled, but the config is valid */
 395        b->avg = 0;
 396        g_assert(throttle_is_valid(&cfg, NULL));
 397        g_assert(!throttle_enabled(&cfg));
 398
 399        /* These are valid configurations (values <= THROTTLE_VALUE_MAX) */
 400        b->avg = 1;
 401        g_assert(throttle_is_valid(&cfg, NULL));
 402
 403        b->avg = THROTTLE_VALUE_MAX;
 404        g_assert(throttle_is_valid(&cfg, NULL));
 405
 406        b->avg = THROTTLE_VALUE_MAX;
 407        b->max = THROTTLE_VALUE_MAX;
 408        g_assert(throttle_is_valid(&cfg, NULL));
 409
 410        /* Values over THROTTLE_VALUE_MAX are not allowed */
 411        b->avg = THROTTLE_VALUE_MAX + 1;
 412        g_assert(!throttle_is_valid(&cfg, NULL));
 413
 414        b->avg = THROTTLE_VALUE_MAX;
 415        b->max = THROTTLE_VALUE_MAX + 1;
 416        g_assert(!throttle_is_valid(&cfg, NULL));
 417
 418        /* burst_length must be between 1 and THROTTLE_VALUE_MAX */
 419        b->avg = 1;
 420        b->max = 1;
 421        b->burst_length = 0;
 422        g_assert(!throttle_is_valid(&cfg, NULL));
 423
 424        b->avg = 1;
 425        b->max = 1;
 426        b->burst_length = 1;
 427        g_assert(throttle_is_valid(&cfg, NULL));
 428
 429        b->avg = 1;
 430        b->max = 1;
 431        b->burst_length = THROTTLE_VALUE_MAX;
 432        g_assert(throttle_is_valid(&cfg, NULL));
 433
 434        b->avg = 1;
 435        b->max = 1;
 436        b->burst_length = THROTTLE_VALUE_MAX + 1;
 437        g_assert(!throttle_is_valid(&cfg, NULL));
 438
 439        /* burst_length * max cannot exceed THROTTLE_VALUE_MAX */
 440        b->avg = 1;
 441        b->max = 2;
 442        b->burst_length = THROTTLE_VALUE_MAX / 2;
 443        g_assert(throttle_is_valid(&cfg, NULL));
 444
 445        b->avg = 1;
 446        b->max = 3;
 447        b->burst_length = THROTTLE_VALUE_MAX / 2;
 448        g_assert(!throttle_is_valid(&cfg, NULL));
 449
 450        b->avg = 1;
 451        b->max = THROTTLE_VALUE_MAX;
 452        b->burst_length = 1;
 453        g_assert(throttle_is_valid(&cfg, NULL));
 454
 455        b->avg = 1;
 456        b->max = THROTTLE_VALUE_MAX;
 457        b->burst_length = 2;
 458        g_assert(!throttle_is_valid(&cfg, NULL));
 459    }
 460}
 461
 462static void test_max_is_missing_limit(void)
 463{
 464    int i;
 465
 466    for (i = 0; i < BUCKETS_COUNT; i++) {
 467        throttle_config_init(&cfg);
 468        cfg.buckets[i].max = 100;
 469        cfg.buckets[i].avg = 0;
 470        g_assert(!throttle_is_valid(&cfg, NULL));
 471
 472        cfg.buckets[i].max = 0;
 473        cfg.buckets[i].avg = 0;
 474        g_assert(throttle_is_valid(&cfg, NULL));
 475
 476        cfg.buckets[i].max = 0;
 477        cfg.buckets[i].avg = 100;
 478        g_assert(throttle_is_valid(&cfg, NULL));
 479
 480        cfg.buckets[i].max = 30;
 481        cfg.buckets[i].avg = 100;
 482        g_assert(!throttle_is_valid(&cfg, NULL));
 483
 484        cfg.buckets[i].max = 100;
 485        cfg.buckets[i].avg = 100;
 486        g_assert(throttle_is_valid(&cfg, NULL));
 487    }
 488}
 489
 490static void test_iops_size_is_missing_limit(void)
 491{
 492    /* A total/read/write iops limit is required */
 493    throttle_config_init(&cfg);
 494    cfg.op_size = 4096;
 495    g_assert(!throttle_is_valid(&cfg, NULL));
 496}
 497
 498static void test_have_timer(void)
 499{
 500    /* zero structures */
 501    memset(&ts, 0, sizeof(ts));
 502    memset(tt, 0, sizeof(*tt));
 503
 504    /* no timer set should return false */
 505    g_assert(!throttle_timers_are_initialized(tt));
 506
 507    /* init structures */
 508    throttle_init(&ts);
 509    throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
 510                         read_timer_cb, write_timer_cb, &ts);
 511
 512    /* timer set by init should return true */
 513    g_assert(throttle_timers_are_initialized(tt));
 514
 515    throttle_timers_destroy(tt);
 516}
 517
 518static void test_detach_attach(void)
 519{
 520    /* zero structures */
 521    memset(&ts, 0, sizeof(ts));
 522    memset(tt, 0, sizeof(*tt));
 523
 524    /* init the structure */
 525    throttle_init(&ts);
 526    throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
 527                         read_timer_cb, write_timer_cb, &ts);
 528
 529    /* timer set by init should return true */
 530    g_assert(throttle_timers_are_initialized(tt));
 531
 532    /* timer should no longer exist after detaching */
 533    throttle_timers_detach_aio_context(tt);
 534    g_assert(!throttle_timers_are_initialized(tt));
 535
 536    /* timer should exist again after attaching */
 537    throttle_timers_attach_aio_context(tt, ctx);
 538    g_assert(throttle_timers_are_initialized(tt));
 539
 540    throttle_timers_destroy(tt);
 541}
 542
 543static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
 544                int size,                   /* size of the operation to do */
 545                double avg,                 /* io limit */
 546                uint64_t op_size,           /* ideal size of an io */
 547                double total_result,
 548                double read_result,
 549                double write_result)
 550{
 551    BucketType to_test[2][3] = { { THROTTLE_BPS_TOTAL,
 552                                   THROTTLE_BPS_READ,
 553                                   THROTTLE_BPS_WRITE, },
 554                                 { THROTTLE_OPS_TOTAL,
 555                                   THROTTLE_OPS_READ,
 556                                   THROTTLE_OPS_WRITE, } };
 557    ThrottleConfig cfg;
 558    BucketType index;
 559    int i;
 560
 561    throttle_config_init(&cfg);
 562
 563    for (i = 0; i < 3; i++) {
 564        BucketType index = to_test[is_ops][i];
 565        cfg.buckets[index].avg = avg;
 566    }
 567
 568    cfg.op_size = op_size;
 569
 570    throttle_init(&ts);
 571    throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
 572                         read_timer_cb, write_timer_cb, &ts);
 573    throttle_config(&ts, QEMU_CLOCK_VIRTUAL, &cfg);
 574
 575    /* account a read */
 576    throttle_account(&ts, false, size);
 577    /* account a write */
 578    throttle_account(&ts, true, size);
 579
 580    /* check total result */
 581    index = to_test[is_ops][0];
 582    if (!double_cmp(ts.cfg.buckets[index].level, total_result)) {
 583        return false;
 584    }
 585
 586    /* check read result */
 587    index = to_test[is_ops][1];
 588    if (!double_cmp(ts.cfg.buckets[index].level, read_result)) {
 589        return false;
 590    }
 591
 592    /* check write result */
 593    index = to_test[is_ops][2];
 594    if (!double_cmp(ts.cfg.buckets[index].level, write_result)) {
 595        return false;
 596    }
 597
 598    throttle_timers_destroy(tt);
 599
 600    return true;
 601}
 602
 603static void test_accounting(void)
 604{
 605    /* tests for bps */
 606
 607    /* op of size 1 */
 608    g_assert(do_test_accounting(false,
 609                                1 * 512,
 610                                150,
 611                                0,
 612                                1024,
 613                                512,
 614                                512));
 615
 616    /* op of size 2 */
 617    g_assert(do_test_accounting(false,
 618                                2 * 512,
 619                                150,
 620                                0,
 621                                2048,
 622                                1024,
 623                                1024));
 624
 625    /* op of size 2 and orthogonal parameter change */
 626    g_assert(do_test_accounting(false,
 627                                2 * 512,
 628                                150,
 629                                17,
 630                                2048,
 631                                1024,
 632                                1024));
 633
 634
 635    /* tests for ops */
 636
 637    /* op of size 1 */
 638    g_assert(do_test_accounting(true,
 639                                1 * 512,
 640                                150,
 641                                0,
 642                                2,
 643                                1,
 644                                1));
 645
 646    /* op of size 2 */
 647    g_assert(do_test_accounting(true,
 648                                2 *  512,
 649                                150,
 650                                0,
 651                                2,
 652                                1,
 653                                1));
 654
 655    /* jumbo op accounting fragmentation : size 64 with op size of 13 units */
 656    g_assert(do_test_accounting(true,
 657                                64 * 512,
 658                                150,
 659                                13 * 512,
 660                                (64.0 * 2) / 13,
 661                                (64.0 / 13),
 662                                (64.0 / 13)));
 663
 664    /* same with orthogonal parameters changes */
 665    g_assert(do_test_accounting(true,
 666                                64 * 512,
 667                                300,
 668                                13 * 512,
 669                                (64.0 * 2) / 13,
 670                                (64.0 / 13),
 671                                (64.0 / 13)));
 672}
 673
 674static void test_groups(void)
 675{
 676    ThrottleConfig cfg1, cfg2;
 677    BlockBackend *blk1, *blk2, *blk3;
 678    BlockBackendPublic *blkp1, *blkp2, *blkp3;
 679    ThrottleGroupMember *tgm1, *tgm2, *tgm3;
 680
 681    /* No actual I/O is performed on these devices */
 682    blk1 = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
 683    blk2 = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
 684    blk3 = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
 685
 686    blkp1 = blk_get_public(blk1);
 687    blkp2 = blk_get_public(blk2);
 688    blkp3 = blk_get_public(blk3);
 689
 690    tgm1 = &blkp1->throttle_group_member;
 691    tgm2 = &blkp2->throttle_group_member;
 692    tgm3 = &blkp3->throttle_group_member;
 693
 694    g_assert(tgm1->throttle_state == NULL);
 695    g_assert(tgm2->throttle_state == NULL);
 696    g_assert(tgm3->throttle_state == NULL);
 697
 698    throttle_group_register_tgm(tgm1, "bar", blk_get_aio_context(blk1));
 699    throttle_group_register_tgm(tgm2, "foo", blk_get_aio_context(blk2));
 700    throttle_group_register_tgm(tgm3, "bar", blk_get_aio_context(blk3));
 701
 702    g_assert(tgm1->throttle_state != NULL);
 703    g_assert(tgm2->throttle_state != NULL);
 704    g_assert(tgm3->throttle_state != NULL);
 705
 706    g_assert(!strcmp(throttle_group_get_name(tgm1), "bar"));
 707    g_assert(!strcmp(throttle_group_get_name(tgm2), "foo"));
 708    g_assert(tgm1->throttle_state == tgm3->throttle_state);
 709
 710    /* Setting the config of a group member affects the whole group */
 711    throttle_config_init(&cfg1);
 712    cfg1.buckets[THROTTLE_BPS_READ].avg  = 500000;
 713    cfg1.buckets[THROTTLE_BPS_WRITE].avg = 285000;
 714    cfg1.buckets[THROTTLE_OPS_READ].avg  = 20000;
 715    cfg1.buckets[THROTTLE_OPS_WRITE].avg = 12000;
 716    throttle_group_config(tgm1, &cfg1);
 717
 718    throttle_group_get_config(tgm1, &cfg1);
 719    throttle_group_get_config(tgm3, &cfg2);
 720    g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
 721
 722    cfg2.buckets[THROTTLE_BPS_READ].avg  = 4547;
 723    cfg2.buckets[THROTTLE_BPS_WRITE].avg = 1349;
 724    cfg2.buckets[THROTTLE_OPS_READ].avg  = 123;
 725    cfg2.buckets[THROTTLE_OPS_WRITE].avg = 86;
 726    throttle_group_config(tgm3, &cfg1);
 727
 728    throttle_group_get_config(tgm1, &cfg1);
 729    throttle_group_get_config(tgm3, &cfg2);
 730    g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
 731
 732    throttle_group_unregister_tgm(tgm1);
 733    throttle_group_unregister_tgm(tgm2);
 734    throttle_group_unregister_tgm(tgm3);
 735
 736    g_assert(tgm1->throttle_state == NULL);
 737    g_assert(tgm2->throttle_state == NULL);
 738    g_assert(tgm3->throttle_state == NULL);
 739}
 740
 741int main(int argc, char **argv)
 742{
 743    qemu_init_main_loop(&error_fatal);
 744    ctx = qemu_get_aio_context();
 745    bdrv_init();
 746    module_call_init(MODULE_INIT_QOM);
 747
 748    do {} while (g_main_context_iteration(NULL, false));
 749
 750    /* tests in the same order as the header function declarations */
 751    g_test_init(&argc, &argv, NULL);
 752    g_test_add_func("/throttle/leak_bucket",        test_leak_bucket);
 753    g_test_add_func("/throttle/compute_wait",       test_compute_wait);
 754    g_test_add_func("/throttle/init",               test_init);
 755    g_test_add_func("/throttle/destroy",            test_destroy);
 756    g_test_add_func("/throttle/have_timer",         test_have_timer);
 757    g_test_add_func("/throttle/detach_attach",      test_detach_attach);
 758    g_test_add_func("/throttle/config/enabled",     test_enabled);
 759    g_test_add_func("/throttle/config/conflicting", test_conflicting_config);
 760    g_test_add_func("/throttle/config/is_valid",    test_is_valid);
 761    g_test_add_func("/throttle/config/ranges",      test_ranges);
 762    g_test_add_func("/throttle/config/max",         test_max_is_missing_limit);
 763    g_test_add_func("/throttle/config/iops_size",
 764                    test_iops_size_is_missing_limit);
 765    g_test_add_func("/throttle/config_functions",   test_config_functions);
 766    g_test_add_func("/throttle/accounting",         test_accounting);
 767    g_test_add_func("/throttle/groups",             test_groups);
 768    return g_test_run();
 769}
 770
 771