cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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
     12struct 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 */
     21static 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
     34static 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
     52static void
     53histogram_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
     64static 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
     71static void
     72entries_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
     83static void
     84entries_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
     93static 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
    125static 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
    202static inline void do_test_pr_label(uint32_t opt)
    203{
    204    opt |= QDIST_PR_LABELS;
    205    do_test_pr(opt);
    206}
    207
    208static 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
    224static 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
    245static 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
    273static 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
    287static 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
    305static 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
    323static 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
    351static 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
    377int 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}