From patchwork Thu Aug 30 14:17:33 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jones X-Patchwork-Id: 10581773 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 624C317DB for ; Thu, 30 Aug 2018 14:17:43 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5164E2BF61 for ; Thu, 30 Aug 2018 14:17:43 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 45E142BF70; Thu, 30 Aug 2018 14:17:43 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A0BF52BF61 for ; Thu, 30 Aug 2018 14:17:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729362AbeH3SUC (ORCPT ); Thu, 30 Aug 2018 14:20:02 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34606 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1729208AbeH3SUB (ORCPT ); Thu, 30 Aug 2018 14:20:01 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id AEF3926356; Thu, 30 Aug 2018 14:17:39 +0000 (UTC) Received: from kamzik.brq.redhat.com (unknown [10.43.2.160]) by smtp.corp.redhat.com (Postfix) with ESMTP id 49EDDFA96E; Thu, 30 Aug 2018 14:17:38 +0000 (UTC) From: Andrew Jones To: kvm@vger.kernel.org Cc: shihwei@cs.columbia.edu, christoffer.dall@arm.com, marc.zyngier@arm.com, ynorov@caviumnetworks.com, kvmarm@lists.cs.columbia.edu, Christoffer Dall Subject: [PATCH kvm-unit-tests 2/2] arm64: add micro-bench Date: Thu, 30 Aug 2018 16:17:33 +0200 Message-Id: <20180830141733.21725-3-drjones@redhat.com> In-Reply-To: <20180830141733.21725-1-drjones@redhat.com> References: <20180830141733.21725-1-drjones@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Thu, 30 Aug 2018 14:17:39 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Thu, 30 Aug 2018 14:17:39 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'drjones@redhat.com' RCPT:'' Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Shih-Wei Li Here we provide the support for measuring various micro level operations on arm64. Measurements are currently obtained using timer counters. Further modifications in KVM will be required to support timestamping using cycle counters, as KVM now disables accesses to the PMU counters from the VM. Signed-off-by: Shih-Wei Li Signed-off-by: Christoffer Dall Signed-off-by: Andrew Jones Acked-by: Christoffer Dall Tested-by: Shih-Wei Li --- arm/Makefile.arm64 | 1 + arm/micro-bench.c | 213 +++++++++++++++++++++++++++++++++++++++++++++ arm/unittests.cfg | 8 ++ 3 files changed, 222 insertions(+) create mode 100644 arm/micro-bench.c diff --git a/arm/Makefile.arm64 b/arm/Makefile.arm64 index f04bbf476763..637435c523da 100644 --- a/arm/Makefile.arm64 +++ b/arm/Makefile.arm64 @@ -15,6 +15,7 @@ OBJDIRS += lib/arm64 # arm64 specific tests tests = $(TEST_DIR)/timer.flat +tests += $(TEST_DIR)/micro-bench.flat include $(SRCDIR)/$(TEST_DIR)/Makefile.common diff --git a/arm/micro-bench.c b/arm/micro-bench.c new file mode 100644 index 000000000000..76650d647f6a --- /dev/null +++ b/arm/micro-bench.c @@ -0,0 +1,213 @@ +/* + * Measure the cost of micro level operations. + * + * This test provides support for quantifying the cost of micro level + * operations. To improve precision in the measurements, one should + * consider pinning each VCPU to a specific physical CPU (PCPU) and to + * ensure no other task could run on that PCPU to skew the results. + * This can be achieved by enabling QMP server in the QEMU command in + * unittest.cfg for micro-bench, allowing a client program to get the + * thread_id for each VCPU thread from the QMP server. Based on that + * information, the client program can then pin the corresponding VCPUs to + * dedicated PCPUs and isolate interrupts and tasks from those PCPUs. + * + * Copyright Columbia University + * Author: Shih-Wei Li + * Author: Christoffer Dall + * Author: Andrew Jones + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#include +#include + +#define NTIMES (1U << 16) + +static u32 cntfrq; + +static volatile bool ipi_ready, ipi_received; +static void *vgic_dist_base; +static void (*write_eoir)(u32 irqstat); + +static void ipi_irq_handler(struct pt_regs *regs) +{ + ipi_ready = false; + ipi_received = true; + gic_write_eoir(gic_read_iar()); + ipi_ready = true; +} + +static void ipi_secondary_entry(void *data) +{ + install_irq_handler(EL1H_IRQ, ipi_irq_handler); + gic_enable_defaults(); + local_irq_enable(); + ipi_ready = true; + while (true) + cpu_relax(); +} + +static bool test_init(void) +{ + int v = gic_init(); + + if (!v) { + printf("No supported gic present, skipping tests...\n"); + return false; + } + + if (nr_cpus < 2) { + printf("At least two cpus required, skipping tests...\n"); + return false; + } + + switch (v) { + case 2: + vgic_dist_base = gicv2_dist_base(); + write_eoir = gicv2_write_eoir; + case 3: + vgic_dist_base = gicv3_dist_base(); + write_eoir = gicv3_write_eoir; + } + + ipi_ready = false; + gic_enable_defaults(); + on_cpu_async(1, ipi_secondary_entry, NULL); + + cntfrq = get_cntfrq(); + printf("Timer Frequency %d Hz (Output in microseconds)\n", cntfrq); + + return true; +} + +static void ipi_prep(void) +{ + unsigned tries = 1 << 28; + + while (!ipi_ready && tries--) + cpu_relax(); + assert(ipi_ready); +} + +static void ipi_exec(void) +{ + unsigned tries = 1 << 28; + static int received = 0; + + ipi_received = false; + + gic_ipi_send_single(1, 1); + + while (!ipi_received && tries--) + cpu_relax(); + + ++received; + assert_msg(ipi_received, "failed to receive IPI in time, but received %d successfully\n", received); +} + +static void hvc_exec(void) +{ + asm volatile("mov w0, #0x4b000000; hvc #0" ::: "w0"); +} + +static void mmio_read_user_exec(void) +{ + /* + * FIXME: Read device-id in virtio mmio here in order to + * force an exit to userspace. This address needs to be + * updated in the future if any relevant changes in QEMU + * test-dev are made. + */ + void *userspace_emulated_addr = (void*)0x0a000008; + + readl(userspace_emulated_addr); +} + +static void mmio_read_vgic_exec(void) +{ + readl(vgic_dist_base + GICD_IIDR); +} + +static void eoi_exec(void) +{ + int spurious_id = 1023; /* writes to EOI are ignored */ + + /* Avoid measuring assert(..) in gic_write_eoir */ + write_eoir(spurious_id); +} + +struct exit_test { + const char *name; + void (*prep)(void); + void (*exec)(void); + bool run; +}; + +static struct exit_test tests[] = { + {"hvc", NULL, hvc_exec, true}, + {"mmio_read_user", NULL, mmio_read_user_exec, true}, + {"mmio_read_vgic", NULL, mmio_read_vgic_exec, true}, + {"eoi", NULL, eoi_exec, true}, + {"ipi", ipi_prep, ipi_exec, true}, +}; + +struct ns_time { + uint64_t ns; + uint64_t ns_frac; +}; + +#define PS_PER_SEC (1000 * 1000 * 1000 * 1000U) +static void ticks_to_ns_time(uint64_t ticks, struct ns_time *ns_time) +{ + uint64_t ps_per_tick = PS_PER_SEC / cntfrq + !!(PS_PER_SEC % cntfrq); + uint64_t ps; + + ps = ticks * ps_per_tick; + ns_time->ns = ps / 1000; + ns_time->ns_frac = (ps % 1000) / 100; +} + +static void loop_test(struct exit_test *test) +{ + uint64_t start, end, total_ticks, ntimes = NTIMES; + struct ns_time total_ns, avg_ns; + + if (test->prep) + test->prep(); + + isb(); + start = read_sysreg(cntpct_el0); + while (ntimes--) + test->exec(); + isb(); + end = read_sysreg(cntpct_el0); + + total_ticks = end - start; + ticks_to_ns_time(total_ticks, &total_ns); + avg_ns.ns = total_ns.ns / NTIMES; + avg_ns.ns_frac = total_ns.ns_frac / NTIMES; + + printf("%-30s%15" PRId64 ".%-15" PRId64 "%15" PRId64 ".%-15" PRId64 "\n", + test->name, total_ns.ns, total_ns.ns_frac, avg_ns.ns, avg_ns.ns_frac); +} + +int main(int argc, char **argv) +{ + int i; + + if (!test_init()) + return 1; + + printf("\n%-30s%18s%13s%18s%13s\n", "name", "total ns", "", "avg ns", ""); + for (i = 0 ; i < 92; ++i) + printf("%c", '-'); + printf("\n"); + for (i = 0; i < ARRAY_SIZE(tests); i++) { + if (!tests[i].run) + continue; + assert(tests[i].name && tests[i].exec); + loop_test(&tests[i]); + } + + return 0; +} diff --git a/arm/unittests.cfg b/arm/unittests.cfg index 44b98cfc7afd..5c8a332da004 100644 --- a/arm/unittests.cfg +++ b/arm/unittests.cfg @@ -116,3 +116,11 @@ file = timer.flat groups = timer timeout = 2s arch = arm64 + +# Exit tests +[micro-bench] +file = micro-bench.flat +smp = 2 +groups = nodefault,micro-bench +accel = kvm +arch = arm64