From patchwork Tue Jun 2 15:46:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Alex_Benn=C3=A9e?= X-Patchwork-Id: 187377 Delivered-To: patch@linaro.org Received: by 2002:a92:5b0a:0:0:0:0:0 with SMTP id p10csp4093288ilb; Tue, 2 Jun 2020 08:54:01 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwKznCCoClAYHFFl2OxHBLRN64ocCwEoUQiF9dnQH80Yaf7MKEBznaRw0Gxq43jmMvchFhF X-Received: by 2002:a25:eb05:: with SMTP id d5mr21672350ybs.12.1591113241298; Tue, 02 Jun 2020 08:54:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1591113241; cv=none; d=google.com; s=arc-20160816; b=fa0HK28gM3RvdtfA7sxUSgvyV3q6rsXGMvv5egGx4SV2wagE+WIQVoU0LpuBMNlE7S 0/Okr19/3diGh9kjDeuVJyuu9eBWXBBye9CIgH5rEMHMJfjk7P1Iy+e49clvSTYbk6Ju 84tiOlWRszYmHqo+8BU7JD6Oj3BuTN0TaRKbawUtD/KuacwXyQphmmGvarhhul+Ssyba kkYc4gYQXKSNDHFfXrYd2hkYn3UrfLbpLabWZUo7BLqYeokzea5+LCQ3vzokNHVAMEV9 u656k803QRmKfZHdPPZ6XuB7amRfNtfjUglYdtzgCAVcqxuoSkYhv8v2an6bvfShw1DP hCaA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:to:from :dkim-signature; bh=TTAp5rDD3D05lpMYKygwT+EZBLy9H09vRzxjadlC3og=; b=T5ggP2MRX+dNN4Y6GRYvD+5yu+98Fl//6ymIz5ZRTBB9Tsfw5Jc/lmh1ovB/zRcRbQ u83WVKuKKM6psYquCMBtKf2LwzwM+ToAnvwc0yUKQkmCveUIDN6k58JZQt23QgNe0nAk Ina7+Hgxow2xPeMDkzc9oWzB1t5BEC9P3NjDyDxxu7/sYGkrZJ3idp3EyX5XOSkYQWC3 ui8lY0Osse9+vRAPGRgc7GrSe2kYgBDaWR+vrSywc28kTmAI1I4e9j+wwYejucvjy8Z3 oK7485gmSNjGZnGPNhVVgI5WxnEKSxfL9Ivt/j8eZPg2Ojc4a6fAkvedCBwvnI75f5tH xfFQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=boJLOshU; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id u10si2343133ybm.304.2020.06.02.08.54.01 for (version=TLS1_2 cipher=ECDHE-ECDSA-CHACHA20-POLY1305 bits=256/256); Tue, 02 Jun 2020 08:54:01 -0700 (PDT) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=boJLOshU; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([::1]:49826 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jg9Em-0005me-Qe for patch@linaro.org; Tue, 02 Jun 2020 11:54:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:55732) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jg97h-0003p9-Qa for qemu-devel@nongnu.org; Tue, 02 Jun 2020 11:46:41 -0400 Received: from mail-wm1-x332.google.com ([2a00:1450:4864:20::332]:54511) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jg97g-0007dx-DQ for qemu-devel@nongnu.org; Tue, 02 Jun 2020 11:46:41 -0400 Received: by mail-wm1-x332.google.com with SMTP id g10so3402146wmh.4 for ; Tue, 02 Jun 2020 08:46:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=TTAp5rDD3D05lpMYKygwT+EZBLy9H09vRzxjadlC3og=; b=boJLOshUdKXGZfw665tFYM4A4pCjHkOuSLRwmpolEJ1R0ind9XcaALkQ4LcriVcjj4 I1Q1cs5XA0/7S+2W9lYhrEQnTXzY6Gs8Dba9RgIkd2OVpvHebJG0pizNUVkf72fXl6bB POYPkewda46q8tBX5ZYhluUdIGsqcJe4TEkDo1fx5lOB3DDUnq+UIbZ/iMHdhlSe2IPt z/W4ZpeAYAE6xd8RwcfSEZAuQUEJZ/ocnY2ZKNqAK0Qde48+9VHckBM46Q0MwDSTC0SV 0ubnhpToIFoI0xshuKpnHJJUpqrlQgJNuc00fQTUzkCLZ9kQCYI5PxZ2Nwg7oDDeyXo4 ke0w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=TTAp5rDD3D05lpMYKygwT+EZBLy9H09vRzxjadlC3og=; b=C/5UCFOLEQNt3DRA2l3zHYuvlHRMWNXrbCYkKIDdEQ9+8qpTiKxAQbZwyOA/vdAYfU 3gbTuDjJJ2y7IihQQfwxdTd70RrjX9m4p4k+SrPkST42W5Nwpq+GClDB6vKMz20T2tkk K9vXsc09Uk1CnMjWCYw00tAB9dNTJpok4Xn/lr+GSjB5R0tW/tJgdKsKC5QThQ7mDVF4 uD+FvpwMaCFN2OQeb/4ubYxaX3SeqAjl3GITV6pI31MJ7BnfBXUGnbM8pSuTZNpriLRd nHfOMIij8SKxOZaf8b+ku3og4bvycJ9is3XQTBgQbsg8d6UgKuBRKeglKtSiMe/JIE21 Lrlg== X-Gm-Message-State: AOAM533yCZoXkhKrP2eYe+u8g7/DdH6BjxIw3ydNYX5wxngQZ9HPtHlM rpcwQHDaTpEi8J8QGoxqxX/j4Q== X-Received: by 2002:a1c:bc84:: with SMTP id m126mr5004966wmf.159.1591112798854; Tue, 02 Jun 2020 08:46:38 -0700 (PDT) Received: from zen.linaroharston ([51.148.130.216]) by smtp.gmail.com with ESMTPSA id b136sm283700wme.1.2020.06.02.08.46.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 02 Jun 2020 08:46:32 -0700 (PDT) Received: from zen.lan (localhost [127.0.0.1]) by zen.linaroharston (Postfix) with ESMTP id F09D61FF96; Tue, 2 Jun 2020 16:46:24 +0100 (BST) From: =?utf-8?q?Alex_Benn=C3=A9e?= To: qemu-devel@nongnu.org Subject: [PATCH v1 8/9] plugins: new hwprofile plugin Date: Tue, 2 Jun 2020 16:46:23 +0100 Message-Id: <20200602154624.4460-9-alex.bennee@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200602154624.4460-1-alex.bennee@linaro.org> References: <20200602154624.4460-1-alex.bennee@linaro.org> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::332; envelope-from=alex.bennee@linaro.org; helo=mail-wm1-x332.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001 autolearn=_AUTOLEARN X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: robert.foley@linaro.org, robhenry@microsoft.com, aaron@os.amperecomputing.com, cota@braap.org, kuhn.chenqun@huawei.com, peter.puhov@linaro.org, =?utf-8?q?Alex_Benn=C3=A9e?= Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" This is a plugin intended to help with profiling access to various bits of system hardware. It only really makes sense for system emulation. It takes advantage of the recently exposed helper API that allows us to see the device name (memory region name) associated with a device. Signed-off-by: Alex Bennée --- tests/plugin/hwprofile.c | 248 +++++++++++++++++++++++++++++++++++++++ tests/plugin/Makefile | 1 + 2 files changed, 249 insertions(+) create mode 100644 tests/plugin/hwprofile.c -- 2.20.1 Reviewed-by: Robert Foley Tested-by: Robert Foley diff --git a/tests/plugin/hwprofile.c b/tests/plugin/hwprofile.c new file mode 100644 index 00000000000..f5e0639e762 --- /dev/null +++ b/tests/plugin/hwprofile.c @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2020, Alex Bennée + * + * HW Profile - breakdown access patterns for IO to devices + * + * License: GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +typedef struct { + uint64_t offset; + int size; + int cpu_read; + int cpu_write; + uint64_t reads; + uint64_t writes; +} IOLocationCounts; + +typedef struct { + const char *name; + uint64_t base; + int cpu_read; + int cpu_write; + uint64_t total_writes; + uint64_t total_reads; + GHashTable *access_pattern; +} DeviceCounts; + +static GMutex lock; +static GHashTable *devices; +static bool detail; + +static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW; + +static inline bool track_reads(void) +{ + return rw == QEMU_PLUGIN_MEM_RW || rw == QEMU_PLUGIN_MEM_R; +} + +static inline bool track_writes(void) +{ + return rw == QEMU_PLUGIN_MEM_RW || rw == QEMU_PLUGIN_MEM_W; +} + +static void plugin_init(void) +{ + devices = g_hash_table_new(g_str_hash, g_str_equal); +} + +static gint sort_cmp(gconstpointer a, gconstpointer b) +{ + DeviceCounts *ea = (DeviceCounts *) a; + DeviceCounts *eb = (DeviceCounts *) b; + return ea->total_reads + ea->total_writes > + eb->total_reads + eb->total_writes ? -1 : 1; +} + +static gint sort_off(gconstpointer a, gconstpointer b) +{ + IOLocationCounts *ea = (IOLocationCounts *) a; + IOLocationCounts *eb = (IOLocationCounts *) b; + return ea->offset > eb->offset; +} + +static void plugin_exit(qemu_plugin_id_t id, void *p) +{ + g_autoptr(GString) report = g_string_new(""); + GList *counts; + + if (!detail) { + g_string_printf(report, "Device, Address"); + if (track_reads()) { + g_string_append_printf(report, ", RCPUs, Reads"); + } + if (track_writes()) { + g_string_append_printf(report, ", WCPUs, Writes"); + } + g_string_append_c(report, '\n'); + } + + counts = g_hash_table_get_values(devices); + if (counts && g_list_next(counts)) { + GList *it; + + it = g_list_sort(counts, sort_cmp); + + while (it) { + DeviceCounts *rec = (DeviceCounts *) it->data; + if (detail) { + GList *accesses = g_hash_table_get_values(rec->access_pattern); + GList *io_it = g_list_sort(accesses, sort_off); + g_string_append_printf(report, "%s @ 0x%"PRIx64"\n", rec->name, rec->base); + while (io_it) { + IOLocationCounts *loc = (IOLocationCounts *) io_it->data; + g_string_append_printf(report, " off:%08"PRIx64, loc->offset); + if (track_reads()) { + g_string_append_printf(report, ", 0x%04x, %"PRId64, + loc->cpu_read, loc->reads); + } + if (track_writes()) { + g_string_append_printf(report, ", 0x%04x, %"PRId64, + loc->cpu_write, loc->writes); + } + g_string_append_c(report,'\n'); + io_it = io_it->next; + } + } else { + g_string_append_printf(report, "%s, 0x%"PRIx64, + rec->name, rec->base); + if (track_reads()) { + g_string_append_printf(report, ", 0x%04x, %"PRId64, + rec->cpu_read, rec->total_reads); + } + if (track_writes()) { + g_string_append_printf(report, ", 0x%04x, %"PRId64, + rec->cpu_write, rec->total_writes); + } + g_string_append_c(report, '\n'); + } + it = it->next; + }; + g_list_free(it); + } + + qemu_plugin_outs(report->str); +} + +static DeviceCounts * new_count(char *name, uint64_t base) +{ + DeviceCounts *count = g_new0(DeviceCounts, 1); + count->name = name; + count->base = base; + if (detail) { + count->access_pattern = g_hash_table_new(g_int64_hash, g_int64_equal); + } + g_hash_table_insert(devices, name, count); + return count; +} + +static IOLocationCounts * new_location(uint64_t offset) +{ + IOLocationCounts *loc = g_new0(IOLocationCounts, 1); + loc->offset = offset; + return loc; +} + +static void vcpu_haddr(unsigned int cpu_index, qemu_plugin_meminfo_t meminfo, + uint64_t vaddr, void *udata) +{ + struct qemu_plugin_hwaddr *hwaddr = qemu_plugin_get_hwaddr(meminfo, vaddr); + + if (!hwaddr || !qemu_plugin_hwaddr_is_io(hwaddr)) { + return; + } else { + char *name = qemu_plugin_hwaddr_device_name(hwaddr); + DeviceCounts *counts; + + g_mutex_lock(&lock); + counts = (DeviceCounts *) g_hash_table_lookup(devices, name); + if (!counts) { + uint64_t off = qemu_plugin_hwaddr_device_offset(hwaddr); + uint64_t base = vaddr - off; + counts = new_count(name, base); + } else { + g_free(name); + } + + if (detail) { + uint64_t off = qemu_plugin_hwaddr_device_offset(hwaddr); + IOLocationCounts *io_count = g_hash_table_lookup(counts->access_pattern, &off); + if (!io_count) { + io_count = new_location(off); + g_hash_table_insert(counts->access_pattern, &off, io_count); + } + if (qemu_plugin_mem_is_store(meminfo)) { + io_count->writes++; + io_count->cpu_write |= (1 << cpu_index); + } else { + io_count->reads++; + io_count->cpu_read |= (1 << cpu_index); + } + } else { + if (qemu_plugin_mem_is_store(meminfo)) { + counts->total_writes++; + counts->cpu_write |= (1 << cpu_index); + } else { + counts->total_reads++; + counts->cpu_read |= (1 << cpu_index); + } + } + g_mutex_unlock(&lock); + } +} + +static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) +{ + size_t n = qemu_plugin_tb_n_insns(tb); + size_t i; + + for (i = 0; i < n; i++) { + struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i); + qemu_plugin_register_vcpu_mem_cb(insn, vcpu_haddr, + QEMU_PLUGIN_CB_NO_REGS, + rw, NULL); + } +} + +QEMU_PLUGIN_EXPORT +int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, + int argc, char **argv) +{ + int i; + + for (i = 0; i < argc; i++) { + char *opt = argv[i]; + if (g_strcmp0(opt, "read") == 0) { + rw = QEMU_PLUGIN_MEM_R; + } else if (g_strcmp0(opt, "write") == 0) { + rw = QEMU_PLUGIN_MEM_W; + } else if (g_strcmp0(opt, "detail") == 0) { + detail = true; + } else { + fprintf(stderr, "option parsing failed: %s\n", opt); + return -1; + } + } + + plugin_init(); + + qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); + qemu_plugin_register_atexit_cb(id, plugin_exit, NULL); + return 0; +} diff --git a/tests/plugin/Makefile b/tests/plugin/Makefile index b3250e2504c..d87b8d40699 100644 --- a/tests/plugin/Makefile +++ b/tests/plugin/Makefile @@ -14,6 +14,7 @@ NAMES += hotblocks NAMES += howvec NAMES += hotpages NAMES += lockstep +NAMES += hwprofile SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES)))