Igt-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
To: igt-dev@lists.freedesktop.org
Cc: Intel-gfx@lists.freedesktop.org,
	Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Subject: [igt-dev] [PATCH i-g-t 2/2] intel_gpu_top: Aggregate engine busyness per class
Date: Wed, 16 Dec 2020 15:28:09 +0000	[thread overview]
Message-ID: <20201216152809.706094-2-tvrtko.ursulin@linux.intel.com> (raw)
In-Reply-To: <20201216152809.706094-1-tvrtko.ursulin@linux.intel.com>

From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

Similarly to how top(1) handles SMP, we can default to showing engines of
a same class as a single bar graph entry.

To achieve this a little bit of hackery is employed. PMU sampling is left
as is and only at the presentation layer we create a fake set of engines,
one for each class, summing and normalizing the load respectively.

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 man/intel_gpu_top.rst |   1 +
 tools/intel_gpu_top.c | 192 +++++++++++++++++++++++++++++++++++++++---
 2 files changed, 180 insertions(+), 13 deletions(-)

diff --git a/man/intel_gpu_top.rst b/man/intel_gpu_top.rst
index 2e0c3a05acc1..35ab10da9bb4 100644
--- a/man/intel_gpu_top.rst
+++ b/man/intel_gpu_top.rst
@@ -54,6 +54,7 @@ RUNTIME CONTROL
 Supported keys:
 
     'q'    Exit from the tool.
+    '1'    Toggle between aggregated engine class and physical engine mode.
 
 DEVICE SELECTION
 ================
diff --git a/tools/intel_gpu_top.c b/tools/intel_gpu_top.c
index 68911940f1d0..8c4280aa19b9 100644
--- a/tools/intel_gpu_top.c
+++ b/tools/intel_gpu_top.c
@@ -76,8 +76,16 @@ struct engine {
 	struct pmu_counter sema;
 };
 
+struct engine_class {
+	unsigned int class;
+	const char *name;
+	unsigned int num_engines;
+};
+
 struct engines {
 	unsigned int num_engines;
+	unsigned int num_classes;
+	struct engine_class *class;
 	unsigned int num_counters;
 	DIR *root;
 	int fd;
@@ -1118,6 +1126,8 @@ print_imc(struct engines *engines, double t, int lines, int con_w, int con_h)
 	return lines;
 }
 
+static bool class_view;
+
 static int
 print_engines_header(struct engines *engines, double t,
 		     int lines, int con_w, int con_h)
@@ -1133,8 +1143,13 @@ print_engines_header(struct engines *engines, double t,
 		pops->open_struct("engines");
 
 		if (output_mode == INTERACTIVE) {
-			const char *a = "          ENGINE      BUSY ";
 			const char *b = " MI_SEMA MI_WAIT";
+			const char *a;
+
+			if (class_view)
+				a = "         ENGINES     BUSY  ";
+			else
+				a = "          ENGINE     BUSY  ";
 
 			printf("\033[7m%s%*s%s\033[0m\n",
 			       a, (int)(con_w - 1 - strlen(a) - strlen(b)),
@@ -1214,6 +1229,164 @@ print_engines_footer(struct engines *engines, double t,
 	return lines;
 }
 
+static int class_cmp(const void *_a, const void *_b)
+{
+	const struct engine_class *a = _a;
+	const struct engine_class *b = _b;
+
+	return a->class - b->class;
+}
+
+static void init_engine_classes(struct engines *engines)
+{
+	struct engine_class *classes;
+	unsigned int i, num;
+	int max = -1;
+
+	for (i = 0; i < engines->num_engines; i++) {
+		struct engine *engine = engine_ptr(engines, i);
+
+		if ((int)engine->class > max)
+			max = engine->class;
+	}
+	assert(max >= 0);
+
+	num = max + 1;
+
+	classes = calloc(num, sizeof(*classes));
+	assert(classes);
+
+	for (i = 0; i < engines->num_engines; i++) {
+		struct engine *engine = engine_ptr(engines, i);
+
+		classes[engine->class].num_engines++;
+	}
+
+	for (i = 0; i < num; i++) {
+		classes[i].class = i;
+		classes[i].name = class_display_name(i);
+	}
+
+	qsort(classes, num, sizeof(*classes), class_cmp);
+
+	engines->num_classes = num;
+	engines->class = classes;
+}
+
+static void __pmu_sum(struct pmu_pair *dst, struct pmu_pair *src)
+{
+	dst->prev += src->prev;
+	dst->cur += src->cur;
+}
+
+static void __pmu_normalize(struct pmu_pair *val, unsigned int n)
+{
+	val->prev /= n;
+	val->cur /= n;
+}
+
+static struct engines *init_classes(struct engines *engines)
+{
+	struct engines *classes;
+	unsigned int i, j;
+
+	init_engine_classes(engines);
+
+	classes = calloc(1, sizeof(struct engines) +
+			    engines->num_classes * sizeof(struct engine));
+	assert(classes);
+
+	classes->num_engines = engines->num_classes;
+	classes->num_classes = engines->num_classes;
+	classes->class = engines->class;
+
+	for (i = 0; i < engines->num_classes; i++) {
+		struct engine *engine = engine_ptr(classes, i);
+
+		engine->class = i;
+		engine->instance = -1;
+
+		if (!engines->class[i].num_engines)
+			continue;
+
+		engine->display_name = strdup(class_display_name(i));
+		assert(engine->display_name);
+		engine->short_name = strdup(class_short_name(i));
+		assert(engine->short_name);
+
+		for (j = 0; j < engines->num_engines; j++) {
+			struct engine *e = engine_ptr(engines, j);
+
+			if (e->class == i) {
+				engine->num_counters = e->num_counters;
+				engine->busy = e->busy;
+				engine->sema = e->sema;
+				engine->wait = e->wait;
+			}
+		}
+	}
+
+	return classes;
+}
+
+static struct engines *
+update_classes(struct engines *classes, struct engines *engines)
+{
+	unsigned int i, j;
+
+	if (!classes)
+		classes = init_classes(engines);
+
+	for (i = 0; i < classes->num_engines; i++) {
+		unsigned int num_engines = classes->class[i].num_engines;
+		struct engine *engine = engine_ptr(classes, i);
+
+		if (!num_engines)
+			continue;
+
+		memset(&engine->busy.val, 0, sizeof(engine->busy.val));
+		memset(&engine->sema.val, 0, sizeof(engine->sema.val));
+		memset(&engine->wait.val, 0, sizeof(engine->wait.val));
+
+		for (j = 0; j < engines->num_engines; j++) {
+			struct engine *e = engine_ptr(engines, j);
+
+			if (e->class == i) {
+				__pmu_sum(&engine->busy.val, &e->busy.val);
+				__pmu_sum(&engine->sema.val, &e->sema.val);
+				__pmu_sum(&engine->wait.val, &e->wait.val);
+			}
+		}
+
+		__pmu_normalize(&engine->busy.val, num_engines);
+		__pmu_normalize(&engine->sema.val, num_engines);
+		__pmu_normalize(&engine->wait.val, num_engines);
+	}
+
+	return classes;
+}
+
+static int
+print_engines(struct engines *engines, double t, int lines, int w, int h)
+{
+	static struct engines *classes;
+	struct engines *show;
+
+	if (class_view)
+		classes = show = update_classes(classes, engines);
+	else
+		show = engines;
+
+	lines = print_engines_header(show, t, lines, w,  h);
+
+	for (unsigned int i = 0; i < show->num_engines && lines < h; i++)
+		lines = print_engine(show, i, t, lines, w, h);
+
+	lines = print_engines_footer(show, t, lines, w, h);
+
+	return lines;
+}
+
 static bool stop_top;
 
 static void sigint_handler(int  sig)
@@ -1292,6 +1465,9 @@ static void process_stdin(unsigned int timeout_us)
 		case 'q':
 			stop_top = true;
 			break;
+		case '1':
+			class_view ^= true;
+			break;
 		};
 	}
 }
@@ -1302,7 +1478,6 @@ int main(int argc, char **argv)
 	int con_w = -1, con_h = -1;
 	char *output_path = NULL;
 	struct engines *engines;
-	unsigned int i;
 	int ret = 0, ch;
 	bool list_device = false;
 	char *pmu_device, *opt_device = NULL;
@@ -1366,6 +1541,7 @@ int main(int argc, char **argv)
 	case INTERACTIVE:
 		pops = &term_pops;
 		interactive_stdin();
+		class_view = true;
 		break;
 	case STDOUT:
 		pops = &stdout_pops;
@@ -1462,17 +1638,7 @@ int main(int argc, char **argv)
 
 			lines = print_imc(engines, t, lines, con_w, con_h);
 
-			lines = print_engines_header(engines, t, lines, con_w,
-						     con_h);
-
-			for (i = 0;
-			     i < engines->num_engines && lines < con_h;
-			     i++)
-				lines = print_engine(engines, i, t, lines,
-						     con_w, con_h);
-
-			lines = print_engines_footer(engines, t, lines, con_w,
-						     con_h);
+			lines = print_engines(engines, t, lines, con_w, con_h);
 		}
 
 		if (stop_top)
-- 
2.25.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

  reply	other threads:[~2020-12-16 15:28 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-16 15:28 [igt-dev] [PATCH i-g-t 1/2] intel_gpu_top: Support exiting the tool by pressing 'q' Tvrtko Ursulin
2020-12-16 15:28 ` Tvrtko Ursulin [this message]
2020-12-16 15:51   ` [Intel-gfx] [igt-dev] [PATCH i-g-t 2/2] intel_gpu_top: Aggregate engine busyness per class Chris Wilson
2020-12-16 15:52     ` Chris Wilson
2020-12-16 16:01     ` Tvrtko Ursulin
2020-12-16 16:05       ` Chris Wilson
2020-12-16 16:42         ` [igt-dev] [PATCH v2 " Tvrtko Ursulin
2020-12-16 15:44 ` [igt-dev] [PATCH i-g-t 1/2] intel_gpu_top: Support exiting the tool by pressing 'q' Chris Wilson
2020-12-16 15:54   ` [igt-dev] [PATCH v2 " Tvrtko Ursulin
2020-12-16 15:57     ` [Intel-gfx] " Chris Wilson
2020-12-17  8:31       ` Chris Wilson
2020-12-16 18:04 ` [igt-dev] ✓ Fi.CI.BAT: success for series starting with [v2,i-g-t,1/2] intel_gpu_top: Support exiting the tool by pressing 'q' (rev3) Patchwork
2020-12-16 21:08 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201216152809.706094-2-tvrtko.ursulin@linux.intel.com \
    --to=tvrtko.ursulin@linux.intel.com \
    --cc=Intel-gfx@lists.freedesktop.org \
    --cc=igt-dev@lists.freedesktop.org \
    --cc=tvrtko.ursulin@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox