qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

test-qdist.c (9674B)


      1 /*
      2  * Copyright (C) 2016, Emilio G. Cota <cota@braap.org>
      3  *
      4  * License: GNU GPL, version 2 or later.
      5  *   See the COPYING file in the top-level directory.
      6  */
      7 #include "qemu/osdep.h"
      8 #include "qemu/qdist.h"
      9 
     10 #include <math.h>
     11 
     12 struct entry_desc {
     13     double x;
     14     unsigned long count;
     15 
     16     /* 0 prints a space, 1-8 prints from qdist_blocks[] */
     17     int fill_code;
     18 };
     19 
     20 /* See: https://en.wikipedia.org/wiki/Block_Elements */
     21 static const gunichar qdist_blocks[] = {
     22     0x2581,
     23     0x2582,
     24     0x2583,
     25     0x2584,
     26     0x2585,
     27     0x2586,
     28     0x2587,
     29     0x2588
     30 };
     31 
     32 #define QDIST_NR_BLOCK_CODES ARRAY_SIZE(qdist_blocks)
     33 
     34 static char *pr_hist(const struct entry_desc *darr, size_t n)
     35 {
     36     GString *s = g_string_new("");
     37     size_t i;
     38 
     39     for (i = 0; i < n; i++) {
     40         int fill = darr[i].fill_code;
     41 
     42         if (fill) {
     43             assert(fill <= QDIST_NR_BLOCK_CODES);
     44             g_string_append_unichar(s, qdist_blocks[fill - 1]);
     45         } else {
     46             g_string_append_c(s, ' ');
     47         }
     48     }
     49     return g_string_free(s, FALSE);
     50 }
     51 
     52 static void
     53 histogram_check(const struct qdist *dist, const struct entry_desc *darr,
     54                 size_t n, size_t n_bins)
     55 {
     56     char *pr = qdist_pr_plain(dist, n_bins);
     57     char *str = pr_hist(darr, n);
     58 
     59     g_assert_cmpstr(pr, ==, str);
     60     g_free(pr);
     61     g_free(str);
     62 }
     63 
     64 static void histogram_check_single_full(const struct qdist *dist, size_t n_bins)
     65 {
     66     struct entry_desc desc = { .fill_code = 8 };
     67 
     68     histogram_check(dist, &desc, 1, n_bins);
     69 }
     70 
     71 static void
     72 entries_check(const struct qdist *dist, const struct entry_desc *darr, size_t n)
     73 {
     74     size_t i;
     75 
     76     for (i = 0; i < n; i++) {
     77         struct qdist_entry *e = &dist->entries[i];
     78 
     79         g_assert_cmpuint(e->count, ==, darr[i].count);
     80     }
     81 }
     82 
     83 static void
     84 entries_insert(struct qdist *dist, const struct entry_desc *darr, size_t n)
     85 {
     86     size_t i;
     87 
     88     for (i = 0; i < n; i++) {
     89         qdist_add(dist, darr[i].x, darr[i].count);
     90     }
     91 }
     92 
     93 static void do_test_bin(const struct entry_desc *a, size_t n_a,
     94                         const struct entry_desc *b, size_t n_b)
     95 {
     96     struct qdist qda;
     97     struct qdist qdb;
     98 
     99     qdist_init(&qda);
    100 
    101     entries_insert(&qda, a, n_a);
    102     qdist_inc(&qda, a[0].x);
    103     qdist_add(&qda, a[0].x, -1);
    104 
    105     g_assert_cmpuint(qdist_unique_entries(&qda), ==, n_a);
    106     g_assert_cmpfloat(qdist_xmin(&qda), ==, a[0].x);
    107     g_assert_cmpfloat(qdist_xmax(&qda), ==, a[n_a - 1].x);
    108     histogram_check(&qda, a, n_a, 0);
    109     histogram_check(&qda, a, n_a, n_a);
    110 
    111     qdist_bin__internal(&qdb, &qda, n_b);
    112     g_assert_cmpuint(qdb.n, ==, n_b);
    113     entries_check(&qdb, b, n_b);
    114     g_assert_cmpuint(qdist_sample_count(&qda), ==, qdist_sample_count(&qdb));
    115     /*
    116      * No histogram_check() for $qdb, since we'd rebin it and that is a bug.
    117      * Instead, regenerate it from $qda.
    118      */
    119     histogram_check(&qda, b, n_b, n_b);
    120 
    121     qdist_destroy(&qdb);
    122     qdist_destroy(&qda);
    123 }
    124 
    125 static void do_test_pr(uint32_t opt)
    126 {
    127     static const struct entry_desc desc[] = {
    128         [0] = { 1, 900, 8 },
    129         [1] = { 2, 1, 1 },
    130         [2] = { 3, 2, 1 }
    131     };
    132     static const char border[] = "|";
    133     const char *llabel = NULL;
    134     const char *rlabel = NULL;
    135     struct qdist dist;
    136     GString *s;
    137     char *str;
    138     char *pr;
    139     size_t n;
    140 
    141     n = ARRAY_SIZE(desc);
    142     qdist_init(&dist);
    143 
    144     entries_insert(&dist, desc, n);
    145     histogram_check(&dist, desc, n, 0);
    146 
    147     s = g_string_new("");
    148 
    149     if (opt & QDIST_PR_LABELS) {
    150         unsigned int lopts = opt & (QDIST_PR_NODECIMAL |
    151                                     QDIST_PR_PERCENT |
    152                                     QDIST_PR_100X |
    153                                     QDIST_PR_NOBINRANGE);
    154 
    155         if (lopts == 0) {
    156             llabel = "[1.0,1.7)";
    157             rlabel = "[2.3,3.0]";
    158         } else if (lopts == QDIST_PR_NODECIMAL) {
    159             llabel = "[1,2)";
    160             rlabel = "[2,3]";
    161         } else if (lopts == (QDIST_PR_PERCENT | QDIST_PR_NODECIMAL)) {
    162             llabel = "[1,2)%";
    163             rlabel = "[2,3]%";
    164         } else if (lopts == QDIST_PR_100X) {
    165             llabel = "[100.0,166.7)";
    166             rlabel = "[233.3,300.0]";
    167         } else if (lopts == (QDIST_PR_NOBINRANGE | QDIST_PR_NODECIMAL)) {
    168             llabel = "1";
    169             rlabel = "3";
    170         } else {
    171             g_assert_cmpstr("BUG", ==, "This is not meant to be exhaustive");
    172         }
    173     }
    174 
    175     if (llabel) {
    176         g_string_append(s, llabel);
    177     }
    178     if (opt & QDIST_PR_BORDER) {
    179         g_string_append(s, border);
    180     }
    181 
    182     str = pr_hist(desc, n);
    183     g_string_append(s, str);
    184     g_free(str);
    185 
    186     if (opt & QDIST_PR_BORDER) {
    187         g_string_append(s, border);
    188     }
    189     if (rlabel) {
    190         g_string_append(s, rlabel);
    191     }
    192 
    193     str = g_string_free(s, FALSE);
    194     pr = qdist_pr(&dist, n, opt);
    195     g_assert_cmpstr(pr, ==, str);
    196     g_free(pr);
    197     g_free(str);
    198 
    199     qdist_destroy(&dist);
    200 }
    201 
    202 static inline void do_test_pr_label(uint32_t opt)
    203 {
    204     opt |= QDIST_PR_LABELS;
    205     do_test_pr(opt);
    206 }
    207 
    208 static void test_pr(void)
    209 {
    210     do_test_pr(0);
    211 
    212     do_test_pr(QDIST_PR_BORDER);
    213 
    214     /* 100X should be ignored because we're not setting LABELS */
    215     do_test_pr(QDIST_PR_100X);
    216 
    217     do_test_pr_label(0);
    218     do_test_pr_label(QDIST_PR_NODECIMAL);
    219     do_test_pr_label(QDIST_PR_PERCENT | QDIST_PR_NODECIMAL);
    220     do_test_pr_label(QDIST_PR_100X);
    221     do_test_pr_label(QDIST_PR_NOBINRANGE | QDIST_PR_NODECIMAL);
    222 }
    223 
    224 static void test_bin_shrink(void)
    225 {
    226     static const struct entry_desc a[] = {
    227         [0] = { 0.0,   42922, 7 },
    228         [1] = { 0.25,  47834, 8 },
    229         [2] = { 0.50,  26628, 0 },
    230         [3] = { 0.625, 597,   4 },
    231         [4] = { 0.75,  10298, 1 },
    232         [5] = { 0.875, 22,    2 },
    233         [6] = { 1.0,   2771,  1 }
    234     };
    235     static const struct entry_desc b[] = {
    236         [0] = { 0.0, 42922, 7 },
    237         [1] = { 0.25, 47834, 8 },
    238         [2] = { 0.50, 27225, 3 },
    239         [3] = { 0.75, 13091, 1 }
    240     };
    241 
    242     return do_test_bin(a, ARRAY_SIZE(a), b, ARRAY_SIZE(b));
    243 }
    244 
    245 static void test_bin_expand(void)
    246 {
    247     static const struct entry_desc a[] = {
    248         [0] = { 0.0,   11713, 5 },
    249         [1] = { 0.25,  20294, 0 },
    250         [2] = { 0.50,  17266, 8 },
    251         [3] = { 0.625, 1506,  0 },
    252         [4] = { 0.75,  10355, 6 },
    253         [5] = { 0.833, 2,     1 },
    254         [6] = { 0.875, 99,    4 },
    255         [7] = { 1.0,   4301,  2 }
    256     };
    257     static const struct entry_desc b[] = {
    258         [0] = { 0.0, 11713, 5 },
    259         [1] = { 0.0, 0,     0 },
    260         [2] = { 0.0, 20294, 8 },
    261         [3] = { 0.0, 0,     0 },
    262         [4] = { 0.0, 0,     0 },
    263         [5] = { 0.0, 17266, 6 },
    264         [6] = { 0.0, 1506,  1 },
    265         [7] = { 0.0, 10355, 4 },
    266         [8] = { 0.0, 101,   1 },
    267         [9] = { 0.0, 4301,  2 }
    268     };
    269 
    270     return do_test_bin(a, ARRAY_SIZE(a), b, ARRAY_SIZE(b));
    271 }
    272 
    273 static void test_bin_precision(void)
    274 {
    275     static const struct entry_desc a[] = {
    276         [0] = { 0, 213549, 8 },
    277         [1] = { 1, 70, 1 },
    278     };
    279     static const struct entry_desc b[] = {
    280         [0] = { 0, 213549, 8 },
    281         [1] = { 0, 70, 1 },
    282     };
    283 
    284     return do_test_bin(a, ARRAY_SIZE(a), b, ARRAY_SIZE(b));
    285 }
    286 
    287 static void test_bin_simple(void)
    288 {
    289     static const struct entry_desc a[] = {
    290         [0] = { 10, 101, 8 },
    291         [1] = { 11, 0, 0 },
    292         [2] = { 12, 2, 1 }
    293     };
    294     static const struct entry_desc b[] = {
    295         [0] = { 0, 101, 8 },
    296         [1] = { 0, 0, 0 },
    297         [2] = { 0, 0, 0 },
    298         [3] = { 0, 0, 0 },
    299         [4] = { 0, 2, 1 }
    300     };
    301 
    302     return do_test_bin(a, ARRAY_SIZE(a), b, ARRAY_SIZE(b));
    303 }
    304 
    305 static void test_single_full(void)
    306 {
    307     struct qdist dist;
    308 
    309     qdist_init(&dist);
    310 
    311     qdist_add(&dist, 3, 102);
    312     g_assert_cmpfloat(qdist_avg(&dist), ==, 3);
    313     g_assert_cmpfloat(qdist_xmin(&dist), ==, 3);
    314     g_assert_cmpfloat(qdist_xmax(&dist), ==, 3);
    315 
    316     histogram_check_single_full(&dist, 0);
    317     histogram_check_single_full(&dist, 1);
    318     histogram_check_single_full(&dist, 10);
    319 
    320     qdist_destroy(&dist);
    321 }
    322 
    323 static void test_single_empty(void)
    324 {
    325     struct qdist dist;
    326     char *pr;
    327 
    328     qdist_init(&dist);
    329 
    330     qdist_add(&dist, 3, 0);
    331     g_assert_cmpuint(qdist_sample_count(&dist), ==, 0);
    332     g_assert(isnan(qdist_avg(&dist)));
    333     g_assert_cmpfloat(qdist_xmin(&dist), ==, 3);
    334     g_assert_cmpfloat(qdist_xmax(&dist), ==, 3);
    335 
    336     pr = qdist_pr_plain(&dist, 0);
    337     g_assert_cmpstr(pr, ==, " ");
    338     g_free(pr);
    339 
    340     pr = qdist_pr_plain(&dist, 1);
    341     g_assert_cmpstr(pr, ==, " ");
    342     g_free(pr);
    343 
    344     pr = qdist_pr_plain(&dist, 2);
    345     g_assert_cmpstr(pr, ==, " ");
    346     g_free(pr);
    347 
    348     qdist_destroy(&dist);
    349 }
    350 
    351 static void test_none(void)
    352 {
    353     struct qdist dist;
    354     char *pr;
    355 
    356     qdist_init(&dist);
    357 
    358     g_assert(isnan(qdist_avg(&dist)));
    359     g_assert(isnan(qdist_xmin(&dist)));
    360     g_assert(isnan(qdist_xmax(&dist)));
    361 
    362     pr = qdist_pr_plain(&dist, 0);
    363     g_assert_cmpstr(pr, ==, "(empty)");
    364     g_free(pr);
    365 
    366     pr = qdist_pr_plain(&dist, 2);
    367     g_assert_cmpstr(pr, ==, "(empty)");
    368     g_free(pr);
    369 
    370     pr = qdist_pr(&dist, 0, QDIST_PR_BORDER);
    371     g_assert_cmpstr(pr, ==, "(empty)");
    372     g_free(pr);
    373 
    374     qdist_destroy(&dist);
    375 }
    376 
    377 int main(int argc, char *argv[])
    378 {
    379     g_test_init(&argc, &argv, NULL);
    380     g_test_add_func("/qdist/none", test_none);
    381     g_test_add_func("/qdist/single/empty", test_single_empty);
    382     g_test_add_func("/qdist/single/full", test_single_full);
    383     g_test_add_func("/qdist/binning/simple", test_bin_simple);
    384     g_test_add_func("/qdist/binning/precision", test_bin_precision);
    385     g_test_add_func("/qdist/binning/expand", test_bin_expand);
    386     g_test_add_func("/qdist/binning/shrink", test_bin_shrink);
    387     g_test_add_func("/qdist/pr", test_pr);
    388     return g_test_run();
    389 }