[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v4 10/14] qdist: add test program
From: |
Emilio G. Cota |
Subject: |
[Qemu-devel] [PATCH v4 10/14] qdist: add test program |
Date: |
Fri, 29 Apr 2016 23:33:13 -0400 |
Signed-off-by: Emilio G. Cota <address@hidden>
---
tests/.gitignore | 1 +
tests/Makefile | 6 +-
tests/test-qdist.c | 363 +++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 369 insertions(+), 1 deletion(-)
create mode 100644 tests/test-qdist.c
diff --git a/tests/.gitignore b/tests/.gitignore
index 9eed229..384d2fd 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -47,6 +47,7 @@ test-qapi-types.[ch]
test-qapi-visit.[ch]
test-qdev-global-props
test-qemu-opts
+test-qdist
test-qga
test-qmp-commands
test-qmp-commands.h
diff --git a/tests/Makefile b/tests/Makefile
index 9194f18..d770bf8 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -68,6 +68,8 @@ check-unit-y += tests/rcutorture$(EXESUF)
gcov-files-rcutorture-y = util/rcu.c
check-unit-y += tests/test-rcu-list$(EXESUF)
gcov-files-test-rcu-list-y = util/rcu.c
+check-unit-y += tests/test-qdist$(EXESUF)
+gcov-files-test-qdist-y = util/qdist.c
check-unit-y += tests/test-bitops$(EXESUF)
check-unit-$(CONFIG_HAS_GLIB_SUBPROCESS_TESTS) +=
tests/test-qdev-global-props$(EXESUF)
check-unit-y += tests/check-qom-interface$(EXESUF)
@@ -389,7 +391,8 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o
tests/check-qdict.o \
tests/test-qmp-commands.o tests/test-visitor-serialization.o \
tests/test-x86-cpuid.o tests/test-mul64.o tests/test-int128.o \
tests/test-opts-visitor.o tests/test-qmp-event.o \
- tests/rcutorture.o tests/test-rcu-list.o
+ tests/rcutorture.o tests/test-rcu-list.o \
+ tests/test-qdist.o
$(test-obj-y): QEMU_INCLUDES += -Itests
QEMU_CFLAGS += -I$(SRC_PATH)/tests
@@ -427,6 +430,7 @@ tests/test-cutils$(EXESUF): tests/test-cutils.o
util/cutils.o
tests/test-int128$(EXESUF): tests/test-int128.o
tests/rcutorture$(EXESUF): tests/rcutorture.o $(test-util-obj-y)
tests/test-rcu-list$(EXESUF): tests/test-rcu-list.o $(test-util-obj-y)
+tests/test-qdist$(EXESUF): tests/test-qdist.o $(test-util-obj-y)
tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \
hw/core/qdev.o hw/core/qdev-properties.o hw/core/hotplug.o\
diff --git a/tests/test-qdist.c b/tests/test-qdist.c
new file mode 100644
index 0000000..ecdd3f4
--- /dev/null
+++ b/tests/test-qdist.c
@@ -0,0 +1,363 @@
+#include "qemu/osdep.h"
+#include <glib.h>
+#include "qemu/qdist.h"
+
+#include <math.h>
+
+struct entry_desc {
+ double x;
+ unsigned long count;
+
+ /* 0 prints a space, 1-8 prints from qdist_blocks[] */
+ int fill_code;
+};
+
+/* See: https://en.wikipedia.org/wiki/Block_Elements */
+static const gunichar qdist_blocks[] = {
+ 0x2581,
+ 0x2582,
+ 0x2583,
+ 0x2584,
+ 0x2585,
+ 0x2586,
+ 0x2587,
+ 0x2588
+};
+
+#define QDIST_NR_BLOCK_CODES ARRAY_SIZE(qdist_blocks)
+
+static char *pr_hist(const struct entry_desc *darr, size_t n)
+{
+ GString *s = g_string_new("");
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ int fill = darr[i].fill_code;
+
+ if (fill) {
+ assert(fill <= QDIST_NR_BLOCK_CODES);
+ g_string_append_unichar(s, qdist_blocks[fill - 1]);
+ } else {
+ g_string_append_c(s, ' ');
+ }
+ }
+ return g_string_free(s, FALSE);
+}
+
+static void
+histogram_check(const struct qdist *dist, const struct entry_desc *darr,
+ size_t n, size_t n_bins)
+{
+ char *pr = qdist_pr_plain(dist, n_bins);
+ char *str = pr_hist(darr, n);
+
+ g_assert_cmpstr(pr, ==, str);
+ g_free(pr);
+ g_free(str);
+}
+
+static void histogram_check_single_full(const struct qdist *dist, size_t
n_bins)
+{
+ struct entry_desc desc = { .fill_code = 8 };
+
+ histogram_check(dist, &desc, 1, n_bins);
+}
+
+static void
+entries_check(const struct qdist *dist, const struct entry_desc *darr, size_t
n)
+{
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ struct qdist_entry *e = &dist->entries[i];
+
+ g_assert_cmpuint(e->count, ==, darr[i].count);
+ }
+}
+
+static void
+entries_insert(struct qdist *dist, const struct entry_desc *darr, size_t n)
+{
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ qdist_add(dist, darr[i].x, darr[i].count);
+ }
+}
+
+static void do_test_bin(const struct entry_desc *a, size_t n_a,
+ const struct entry_desc *b, size_t n_b)
+{
+ struct qdist qda;
+ struct qdist qdb;
+
+ qdist_init(&qda);
+
+ entries_insert(&qda, a, n_a);
+ qdist_inc(&qda, a[0].x);
+ qdist_add(&qda, a[0].x, -1);
+
+ g_assert_cmpuint(qdist_unique_entries(&qda), ==, n_a);
+ g_assert_cmpfloat(qdist_xmin(&qda), ==, a[0].x);
+ g_assert_cmpfloat(qdist_xmax(&qda), ==, a[n_a - 1].x);
+ histogram_check(&qda, a, n_a, 0);
+ histogram_check(&qda, a, n_a, n_a);
+
+ qdist_bin__internal(&qdb, &qda, n_b);
+ g_assert_cmpuint(qdb.n, ==, n_b);
+ entries_check(&qdb, b, n_b);
+ g_assert_cmpuint(qdist_sample_count(&qda), ==, qdist_sample_count(&qdb));
+ /*
+ * No histogram_check() for $qdb, since we'd rebin it and that is a bug.
+ * Instead, regenerate it from $qda.
+ */
+ histogram_check(&qda, b, n_b, n_b);
+
+ qdist_destroy(&qdb);
+ qdist_destroy(&qda);
+}
+
+static void do_test_pr(uint32_t opt)
+{
+ static const struct entry_desc desc[] = {
+ [0] = { 1, 900, 8 },
+ [1] = { 2, 1, 1 },
+ [2] = { 3, 2, 1 }
+ };
+ static const char border[] = "|";
+ const char *llabel = NULL;
+ const char *rlabel = NULL;
+ struct qdist dist;
+ GString *s;
+ char *str;
+ char *pr;
+ size_t n;
+
+ n = ARRAY_SIZE(desc);
+ qdist_init(&dist);
+
+ entries_insert(&dist, desc, n);
+ histogram_check(&dist, desc, n, 0);
+
+ s = g_string_new("");
+
+ if (opt & QDIST_PR_LABELS) {
+ unsigned int lopts = opt & (QDIST_PR_NODECIMAL |
+ QDIST_PR_PERCENT |
+ QDIST_PR_100X |
+ QDIST_PR_NOBINRANGE);
+
+ if (lopts == 0) {
+ llabel = "[1.0,1.7)";
+ rlabel = "[2.3,3.0]";
+ } else if (lopts == QDIST_PR_NODECIMAL) {
+ llabel = "[1,2)";
+ rlabel = "[2,3]";
+ } else if (lopts == (QDIST_PR_PERCENT | QDIST_PR_NODECIMAL)) {
+ llabel = "[1,2)%";
+ rlabel = "[2,3]%";
+ } else if (lopts == QDIST_PR_100X) {
+ llabel = "[100.0,166.7)";
+ rlabel = "[233.3,300.0]";
+ } else if (lopts == (QDIST_PR_NOBINRANGE | QDIST_PR_NODECIMAL)) {
+ llabel = "1";
+ rlabel = "3";
+ } else {
+ g_assert_cmpstr("BUG", ==, "This is not meant to be exhaustive");
+ }
+ }
+
+ if (llabel) {
+ g_string_append(s, llabel);
+ }
+ if (opt & QDIST_PR_BORDER) {
+ g_string_append(s, border);
+ }
+
+ str = pr_hist(desc, n);
+ g_string_append(s, str);
+ g_free(str);
+
+ if (opt & QDIST_PR_BORDER) {
+ g_string_append(s, border);
+ }
+ if (rlabel) {
+ g_string_append(s, rlabel);
+ }
+
+ str = g_string_free(s, FALSE);
+ pr = qdist_pr(&dist, n, opt);
+ g_assert_cmpstr(pr, ==, str);
+ g_free(pr);
+ g_free(str);
+
+ qdist_destroy(&dist);
+}
+
+static inline void do_test_pr_label(uint32_t opt)
+{
+ opt |= QDIST_PR_LABELS;
+ do_test_pr(opt);
+}
+
+static void test_pr(void)
+{
+ do_test_pr(0);
+
+ do_test_pr(QDIST_PR_BORDER);
+
+ /* 100X should be ignored because we're not setting LABELS */
+ do_test_pr(QDIST_PR_100X);
+
+ do_test_pr_label(0);
+ do_test_pr_label(QDIST_PR_NODECIMAL);
+ do_test_pr_label(QDIST_PR_PERCENT | QDIST_PR_NODECIMAL);
+ do_test_pr_label(QDIST_PR_100X);
+ do_test_pr_label(QDIST_PR_NOBINRANGE | QDIST_PR_NODECIMAL);
+}
+
+static void test_bin_shrink(void)
+{
+ static const struct entry_desc a[] = {
+ [0] = { 0.0, 42922, 7 },
+ [1] = { 0.25, 47834, 8 },
+ [2] = { 0.50, 26628, 0 },
+ [3] = { 0.625, 597, 4 },
+ [4] = { 0.75, 10298, 1 },
+ [5] = { 0.875, 22, 2 },
+ [6] = { 1.0, 2771, 1 }
+ };
+ static const struct entry_desc b[] = {
+ [0] = { 0.0, 42922, 7 },
+ [1] = { 0.25, 47834, 8 },
+ [2] = { 0.50, 27225, 3 },
+ [3] = { 0.75, 13091, 1 }
+ };
+
+ return do_test_bin(a, ARRAY_SIZE(a), b, ARRAY_SIZE(b));
+}
+
+static void test_bin_expand(void)
+{
+ static const struct entry_desc a[] = {
+ [0] = { 0.0, 11713, 5 },
+ [1] = { 0.25, 20294, 0 },
+ [2] = { 0.50, 17266, 8 },
+ [3] = { 0.625, 1506, 0 },
+ [4] = { 0.75, 10355, 6 },
+ [5] = { 0.833, 2, 1 },
+ [6] = { 0.875, 99, 4 },
+ [7] = { 1.0, 4301, 2 }
+ };
+ static const struct entry_desc b[] = {
+ [0] = { 0.0, 11713, 5 },
+ [1] = { 0.0, 0, 0 },
+ [2] = { 0.0, 20294, 8 },
+ [3] = { 0.0, 0, 0 },
+ [4] = { 0.0, 0, 0 },
+ [5] = { 0.0, 17266, 6 },
+ [6] = { 0.0, 1506, 1 },
+ [7] = { 0.0, 10355, 4 },
+ [8] = { 0.0, 101, 1 },
+ [9] = { 0.0, 4301, 2 }
+ };
+
+ return do_test_bin(a, ARRAY_SIZE(a), b, ARRAY_SIZE(b));
+}
+
+static void test_bin_simple(void)
+{
+ static const struct entry_desc a[] = {
+ [0] = { 10, 101, 8 },
+ [1] = { 11, 0, 0 },
+ [2] = { 12, 2, 1 }
+ };
+ static const struct entry_desc b[] = {
+ [0] = { 0, 101, 8 },
+ [1] = { 0, 0, 0 },
+ [2] = { 0, 0, 0 },
+ [3] = { 0, 0, 0 },
+ [4] = { 0, 2, 1 }
+ };
+
+ return do_test_bin(a, ARRAY_SIZE(a), b, ARRAY_SIZE(b));
+}
+
+static void test_single_full(void)
+{
+ struct qdist dist;
+
+ qdist_init(&dist);
+
+ qdist_add(&dist, 3, 102);
+ g_assert_cmpfloat(qdist_avg(&dist), ==, 3);
+ g_assert_cmpfloat(qdist_xmin(&dist), ==, 3);
+ g_assert_cmpfloat(qdist_xmax(&dist), ==, 3);
+
+ histogram_check_single_full(&dist, 0);
+ histogram_check_single_full(&dist, 1);
+ histogram_check_single_full(&dist, 10);
+
+ qdist_destroy(&dist);
+}
+
+static void test_single_empty(void)
+{
+ struct qdist dist;
+ char *pr;
+
+ qdist_init(&dist);
+
+ qdist_add(&dist, 3, 0);
+ g_assert_cmpuint(qdist_sample_count(&dist), ==, 0);
+ g_assert(isnan(qdist_avg(&dist)));
+ g_assert_cmpfloat(qdist_xmin(&dist), ==, 3);
+ g_assert_cmpfloat(qdist_xmax(&dist), ==, 3);
+
+ pr = qdist_pr_plain(&dist, 0);
+ g_assert_cmpstr(pr, ==, " ");
+ g_free(pr);
+
+ pr = qdist_pr_plain(&dist, 1);
+ g_assert_cmpstr(pr, ==, " ");
+ g_free(pr);
+
+ pr = qdist_pr_plain(&dist, 2);
+ g_assert_cmpstr(pr, ==, " ");
+ g_free(pr);
+
+ qdist_destroy(&dist);
+}
+
+static void test_none(void)
+{
+ struct qdist dist;
+ char *pr;
+
+ qdist_init(&dist);
+
+ g_assert(isnan(qdist_avg(&dist)));
+ g_assert(isnan(qdist_xmin(&dist)));
+ g_assert(isnan(qdist_xmax(&dist)));
+
+ pr = qdist_pr_plain(&dist, 0);
+ g_assert(pr == NULL);
+
+ pr = qdist_pr_plain(&dist, 2);
+ g_assert(pr == NULL);
+
+ qdist_destroy(&dist);
+}
+
+int main(int argc, char *argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func("/qdist/none", test_none);
+ g_test_add_func("/qdist/single/empty", test_single_empty);
+ g_test_add_func("/qdist/single/full", test_single_full);
+ g_test_add_func("/qdist/binning/simple", test_bin_simple);
+ g_test_add_func("/qdist/binning/expand", test_bin_expand);
+ g_test_add_func("/qdist/binning/shrink", test_bin_shrink);
+ g_test_add_func("/qdist/pr", test_pr);
+ return g_test_run();
+}
--
2.5.0
- [Qemu-devel] [PATCH v4 00/14] tb hash improvements, Emilio G. Cota, 2016/04/29
- [Qemu-devel] [PATCH v4 01/14] compiler.h: add QEMU_ALIGNED() to enforce struct alignment, Emilio G. Cota, 2016/04/29
- [Qemu-devel] [PATCH v4 04/14] include/processor.h: define cpu_relax(), Emilio G. Cota, 2016/04/29
- [Qemu-devel] [PATCH v4 08/14] tb hash: hash phys_pc, pc, and flags with xxhash, Emilio G. Cota, 2016/04/29
- [Qemu-devel] [PATCH v4 03/14] seqlock: rename write_lock/unlock to write_begin/end, Emilio G. Cota, 2016/04/29
- [Qemu-devel] [PATCH v4 10/14] qdist: add test program,
Emilio G. Cota <=
- [Qemu-devel] [PATCH v4 05/14] atomics: add atomic_test_and_set, Emilio G. Cota, 2016/04/29
- [Qemu-devel] [PATCH v4 11/14] qht: QEMU's fast, resizable and scalable Hash Table, Emilio G. Cota, 2016/04/29
- [Qemu-devel] [PATCH v4 06/14] qemu-thread: add simple test-and-set spinlock, Emilio G. Cota, 2016/04/29
- [Qemu-devel] [PATCH v4 14/14] translate-all: add tb hash bucket info to 'info jit' dump, Emilio G. Cota, 2016/04/29
- [Qemu-devel] [PATCH v4 02/14] seqlock: remove optional mutex, Emilio G. Cota, 2016/04/29
- [Qemu-devel] [PATCH v4 07/14] exec: add tb_hash_func5, derived from xxhash, Emilio G. Cota, 2016/04/29
- [Qemu-devel] [PATCH v4 12/14] qht: add test program, Emilio G. Cota, 2016/04/29
- [Qemu-devel] [PATCH v4 13/14] tb hash: track translated blocks with qht, Emilio G. Cota, 2016/04/29
- [Qemu-devel] [PATCH v4 09/14] qdist: add module to represent frequency distributions of data, Emilio G. Cota, 2016/04/29