qemu/tests/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 <glib.h>
  16#include <math.h>
  17#include "block/aio.h"
  18#include "qemu/throttle.h"
  19#include "qemu/error-report.h"
  20#include "block/throttle-groups.h"
  21
  22static AioContext     *ctx;
  23static LeakyBucket    bkt;
  24static ThrottleConfig cfg;
  25static ThrottleState  ts;
  26static ThrottleTimers tt;
  27
  28/* useful function */
  29static bool double_cmp(double x, double y)
  30{
  31    return fabsl(x - y) < 1e-6;
  32}
  33
  34/* tests for single bucket operations */
  35static void test_leak_bucket(void)
  36{
  37    /* set initial value */
  38    bkt.avg = 150;
  39    bkt.max = 15;
  40    bkt.level = 1.5;
  41
  42    /* leak an op work of time */
  43    throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
  44    g_assert(bkt.avg == 150);
  45    g_assert(bkt.max == 15);
  46    g_assert(double_cmp(bkt.level, 0.5));
  47
  48    /* leak again emptying the bucket */
  49    throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
  50    g_assert(bkt.avg == 150);
  51    g_assert(bkt.max == 15);
  52    g_assert(double_cmp(bkt.level, 0));
  53
  54    /* check that the bucket level won't go lower */
  55    throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
  56    g_assert(bkt.avg == 150);
  57    g_assert(bkt.max == 15);
  58    g_assert(double_cmp(bkt.level, 0));
  59}
  60
  61static void test_compute_wait(void)
  62{
  63    int64_t wait;
  64    int64_t result;
  65
  66    /* no operation limit set */
  67    bkt.avg = 0;
  68    bkt.max = 15;
  69    bkt.level = 1.5;
  70    wait = throttle_compute_wait(&bkt);
  71    g_assert(!wait);
  72
  73    /* zero delta */
  74    bkt.avg = 150;
  75    bkt.max = 15;
  76    bkt.level = 15;
  77    wait = throttle_compute_wait(&bkt);
  78    g_assert(!wait);
  79
  80    /* below zero delta */
  81    bkt.avg = 150;
  82    bkt.max = 15;
  83    bkt.level = 9;
  84    wait = throttle_compute_wait(&bkt);
  85    g_assert(!wait);
  86
  87    /* half an operation above max */
  88    bkt.avg = 150;
  89    bkt.max = 15;
  90    bkt.level = 15.5;
  91    wait = throttle_compute_wait(&bkt);
  92    /* time required to do half an operation */
  93    result = (int64_t)  NANOSECONDS_PER_SECOND / 150 / 2;
  94    g_assert(wait == result);
  95}
  96
  97/* functions to test ThrottleState initialization/destroy methods */
  98static void read_timer_cb(void *opaque)
  99{
 100}
 101
 102static void write_timer_cb(void *opaque)
 103{
 104}
 105
 106static void test_init(void)
 107{
 108    int i;
 109
 110    /* fill the structures with crap */
 111    memset(&ts, 1, sizeof(ts));
 112    memset(&tt, 1, sizeof(tt));
 113
 114    /* init structures */
 115    throttle_init(&ts);
 116    throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
 117                         read_timer_cb, write_timer_cb, &ts);
 118
 119    /* check initialized fields */
 120    g_assert(tt.clock_type == QEMU_CLOCK_VIRTUAL);
 121    g_assert(tt.timers[0]);
 122    g_assert(tt.timers[1]);
 123
 124    /* check other fields where cleared */
 125    g_assert(!ts.previous_leak);
 126    g_assert(!ts.cfg.op_size);
 127    for (i = 0; i < BUCKETS_COUNT; i++) {
 128        g_assert(!ts.cfg.buckets[i].avg);
 129        g_assert(!ts.cfg.buckets[i].max);
 130        g_assert(!ts.cfg.buckets[i].level);
 131    }
 132
 133    throttle_timers_destroy(&tt);
 134}
 135
 136static void test_destroy(void)
 137{
 138    int i;
 139    throttle_init(&ts);
 140    throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
 141                         read_timer_cb, write_timer_cb, &ts);
 142    throttle_timers_destroy(&tt);
 143    for (i = 0; i < 2; i++) {
 144        g_assert(!tt.timers[i]);
 145    }
 146}
 147
 148/* function to test throttle_config and throttle_get_config */
 149static void test_config_functions(void)
 150{
 151    int i;
 152    ThrottleConfig orig_cfg, final_cfg;
 153
 154    orig_cfg.buckets[THROTTLE_BPS_TOTAL].avg = 153;
 155    orig_cfg.buckets[THROTTLE_BPS_READ].avg  = 56;
 156    orig_cfg.buckets[THROTTLE_BPS_WRITE].avg = 1;
 157
 158    orig_cfg.buckets[THROTTLE_OPS_TOTAL].avg = 150;
 159    orig_cfg.buckets[THROTTLE_OPS_READ].avg  = 69;
 160    orig_cfg.buckets[THROTTLE_OPS_WRITE].avg = 23;
 161
 162    orig_cfg.buckets[THROTTLE_BPS_TOTAL].max = 0; /* should be corrected */
 163    orig_cfg.buckets[THROTTLE_BPS_READ].max  = 1; /* should not be corrected */
 164    orig_cfg.buckets[THROTTLE_BPS_WRITE].max = 120;
 165
 166    orig_cfg.buckets[THROTTLE_OPS_TOTAL].max = 150;
 167    orig_cfg.buckets[THROTTLE_OPS_READ].max  = 400;
 168    orig_cfg.buckets[THROTTLE_OPS_WRITE].max = 500;
 169
 170    orig_cfg.buckets[THROTTLE_BPS_TOTAL].level = 45;
 171    orig_cfg.buckets[THROTTLE_BPS_READ].level  = 65;
 172    orig_cfg.buckets[THROTTLE_BPS_WRITE].level = 23;
 173
 174    orig_cfg.buckets[THROTTLE_OPS_TOTAL].level = 1;
 175    orig_cfg.buckets[THROTTLE_OPS_READ].level  = 90;
 176    orig_cfg.buckets[THROTTLE_OPS_WRITE].level = 75;
 177
 178    orig_cfg.op_size = 1;
 179
 180    throttle_init(&ts);
 181    throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
 182                         read_timer_cb, write_timer_cb, &ts);
 183    /* structure reset by throttle_init previous_leak should be null */
 184    g_assert(!ts.previous_leak);
 185    throttle_config(&ts, &tt, &orig_cfg);
 186
 187    /* has previous leak been initialized by throttle_config ? */
 188    g_assert(ts.previous_leak);
 189
 190    /* get back the fixed configuration */
 191    throttle_get_config(&ts, &final_cfg);
 192
 193    throttle_timers_destroy(&tt);
 194
 195    g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].avg == 153);
 196    g_assert(final_cfg.buckets[THROTTLE_BPS_READ].avg  == 56);
 197    g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].avg == 1);
 198
 199    g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].avg == 150);
 200    g_assert(final_cfg.buckets[THROTTLE_OPS_READ].avg  == 69);
 201    g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].avg == 23);
 202
 203    g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].max == 15.3);/* fixed */
 204    g_assert(final_cfg.buckets[THROTTLE_BPS_READ].max  == 1);   /* not fixed */
 205    g_assert(final_cfg.buckets[THROTTLE_BPS_WRITE].max == 120);
 206
 207    g_assert(final_cfg.buckets[THROTTLE_OPS_TOTAL].max == 150);
 208    g_assert(final_cfg.buckets[THROTTLE_OPS_READ].max  == 400);
 209    g_assert(final_cfg.buckets[THROTTLE_OPS_WRITE].max == 500);
 210
 211    g_assert(final_cfg.op_size == 1);
 212
 213    /* check bucket have been cleared */
 214    for (i = 0; i < BUCKETS_COUNT; i++) {
 215        g_assert(!final_cfg.buckets[i].level);
 216    }
 217}
 218
 219/* functions to test is throttle is enabled by a config */
 220static void set_cfg_value(bool is_max, int index, int value)
 221{
 222    if (is_max) {
 223        cfg.buckets[index].max = value;
 224    } else {
 225        cfg.buckets[index].avg = value;
 226    }
 227}
 228
 229static void test_enabled(void)
 230{
 231    int i;
 232
 233    memset(&cfg, 0, sizeof(cfg));
 234    g_assert(!throttle_enabled(&cfg));
 235
 236    for (i = 0; i < BUCKETS_COUNT; i++) {
 237        memset(&cfg, 0, sizeof(cfg));
 238        set_cfg_value(false, i, 150);
 239        g_assert(throttle_enabled(&cfg));
 240    }
 241
 242    for (i = 0; i < BUCKETS_COUNT; i++) {
 243        memset(&cfg, 0, sizeof(cfg));
 244        set_cfg_value(false, i, -150);
 245        g_assert(!throttle_enabled(&cfg));
 246    }
 247}
 248
 249/* tests functions for throttle_conflicting */
 250
 251static void test_conflicts_for_one_set(bool is_max,
 252                                       int total,
 253                                       int read,
 254                                       int write)
 255{
 256    memset(&cfg, 0, sizeof(cfg));
 257    g_assert(!throttle_conflicting(&cfg));
 258
 259    set_cfg_value(is_max, total, 1);
 260    set_cfg_value(is_max, read,  1);
 261    g_assert(throttle_conflicting(&cfg));
 262
 263    memset(&cfg, 0, sizeof(cfg));
 264    set_cfg_value(is_max, total, 1);
 265    set_cfg_value(is_max, write, 1);
 266    g_assert(throttle_conflicting(&cfg));
 267
 268    memset(&cfg, 0, sizeof(cfg));
 269    set_cfg_value(is_max, total, 1);
 270    set_cfg_value(is_max, read,  1);
 271    set_cfg_value(is_max, write, 1);
 272    g_assert(throttle_conflicting(&cfg));
 273
 274    memset(&cfg, 0, sizeof(cfg));
 275    set_cfg_value(is_max, total, 1);
 276    g_assert(!throttle_conflicting(&cfg));
 277
 278    memset(&cfg, 0, sizeof(cfg));
 279    set_cfg_value(is_max, read,  1);
 280    set_cfg_value(is_max, write, 1);
 281    g_assert(!throttle_conflicting(&cfg));
 282}
 283
 284static void test_conflicting_config(void)
 285{
 286    /* bps average conflicts */
 287    test_conflicts_for_one_set(false,
 288                               THROTTLE_BPS_TOTAL,
 289                               THROTTLE_BPS_READ,
 290                               THROTTLE_BPS_WRITE);
 291
 292    /* ops average conflicts */
 293    test_conflicts_for_one_set(false,
 294                               THROTTLE_OPS_TOTAL,
 295                               THROTTLE_OPS_READ,
 296                               THROTTLE_OPS_WRITE);
 297
 298    /* bps average conflicts */
 299    test_conflicts_for_one_set(true,
 300                               THROTTLE_BPS_TOTAL,
 301                               THROTTLE_BPS_READ,
 302                               THROTTLE_BPS_WRITE);
 303    /* ops average conflicts */
 304    test_conflicts_for_one_set(true,
 305                               THROTTLE_OPS_TOTAL,
 306                               THROTTLE_OPS_READ,
 307                               THROTTLE_OPS_WRITE);
 308}
 309/* functions to test the throttle_is_valid function */
 310static void test_is_valid_for_value(int value, bool should_be_valid)
 311{
 312    int is_max, index;
 313    for (is_max = 0; is_max < 2; is_max++) {
 314        for (index = 0; index < BUCKETS_COUNT; index++) {
 315            memset(&cfg, 0, sizeof(cfg));
 316            set_cfg_value(is_max, index, value);
 317            g_assert(throttle_is_valid(&cfg) == should_be_valid);
 318        }
 319    }
 320}
 321
 322static void test_is_valid(void)
 323{
 324    /* negative number are invalid */
 325    test_is_valid_for_value(-1, false);
 326    /* zero are valids */
 327    test_is_valid_for_value(0, true);
 328    /* positives numers are valids */
 329    test_is_valid_for_value(1, true);
 330}
 331
 332static void test_have_timer(void)
 333{
 334    /* zero structures */
 335    memset(&ts, 0, sizeof(ts));
 336    memset(&tt, 0, sizeof(tt));
 337
 338    /* no timer set should return false */
 339    g_assert(!throttle_timers_are_initialized(&tt));
 340
 341    /* init structures */
 342    throttle_init(&ts);
 343    throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
 344                         read_timer_cb, write_timer_cb, &ts);
 345
 346    /* timer set by init should return true */
 347    g_assert(throttle_timers_are_initialized(&tt));
 348
 349    throttle_timers_destroy(&tt);
 350}
 351
 352static void test_detach_attach(void)
 353{
 354    /* zero structures */
 355    memset(&ts, 0, sizeof(ts));
 356    memset(&tt, 0, sizeof(tt));
 357
 358    /* init the structure */
 359    throttle_init(&ts);
 360    throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
 361                         read_timer_cb, write_timer_cb, &ts);
 362
 363    /* timer set by init should return true */
 364    g_assert(throttle_timers_are_initialized(&tt));
 365
 366    /* timer should no longer exist after detaching */
 367    throttle_timers_detach_aio_context(&tt);
 368    g_assert(!throttle_timers_are_initialized(&tt));
 369
 370    /* timer should exist again after attaching */
 371    throttle_timers_attach_aio_context(&tt, ctx);
 372    g_assert(throttle_timers_are_initialized(&tt));
 373
 374    throttle_timers_destroy(&tt);
 375}
 376
 377static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
 378                int size,                   /* size of the operation to do */
 379                double avg,                 /* io limit */
 380                uint64_t op_size,           /* ideal size of an io */
 381                double total_result,
 382                double read_result,
 383                double write_result)
 384{
 385    BucketType to_test[2][3] = { { THROTTLE_BPS_TOTAL,
 386                                   THROTTLE_BPS_READ,
 387                                   THROTTLE_BPS_WRITE, },
 388                                 { THROTTLE_OPS_TOTAL,
 389                                   THROTTLE_OPS_READ,
 390                                   THROTTLE_OPS_WRITE, } };
 391    ThrottleConfig cfg;
 392    BucketType index;
 393    int i;
 394
 395    for (i = 0; i < 3; i++) {
 396        BucketType index = to_test[is_ops][i];
 397        cfg.buckets[index].avg = avg;
 398    }
 399
 400    cfg.op_size = op_size;
 401
 402    throttle_init(&ts);
 403    throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
 404                         read_timer_cb, write_timer_cb, &ts);
 405    throttle_config(&ts, &tt, &cfg);
 406
 407    /* account a read */
 408    throttle_account(&ts, false, size);
 409    /* account a write */
 410    throttle_account(&ts, true, size);
 411
 412    /* check total result */
 413    index = to_test[is_ops][0];
 414    if (!double_cmp(ts.cfg.buckets[index].level, total_result)) {
 415        return false;
 416    }
 417
 418    /* check read result */
 419    index = to_test[is_ops][1];
 420    if (!double_cmp(ts.cfg.buckets[index].level, read_result)) {
 421        return false;
 422    }
 423
 424    /* check write result */
 425    index = to_test[is_ops][2];
 426    if (!double_cmp(ts.cfg.buckets[index].level, write_result)) {
 427        return false;
 428    }
 429
 430    throttle_timers_destroy(&tt);
 431
 432    return true;
 433}
 434
 435static void test_accounting(void)
 436{
 437    /* tests for bps */
 438
 439    /* op of size 1 */
 440    g_assert(do_test_accounting(false,
 441                                1 * 512,
 442                                150,
 443                                0,
 444                                1024,
 445                                512,
 446                                512));
 447
 448    /* op of size 2 */
 449    g_assert(do_test_accounting(false,
 450                                2 * 512,
 451                                150,
 452                                0,
 453                                2048,
 454                                1024,
 455                                1024));
 456
 457    /* op of size 2 and orthogonal parameter change */
 458    g_assert(do_test_accounting(false,
 459                                2 * 512,
 460                                150,
 461                                17,
 462                                2048,
 463                                1024,
 464                                1024));
 465
 466
 467    /* tests for ops */
 468
 469    /* op of size 1 */
 470    g_assert(do_test_accounting(true,
 471                                1 * 512,
 472                                150,
 473                                0,
 474                                2,
 475                                1,
 476                                1));
 477
 478    /* op of size 2 */
 479    g_assert(do_test_accounting(true,
 480                                2 *  512,
 481                                150,
 482                                0,
 483                                2,
 484                                1,
 485                                1));
 486
 487    /* jumbo op accounting fragmentation : size 64 with op size of 13 units */
 488    g_assert(do_test_accounting(true,
 489                                64 * 512,
 490                                150,
 491                                13 * 512,
 492                                (64.0 * 2) / 13,
 493                                (64.0 / 13),
 494                                (64.0 / 13)));
 495
 496    /* same with orthogonal parameters changes */
 497    g_assert(do_test_accounting(true,
 498                                64 * 512,
 499                                300,
 500                                13 * 512,
 501                                (64.0 * 2) / 13,
 502                                (64.0 / 13),
 503                                (64.0 / 13)));
 504}
 505
 506static void test_groups(void)
 507{
 508    ThrottleConfig cfg1, cfg2;
 509    BlockDriverState *bdrv1, *bdrv2, *bdrv3;
 510
 511    bdrv1 = bdrv_new();
 512    bdrv2 = bdrv_new();
 513    bdrv3 = bdrv_new();
 514
 515    g_assert(bdrv1->throttle_state == NULL);
 516    g_assert(bdrv2->throttle_state == NULL);
 517    g_assert(bdrv3->throttle_state == NULL);
 518
 519    throttle_group_register_bs(bdrv1, "bar");
 520    throttle_group_register_bs(bdrv2, "foo");
 521    throttle_group_register_bs(bdrv3, "bar");
 522
 523    g_assert(bdrv1->throttle_state != NULL);
 524    g_assert(bdrv2->throttle_state != NULL);
 525    g_assert(bdrv3->throttle_state != NULL);
 526
 527    g_assert(!strcmp(throttle_group_get_name(bdrv1), "bar"));
 528    g_assert(!strcmp(throttle_group_get_name(bdrv2), "foo"));
 529    g_assert(bdrv1->throttle_state == bdrv3->throttle_state);
 530
 531    /* Setting the config of a group member affects the whole group */
 532    memset(&cfg1, 0, sizeof(cfg1));
 533    cfg1.buckets[THROTTLE_BPS_READ].avg  = 500000;
 534    cfg1.buckets[THROTTLE_BPS_WRITE].avg = 285000;
 535    cfg1.buckets[THROTTLE_OPS_READ].avg  = 20000;
 536    cfg1.buckets[THROTTLE_OPS_WRITE].avg = 12000;
 537    throttle_group_config(bdrv1, &cfg1);
 538
 539    throttle_group_get_config(bdrv1, &cfg1);
 540    throttle_group_get_config(bdrv3, &cfg2);
 541    g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
 542
 543    cfg2.buckets[THROTTLE_BPS_READ].avg  = 4547;
 544    cfg2.buckets[THROTTLE_BPS_WRITE].avg = 1349;
 545    cfg2.buckets[THROTTLE_OPS_READ].avg  = 123;
 546    cfg2.buckets[THROTTLE_OPS_WRITE].avg = 86;
 547    throttle_group_config(bdrv3, &cfg1);
 548
 549    throttle_group_get_config(bdrv1, &cfg1);
 550    throttle_group_get_config(bdrv3, &cfg2);
 551    g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
 552
 553    throttle_group_unregister_bs(bdrv1);
 554    throttle_group_unregister_bs(bdrv2);
 555    throttle_group_unregister_bs(bdrv3);
 556
 557    g_assert(bdrv1->throttle_state == NULL);
 558    g_assert(bdrv2->throttle_state == NULL);
 559    g_assert(bdrv3->throttle_state == NULL);
 560}
 561
 562int main(int argc, char **argv)
 563{
 564    Error *local_error = NULL;
 565
 566    qemu_init_main_loop(&local_error);
 567    ctx = qemu_get_aio_context();
 568
 569    if (!ctx) {
 570        error_report("Failed to create AIO Context: '%s'",
 571                     local_error ? error_get_pretty(local_error) :
 572                     "Failed to initialize the QEMU main loop");
 573        if (local_error) {
 574            error_free(local_error);
 575        }
 576        exit(1);
 577    }
 578
 579    bdrv_init();
 580
 581    do {} while (g_main_context_iteration(NULL, false));
 582
 583    /* tests in the same order as the header function declarations */
 584    g_test_init(&argc, &argv, NULL);
 585    g_test_add_func("/throttle/leak_bucket",        test_leak_bucket);
 586    g_test_add_func("/throttle/compute_wait",       test_compute_wait);
 587    g_test_add_func("/throttle/init",               test_init);
 588    g_test_add_func("/throttle/destroy",            test_destroy);
 589    g_test_add_func("/throttle/have_timer",         test_have_timer);
 590    g_test_add_func("/throttle/detach_attach",      test_detach_attach);
 591    g_test_add_func("/throttle/config/enabled",     test_enabled);
 592    g_test_add_func("/throttle/config/conflicting", test_conflicting_config);
 593    g_test_add_func("/throttle/config/is_valid",    test_is_valid);
 594    g_test_add_func("/throttle/config_functions",   test_config_functions);
 595    g_test_add_func("/throttle/accounting",         test_accounting);
 596    g_test_add_func("/throttle/groups",             test_groups);
 597    return g_test_run();
 598}
 599
 600