2 * Copyright (C) 2016, Emilio G. Cota <cota@braap.org>
4 * License: GNU GPL, version 2 or later.
5 * See the COPYING file in the top-level directory.
7 #include "qemu/osdep.h"
8 #include "qemu/qdist.h"
16 /* 0 prints a space, 1-8 prints from qdist_blocks[] */
20 /* See: https://en.wikipedia.org/wiki/Block_Elements */
21 static const gunichar qdist_blocks
[] = {
32 #define QDIST_NR_BLOCK_CODES ARRAY_SIZE(qdist_blocks)
34 static char *pr_hist(const struct entry_desc
*darr
, size_t n
)
36 GString
*s
= g_string_new("");
39 for (i
= 0; i
< n
; i
++) {
40 int fill
= darr
[i
].fill_code
;
43 assert(fill
<= QDIST_NR_BLOCK_CODES
);
44 g_string_append_unichar(s
, qdist_blocks
[fill
- 1]);
46 g_string_append_c(s
, ' ');
49 return g_string_free(s
, FALSE
);
53 histogram_check(const struct qdist
*dist
, const struct entry_desc
*darr
,
54 size_t n
, size_t n_bins
)
56 char *pr
= qdist_pr_plain(dist
, n_bins
);
57 char *str
= pr_hist(darr
, n
);
59 g_assert_cmpstr(pr
, ==, str
);
64 static void histogram_check_single_full(const struct qdist
*dist
, size_t n_bins
)
66 struct entry_desc desc
= { .fill_code
= 8 };
68 histogram_check(dist
, &desc
, 1, n_bins
);
72 entries_check(const struct qdist
*dist
, const struct entry_desc
*darr
, size_t n
)
76 for (i
= 0; i
< n
; i
++) {
77 struct qdist_entry
*e
= &dist
->entries
[i
];
79 g_assert_cmpuint(e
->count
, ==, darr
[i
].count
);
84 entries_insert(struct qdist
*dist
, const struct entry_desc
*darr
, size_t n
)
88 for (i
= 0; i
< n
; i
++) {
89 qdist_add(dist
, darr
[i
].x
, darr
[i
].count
);
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
)
101 entries_insert(&qda
, a
, n_a
);
102 qdist_inc(&qda
, a
[0].x
);
103 qdist_add(&qda
, a
[0].x
, -1);
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
);
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
));
116 * No histogram_check() for $qdb, since we'd rebin it and that is a bug.
117 * Instead, regenerate it from $qda.
119 histogram_check(&qda
, b
, n_b
, n_b
);
125 static void do_test_pr(uint32_t opt
)
127 static const struct entry_desc desc
[] = {
132 static const char border
[] = "|";
133 const char *llabel
= NULL
;
134 const char *rlabel
= NULL
;
141 n
= ARRAY_SIZE(desc
);
144 entries_insert(&dist
, desc
, n
);
145 histogram_check(&dist
, desc
, n
, 0);
147 s
= g_string_new("");
149 if (opt
& QDIST_PR_LABELS
) {
150 unsigned int lopts
= opt
& (QDIST_PR_NODECIMAL
|
153 QDIST_PR_NOBINRANGE
);
156 llabel
= "[1.0,1.7)";
157 rlabel
= "[2.3,3.0]";
158 } else if (lopts
== QDIST_PR_NODECIMAL
) {
161 } else if (lopts
== (QDIST_PR_PERCENT
| QDIST_PR_NODECIMAL
)) {
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
)) {
171 g_assert_cmpstr("BUG", ==, "This is not meant to be exhaustive");
176 g_string_append(s
, llabel
);
178 if (opt
& QDIST_PR_BORDER
) {
179 g_string_append(s
, border
);
182 str
= pr_hist(desc
, n
);
183 g_string_append(s
, str
);
186 if (opt
& QDIST_PR_BORDER
) {
187 g_string_append(s
, border
);
190 g_string_append(s
, rlabel
);
193 str
= g_string_free(s
, FALSE
);
194 pr
= qdist_pr(&dist
, n
, opt
);
195 g_assert_cmpstr(pr
, ==, str
);
199 qdist_destroy(&dist
);
202 static inline void do_test_pr_label(uint32_t opt
)
204 opt
|= QDIST_PR_LABELS
;
208 static void test_pr(void)
212 do_test_pr(QDIST_PR_BORDER
);
214 /* 100X should be ignored because we're not setting LABELS */
215 do_test_pr(QDIST_PR_100X
);
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
);
224 static void test_bin_shrink(void)
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 }
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 }
242 return do_test_bin(a
, ARRAY_SIZE(a
), b
, ARRAY_SIZE(b
));
245 static void test_bin_expand(void)
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 }
257 static const struct entry_desc b
[] = {
258 [0] = { 0.0, 11713, 5 },
260 [2] = { 0.0, 20294, 8 },
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 }
270 return do_test_bin(a
, ARRAY_SIZE(a
), b
, ARRAY_SIZE(b
));
273 static void test_bin_precision(void)
275 static const struct entry_desc a
[] = {
276 [0] = { 0, 213549, 8 },
279 static const struct entry_desc b
[] = {
280 [0] = { 0, 213549, 8 },
284 return do_test_bin(a
, ARRAY_SIZE(a
), b
, ARRAY_SIZE(b
));
287 static void test_bin_simple(void)
289 static const struct entry_desc a
[] = {
290 [0] = { 10, 101, 8 },
294 static const struct entry_desc b
[] = {
302 return do_test_bin(a
, ARRAY_SIZE(a
), b
, ARRAY_SIZE(b
));
305 static void test_single_full(void)
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);
316 histogram_check_single_full(&dist
, 0);
317 histogram_check_single_full(&dist
, 1);
318 histogram_check_single_full(&dist
, 10);
320 qdist_destroy(&dist
);
323 static void test_single_empty(void)
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);
336 pr
= qdist_pr_plain(&dist
, 0);
337 g_assert_cmpstr(pr
, ==, " ");
340 pr
= qdist_pr_plain(&dist
, 1);
341 g_assert_cmpstr(pr
, ==, " ");
344 pr
= qdist_pr_plain(&dist
, 2);
345 g_assert_cmpstr(pr
, ==, " ");
348 qdist_destroy(&dist
);
351 static void test_none(void)
358 g_assert(isnan(qdist_avg(&dist
)));
359 g_assert(isnan(qdist_xmin(&dist
)));
360 g_assert(isnan(qdist_xmax(&dist
)));
362 pr
= qdist_pr_plain(&dist
, 0);
363 g_assert_cmpstr(pr
, ==, "(empty)");
366 pr
= qdist_pr_plain(&dist
, 2);
367 g_assert_cmpstr(pr
, ==, "(empty)");
370 pr
= qdist_pr(&dist
, 0, QDIST_PR_BORDER
);
371 g_assert_cmpstr(pr
, ==, "(empty)");
374 qdist_destroy(&dist
);
377 int main(int argc
, char *argv
[])
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
);