From patchwork Wed Feb 10 10:53:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Tvrtko Ursulin X-Patchwork-Id: 12080501 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,HK_RANDOM_FROM,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 95E4CC433E0 for ; Wed, 10 Feb 2021 10:54:00 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1B11B64E32 for ; Wed, 10 Feb 2021 10:53:59 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1B11B64E32 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 77ACC6EC51; Wed, 10 Feb 2021 10:53:59 +0000 (UTC) Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by gabe.freedesktop.org (Postfix) with ESMTPS id 41D7C6EC51; Wed, 10 Feb 2021 10:53:58 +0000 (UTC) IronPort-SDR: wMFOiuByK5PkouiNZAgz8uWO/8q77nukPMcqxJbvNKWTo62HsJGQmW+l07KPIhRmM1z2WyoznV pHKMdjgjSxeQ== X-IronPort-AV: E=McAfee;i="6000,8403,9890"; a="161803063" X-IronPort-AV: E=Sophos;i="5.81,168,1610438400"; d="scan'208";a="161803063" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Feb 2021 02:53:55 -0800 IronPort-SDR: yBNWdwSgUy8uQvz/W76RJ2fnUD4WBrYnVmPFG0VC7RDU0sujmPpE5boQ1yp8qYkQvE5Qv0YDp3 Y7AGk1KsvJkg== X-IronPort-AV: E=Sophos;i="5.81,168,1610438400"; d="scan'208";a="359529229" Received: from baruchs-mobl.ger.corp.intel.com (HELO localhost.localdomain) ([10.214.255.101]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Feb 2021 02:53:53 -0800 From: Tvrtko Ursulin To: igt-dev@lists.freedesktop.org Date: Wed, 10 Feb 2021 10:53:43 +0000 Message-Id: <20210210105343.63133-1-tvrtko.ursulin@linux.intel.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210210093756.61424-2-tvrtko.ursulin@linux.intel.com> References: <20210210093756.61424-2-tvrtko.ursulin@linux.intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH i-g-t 2/3] intel_gpu_top: Aggregate clients by PID by default X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Intel-gfx@lists.freedesktop.org Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Tvrtko Ursulin Implement a default view where clients are aggregated by their PID. Toggled by pressing 'H' similar to top(1). v2: * Fix memory leak. v3: * Do not allow sort by client id in aggregated mode. * Tweak sort criteria and sorting decisions. (Chris) Signed-off-by: Tvrtko Ursulin Reviewed-by: Chris Wilson --- man/intel_gpu_top.rst | 1 + tools/intel_gpu_top.c | 130 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 118 insertions(+), 13 deletions(-) diff --git a/man/intel_gpu_top.rst b/man/intel_gpu_top.rst index b145d85c0440..20658e291db0 100644 --- a/man/intel_gpu_top.rst +++ b/man/intel_gpu_top.rst @@ -58,6 +58,7 @@ Supported keys: 'n' Toggle display of numeric client busyness overlay. 's' Toggle between sort modes (runtime, total runtime, pid, client id). 'i' Toggle display of clients which used no GPU time. + 'H' Toggle between per PID aggregation and individual clients. DEVICE SELECTION ================ diff --git a/tools/intel_gpu_top.c b/tools/intel_gpu_top.c index 63ef77056341..695a8cb397ae 100644 --- a/tools/intel_gpu_top.c +++ b/tools/intel_gpu_top.c @@ -979,17 +979,18 @@ static int client_pid_cmp(const void *_a, const void *_b) static int (*client_cmp)(const void *, const void *) = client_last_cmp; -static void sort_clients(struct clients *clients) +static struct clients *sort_clients(struct clients *clients, + int (*cmp)(const void *, const void *)) { unsigned int active, free; struct client *c; int tmp; if (!clients) - return; + return clients; qsort(clients->client, clients->num_clients, sizeof(*clients->client), - client_cmp); + cmp); /* Trim excessive array space. */ active = 0; @@ -1011,9 +1012,95 @@ static void sort_clients(struct clients *clients) sizeof(*c)); } } + + return clients; } -static void scan_clients(struct clients *clients) +static bool aggregate_pids = true; + +static struct clients *display_clients(struct clients *clients) +{ + struct client *ac, *c, *cp = NULL; + struct clients *aggregated; + int tmp, num = 0; + + if (!aggregate_pids) + return sort_clients(clients, client_cmp); + + /* Sort by pid first to make it easy to aggregate while walking. */ + sort_clients(clients, client_pid_cmp); + + aggregated = calloc(1, sizeof(*clients)); + assert(aggregated); + + ac = calloc(clients->num_clients, sizeof(*c)); + assert(ac); + + aggregated->num_classes = clients->num_classes; + aggregated->class = clients->class; + aggregated->client = ac; + + for_each_client(clients, c, tmp) { + unsigned int i; + + if (c->status == FREE) + break; + + assert(c->status == ALIVE); + + if ((cp && c->pid != cp->pid) || !cp) { + ac = &aggregated->client[num++]; + + /* New pid. */ + ac->clients = aggregated; + ac->status = ALIVE; + ac->id = -c->pid; + ac->pid = c->pid; + ac->busy_root = -1; + ac->sysfs_root = -1; + strcpy(ac->name, c->name); + strcpy(ac->print_name, c->print_name); + ac->engines = c->engines; + ac->val = calloc(clients->num_classes, + sizeof(ac->val[0])); + assert(ac->val); + ac->samples = 1; + } + + cp = c; + + if (c->samples < 2) + continue; + + ac->samples = 2; /* All what matters for display. */ + ac->total_runtime += c->total_runtime; + ac->last_runtime += c->last_runtime; + + for (i = 0; i < clients->num_classes; i++) + ac->val[i] += c->val[i]; + } + + aggregated->num_clients = num; + aggregated->active_clients = num; + + return sort_clients(aggregated, client_cmp); +} + +static void free_clients(struct clients *clients) +{ + struct client *c; + unsigned int tmp; + + for_each_client(clients, c, tmp) { + free(c->val); + free(c->last); + } + + free(clients->client); + free(clients); +} + +static struct clients *scan_clients(struct clients *clients) { struct dirent *dent; struct client *c; @@ -1022,7 +1109,7 @@ static void scan_clients(struct clients *clients) DIR *d; if (!clients) - return; + return clients; for_each_client(clients, c, tmp) { assert(c->status != PROBE); @@ -1034,7 +1121,7 @@ static void scan_clients(struct clients *clients) d = opendir(clients->sysfs_root); if (!d) - return; + return clients; while ((dent = readdir(d)) != NULL) { char name[24], pid[24]; @@ -1077,7 +1164,7 @@ static void scan_clients(struct clients *clients) break; } - sort_clients(clients); + return display_clients(clients); } static const char *bars[] = { " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█" }; @@ -2177,11 +2264,16 @@ static void select_client_sort(void) }; static unsigned int client_sort; +bump: if (++client_sort >= ARRAY_SIZE(cmp)) client_sort = 0; client_cmp = cmp[client_sort].cmp; header_msg = cmp[client_sort].msg; + + /* Sort by client id makes no sense with pid aggregation. */ + if (aggregate_pids && client_cmp == client_id_cmp) + goto bump; } static void process_stdin(unsigned int timeout_us) @@ -2227,6 +2319,13 @@ static void process_stdin(unsigned int timeout_us) case 's': select_client_sort(); break; + case 'H': + aggregate_pids ^= true; + if (aggregate_pids) + header_msg = "Aggregating clients."; + else + header_msg = "Showing individual clients."; + break; }; } } @@ -2378,6 +2477,7 @@ int main(int argc, char **argv) codename = igt_device_get_pretty_name(&card, false); while (!stop_top) { + struct clients *disp_clients; bool consumed = false; int j, lines = 0; struct winsize ws; @@ -2400,7 +2500,7 @@ int main(int argc, char **argv) pmu_sample(engines); t = (double)(engines->ts.cur - engines->ts.prev) / 1e9; - scan_clients(clients); + disp_clients = scan_clients(clients); if (stop_top) break; @@ -2416,14 +2516,14 @@ int main(int argc, char **argv) lines = print_engines(engines, t, lines, con_w, con_h); - if (clients) { + if (disp_clients) { int class_w; - lines = print_clients_header(clients, lines, + lines = print_clients_header(disp_clients, lines, con_w, con_h, &class_w); - for_each_client(clients, c, j) { + for_each_client(disp_clients, c, j) { assert(c->status != PROBE); if (c->status != ALIVE) break; /* Active clients are first in the array. */ @@ -2437,8 +2537,9 @@ int main(int argc, char **argv) &class_w); } - lines = print_clients_footer(clients, t, lines, - con_w, con_h); + lines = print_clients_footer(disp_clients, t, + lines, con_w, + con_h); } pops->close_struct(); @@ -2447,6 +2548,9 @@ int main(int argc, char **argv) if (stop_top) break; + if (disp_clients != clients) + free_clients(disp_clients); + if (output_mode == INTERACTIVE) process_stdin(period_us); else