From patchwork Sat Apr 30 03:33:13 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emilio Cota X-Patchwork-Id: 8986481 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id BAACABF29F for ; Sat, 30 Apr 2016 03:34:33 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 59371201DD for ; Sat, 30 Apr 2016 03:34:32 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 008C6201CD for ; Sat, 30 Apr 2016 03:34:30 +0000 (UTC) Received: from localhost ([::1]:57153 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1awLfn-0004Pb-3P for patchwork-qemu-devel@patchwork.kernel.org; Fri, 29 Apr 2016 23:34:27 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:59224) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1awLfN-00040w-M8 for qemu-devel@nongnu.org; Fri, 29 Apr 2016 23:34:08 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1awLf7-00005h-GP for qemu-devel@nongnu.org; Fri, 29 Apr 2016 23:33:56 -0400 Received: from out5-smtp.messagingengine.com ([66.111.4.29]:36111) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1awLf6-0008Td-6x for qemu-devel@nongnu.org; Fri, 29 Apr 2016 23:33:45 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 93C8620842 for ; Fri, 29 Apr 2016 23:33:21 -0400 (EDT) Received: from frontend1 ([10.202.2.160]) by compute3.internal (MEProxy); Fri, 29 Apr 2016 23:33:21 -0400 DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=braap.org; h=cc :date:from:in-reply-to:message-id:references:subject:to :x-sasl-enc:x-sasl-enc; s=mesmtp; bh=if+m/5+YAQ9wAwH1Xi3H4C07iHA =; b=IhjD5LmsrB0dn8O8IZLJkM9ZtLzQGqXRwRf+4kLHNhqbsBoC66xEPahBYvt ZlRM0rNsJZ6hyMGXK7LmnI1849tx66655V7kpothGEmDTB6AlBopoZr/HOt++clt 4CGkaHm0qrNRZJeprWjIb7pSZ+NSkVMINO5huCCxgK3WCz6Y= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d= messagingengine.com; h=cc:date:from:in-reply-to:message-id :references:subject:to:x-sasl-enc:x-sasl-enc; s=smtpout; bh=if+m /5+YAQ9wAwH1Xi3H4C07iHA=; b=DIR9IlgvxWuvNzxyDjjbgTqg7hcoMjN1A1fL F7FA7RiT2/J2qdhDRtG1t+1YPBcK7hWsbt7JiWID6OShaGC/+Sgx3zD/Mo0kMubG 94cs8HjMxnLxZSdAGL490PPqkvzxJ8sWYDdc43lAz+Q5bFbAUAXqpEPwc3ZpqIU9 1K8s9cE= X-Sasl-enc: OvBLo4lMPH+lDrOp61Bcg6GZxE8DkMybU/wXEt6ClP4c 1461987201 Received: from localhost (flamenco.cs.columbia.edu [128.59.20.216]) by mail.messagingengine.com (Postfix) with ESMTPA id 2EBC8C00012; Fri, 29 Apr 2016 23:33:21 -0400 (EDT) From: "Emilio G. Cota" To: QEMU Developers , MTTCG Devel Date: Fri, 29 Apr 2016 23:33:13 -0400 Message-Id: <1461987197-31264-11-git-send-email-cota@braap.org> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1461987197-31264-1-git-send-email-cota@braap.org> References: <1461987197-31264-1-git-send-email-cota@braap.org> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 66.111.4.29 Subject: [Qemu-devel] [PATCH v4 10/14] qdist: add test program X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paolo Bonzini , Sergey Fedorov , Richard Henderson , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Peter Crosthwaite Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Emilio G. Cota Reviewed-by: Richard Henderson --- 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 +#include "qemu/qdist.h" + +#include + +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(); +}