OSDN Git Service

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