[Intel-gfx] [PATCH i-g-t 8/8] gputop: Basic vendor agnostic GPU top tool

2023-04-17 Thread Tvrtko Ursulin
From: Tvrtko Ursulin 

Rudimentary vendor agnostic example of how lib_igt_drm_clients can be used
to display a sorted by card and usage list of processes using GPUs.

Borrows a bit of code from intel_gpu_top but for now omits the fancy
features like interactive functionality, card selection, client
aggregation, sort modes, JSON output  and pretty engine names. Also no
support for global GPU or system metrics.

On the other hand it shows clients from all DRM cards which
intel_gpu_top does not do.

Signed-off-by: Tvrtko Ursulin 
Cc: Rob Clark 
Cc: Christian König 
Acked-by: Christian König 
Reviewed-by: Rob Clark 
---
 tools/gputop.c| 266 ++
 tools/meson.build |   5 +
 2 files changed, 271 insertions(+)
 create mode 100644 tools/gputop.c

diff --git a/tools/gputop.c b/tools/gputop.c
new file mode 100644
index ..4fb5ce63e07c
--- /dev/null
+++ b/tools/gputop.c
@@ -0,0 +1,266 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "igt_drm_clients.h"
+#include "igt_drm_fdinfo.h"
+
+static const char *bars[] = { " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█" };
+
+static void n_spaces(const unsigned int n)
+{
+   unsigned int i;
+
+   for (i = 0; i < n; i++)
+   putchar(' ');
+}
+
+static void print_percentage_bar(double percent, int max_len)
+{
+   int bar_len, i, len = max_len - 2;
+   const int w = 8;
+
+   assert(max_len > 0);
+
+   bar_len = ceil(w * percent * len / 100.0);
+   if (bar_len > w * len)
+   bar_len = w * len;
+
+   putchar('|');
+
+   for (i = bar_len; i >= w; i -= w)
+   printf("%s", bars[w]);
+   if (i)
+   printf("%s", bars[i]);
+
+   len -= (bar_len + (w - 1)) / w;
+   n_spaces(len);
+
+   putchar('|');
+}
+
+static int
+print_client_header(struct igt_drm_client *c, int lines, int con_w, int con_h,
+   int *engine_w)
+{
+   int ret, len;
+
+   if (lines++ >= con_h)
+   return lines;
+
+   printf("\033[7m");
+   ret = printf("DRM minor %u", c->drm_minor);
+   n_spaces(con_w - ret);
+
+   if (lines++ >= con_h)
+   return lines;
+
+   putchar('\n');
+   len = printf("%*s %*s ",
+c->clients->max_pid_len, "PID",
+c->clients->max_name_len, "NAME");
+
+   if (c->engines->num_engines) {
+   unsigned int i;
+   int width;
+
+   *engine_w = width = (con_w - len) / c->engines->num_engines;
+
+   for (i = 0; i <= c->engines->max_engine_id; i++) {
+   const char *name = c->engines->names[i];
+   int name_len = strlen(name);
+   int pad = (width - name_len) / 2;
+   int spaces = width - pad - name_len;
+
+   if (!name)
+   continue;
+
+   if (pad < 0 || spaces < 0)
+   continue;
+
+   n_spaces(pad);
+   printf("%s", name);
+   n_spaces(spaces);
+   len += pad + name_len + spaces;
+   }
+   }
+
+   n_spaces(con_w - len);
+   printf("\033[0m\n");
+
+   return lines;
+}
+
+
+static bool
+newheader(const struct igt_drm_client *c, const struct igt_drm_client *pc)
+{
+   return !pc || c->drm_minor != pc->drm_minor;
+}
+
+static int
+print_client(struct igt_drm_client *c, struct igt_drm_client **prevc,
+double t, int lines, int con_w, int con_h,
+unsigned int period_us, int *engine_w)
+{
+   unsigned int i;
+
+   /* Filter out idle clients. */
+   if (!c->total_runtime || c->samples < 2)
+   return lines;
+
+   /* Print header when moving to a different DRM card. */
+   if (newheader(c, *prevc)) {
+   lines = print_client_header(c, lines, con_w, con_h, engine_w);
+   if (lines >= con_h)
+   return lines;
+   }
+
+   *prevc = c;
+
+   printf("%*s %*s ",
+  c->clients->max_pid_len, c->pid_str,
+  c->clients->max_name_len, c->print_name);
+   lines++;
+
+   for (i = 0; c->samples > 1 && i <= c->engines->max_engine_id; i++) {
+   double pct;
+
+   if (!c->engines->capacity[i])
+   continue;
+
+   pct = (double)c->val[i] / period_us / 1e3 * 100 /
+ c->engines->capacity[i];
+
+   /*
+* Guard against fluctuations between our scanning period and
+* GPU times as exported by the 

[Intel-gfx] [PATCH i-g-t 8/8] gputop: Basic vendor agnostic GPU top tool

2023-04-06 Thread Tvrtko Ursulin
From: Tvrtko Ursulin 

Rudimentary vendor agnostic example of how lib_igt_drm_clients can be used
to display a sorted by card and usage list of processes using GPUs.

Borrows a bit of code from intel_gpu_top but for now omits the fancy
features like interactive functionality, card selection, client
aggregation, sort modes, JSON output  and pretty engine names. Also no
support for global GPU or system metrics.

On the other hand it shows clients from all DRM cards which
intel_gpu_top does not do.

Signed-off-by: Tvrtko Ursulin 
Cc: Rob Clark 
Cc: Christian König 
Acked-by: Christian König 
Reviewed-by: Rob Clark 
---
 tools/gputop.c| 260 ++
 tools/meson.build |   5 +
 2 files changed, 265 insertions(+)
 create mode 100644 tools/gputop.c

diff --git a/tools/gputop.c b/tools/gputop.c
new file mode 100644
index ..d259cac1ab17
--- /dev/null
+++ b/tools/gputop.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "igt_drm_clients.h"
+#include "igt_drm_fdinfo.h"
+
+static const char *bars[] = { " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█" };
+
+static void n_spaces(const unsigned int n)
+{
+   unsigned int i;
+
+   for (i = 0; i < n; i++)
+   putchar(' ');
+}
+
+static void print_percentage_bar(double percent, int max_len)
+{
+   int bar_len, i, len = max_len - 2;
+   const int w = 8;
+
+   assert(max_len > 0);
+
+   bar_len = ceil(w * percent * len / 100.0);
+   if (bar_len > w * len)
+   bar_len = w * len;
+
+   putchar('|');
+
+   for (i = bar_len; i >= w; i -= w)
+   printf("%s", bars[w]);
+   if (i)
+   printf("%s", bars[i]);
+
+   len -= (bar_len + (w - 1)) / w;
+   n_spaces(len);
+
+   putchar('|');
+}
+
+static int
+print_client_header(struct igt_drm_client *c, int lines, int con_w, int con_h,
+   int *engine_w)
+{
+   const char *pidname = "PID   NAME ";
+   int ret, len = strlen(pidname);
+
+   if (lines++ >= con_h || len >= con_w)
+   return lines;
+   printf("\033[7m");
+   ret = printf("DRM minor %u", c->drm_minor);
+   n_spaces(con_w - ret);
+
+   if (lines++ >= con_h)
+   return lines;
+   printf("\n%s", pidname);
+
+   if (c->engines->num_engines) {
+   unsigned int i;
+   int width;
+
+   *engine_w = width = (con_w - len) / c->engines->num_engines;
+
+   for (i = 0; i <= c->engines->max_engine_id; i++) {
+   const char *name = c->engines->names[i];
+   int name_len = strlen(name);
+   int pad = (width - name_len) / 2;
+   int spaces = width - pad - name_len;
+
+   if (!name)
+   continue;
+
+   if (pad < 0 || spaces < 0)
+   continue;
+
+   n_spaces(pad);
+   printf("%s", name);
+   n_spaces(spaces);
+   len += pad + name_len + spaces;
+   }
+   }
+
+   n_spaces(con_w - len);
+   printf("\033[0m\n");
+
+   return lines;
+}
+
+
+static bool
+newheader(const struct igt_drm_client *c, const struct igt_drm_client *pc)
+{
+   return !pc || c->drm_minor != pc->drm_minor;
+}
+
+static int
+print_client(struct igt_drm_client *c, struct igt_drm_client **prevc,
+double t, int lines, int con_w, int con_h,
+unsigned int period_us, int *engine_w)
+{
+   unsigned int i;
+
+   /* Filter out idle clients. */
+   if (!c->total_runtime || c->samples < 2)
+   return lines;
+
+   /* Print header when moving to a different DRM card. */
+   if (newheader(c, *prevc)) {
+   lines = print_client_header(c, lines, con_w, con_h, engine_w);
+   if (lines >= con_h)
+   return lines;
+   }
+
+   *prevc = c;
+
+   printf("%8u %17s ", c->pid, c->print_name);
+   lines++;
+
+   for (i = 0; c->samples > 1 && i <= c->engines->max_engine_id; i++) {
+   double pct;
+
+   if (!c->engines->capacity[i])
+   continue;
+
+   pct = (double)c->val[i] / period_us / 1e3 * 100 /
+ c->engines->capacity[i];
+
+   /*
+* Guard against fluctuations between our scanning period and
+* GPU times as exported by the kernel in fdinfo.
+*/
+   if (pct > 100.0)
+   pct = 100.0;
+
+   

Re: [Intel-gfx] [PATCH i-g-t 8/8] gputop: Basic vendor agnostic GPU top tool

2023-04-06 Thread Tvrtko Ursulin



On 05/04/2023 18:57, Rob Clark wrote:

On Tue, Jan 31, 2023 at 3:33 AM Tvrtko Ursulin
 wrote:


From: Tvrtko Ursulin 

Rudimentary vendor agnostic example of how lib_igt_drm_clients can be used
to display a sorted by card and usage list of processes using GPUs.

Borrows a bit of code from intel_gpu_top but for now omits the fancy
features like interactive functionality, card selection, client
aggregation, sort modes, JSON output  and pretty engine names. Also no
support for global GPU or system metrics.

On the other hand it shows clients from all DRM cards which
intel_gpu_top does not do.

Signed-off-by: Tvrtko Ursulin 
Cc: Rob Clark 
Cc: Christian König 
Acked-by: Christian König 


Reviewed-by: Rob Clark 


Presumably for 8/8 only?

The rest of the series does not apply any more by now. I need to rebase..

Regards,

Tvrtko




---
  tools/gputop.c| 260 ++
  tools/meson.build |   5 +
  2 files changed, 265 insertions(+)
  create mode 100644 tools/gputop.c

diff --git a/tools/gputop.c b/tools/gputop.c
new file mode 100644
index ..d259cac1ab17
--- /dev/null
+++ b/tools/gputop.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "igt_drm_clients.h"
+#include "igt_drm_fdinfo.h"
+
+static const char *bars[] = { " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█" };
+
+static void n_spaces(const unsigned int n)
+{
+   unsigned int i;
+
+   for (i = 0; i < n; i++)
+   putchar(' ');
+}
+
+static void print_percentage_bar(double percent, int max_len)
+{
+   int bar_len, i, len = max_len - 2;
+   const int w = 8;
+
+   assert(max_len > 0);
+
+   bar_len = ceil(w * percent * len / 100.0);
+   if (bar_len > w * len)
+   bar_len = w * len;
+
+   putchar('|');
+
+   for (i = bar_len; i >= w; i -= w)
+   printf("%s", bars[w]);
+   if (i)
+   printf("%s", bars[i]);
+
+   len -= (bar_len + (w - 1)) / w;
+   n_spaces(len);
+
+   putchar('|');
+}
+
+static int
+print_client_header(struct igt_drm_client *c, int lines, int con_w, int con_h,
+   int *engine_w)
+{
+   const char *pidname = "PID   NAME ";
+   int ret, len = strlen(pidname);
+
+   if (lines++ >= con_h || len >= con_w)
+   return lines;
+   printf("\033[7m");
+   ret = printf("DRM minor %u", c->drm_minor);
+   n_spaces(con_w - ret);
+
+   if (lines++ >= con_h)
+   return lines;
+   printf("\n%s", pidname);
+
+   if (c->engines->num_engines) {
+   unsigned int i;
+   int width;
+
+   *engine_w = width = (con_w - len) / c->engines->num_engines;
+
+   for (i = 0; i <= c->engines->max_engine_id; i++) {
+   const char *name = c->engines->names[i];
+   int name_len = strlen(name);
+   int pad = (width - name_len) / 2;
+   int spaces = width - pad - name_len;
+
+   if (!name)
+   continue;
+
+   if (pad < 0 || spaces < 0)
+   continue;
+
+   n_spaces(pad);
+   printf("%s", name);
+   n_spaces(spaces);
+   len += pad + name_len + spaces;
+   }
+   }
+
+   n_spaces(con_w - len);
+   printf("\033[0m\n");
+
+   return lines;
+}
+
+
+static bool
+newheader(const struct igt_drm_client *c, const struct igt_drm_client *pc)
+{
+   return !pc || c->drm_minor != pc->drm_minor;
+}
+
+static int
+print_client(struct igt_drm_client *c, struct igt_drm_client **prevc,
+double t, int lines, int con_w, int con_h,
+unsigned int period_us, int *engine_w)
+{
+   unsigned int i;
+
+   /* Filter out idle clients. */
+   if (!c->total_runtime || c->samples < 2)
+   return lines;
+
+   /* Print header when moving to a different DRM card. */
+   if (newheader(c, *prevc)) {
+   lines = print_client_header(c, lines, con_w, con_h, engine_w);
+   if (lines >= con_h)
+   return lines;
+   }
+
+   *prevc = c;
+
+   printf("%8u %17s ", c->pid, c->print_name);
+   lines++;
+
+   for (i = 0; c->samples > 1 && i <= c->engines->max_engine_id; i++) {
+   double pct;
+
+   if (!c->engines->capacity[i])
+   continue;
+
+   pct = (double)c->val[i] / period_us / 1e3 * 100 /
+ c->engines->capacity[i];
+
+   /*
+* Guard 

Re: [Intel-gfx] [PATCH i-g-t 8/8] gputop: Basic vendor agnostic GPU top tool

2023-04-05 Thread Rob Clark
On Tue, Jan 31, 2023 at 3:33 AM Tvrtko Ursulin
 wrote:
>
> From: Tvrtko Ursulin 
>
> Rudimentary vendor agnostic example of how lib_igt_drm_clients can be used
> to display a sorted by card and usage list of processes using GPUs.
>
> Borrows a bit of code from intel_gpu_top but for now omits the fancy
> features like interactive functionality, card selection, client
> aggregation, sort modes, JSON output  and pretty engine names. Also no
> support for global GPU or system metrics.
>
> On the other hand it shows clients from all DRM cards which
> intel_gpu_top does not do.
>
> Signed-off-by: Tvrtko Ursulin 
> Cc: Rob Clark 
> Cc: Christian König 
> Acked-by: Christian König 

Reviewed-by: Rob Clark 

> ---
>  tools/gputop.c| 260 ++
>  tools/meson.build |   5 +
>  2 files changed, 265 insertions(+)
>  create mode 100644 tools/gputop.c
>
> diff --git a/tools/gputop.c b/tools/gputop.c
> new file mode 100644
> index ..d259cac1ab17
> --- /dev/null
> +++ b/tools/gputop.c
> @@ -0,0 +1,260 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2022 Intel Corporation
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#include "igt_drm_clients.h"
> +#include "igt_drm_fdinfo.h"
> +
> +static const char *bars[] = { " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█" };
> +
> +static void n_spaces(const unsigned int n)
> +{
> +   unsigned int i;
> +
> +   for (i = 0; i < n; i++)
> +   putchar(' ');
> +}
> +
> +static void print_percentage_bar(double percent, int max_len)
> +{
> +   int bar_len, i, len = max_len - 2;
> +   const int w = 8;
> +
> +   assert(max_len > 0);
> +
> +   bar_len = ceil(w * percent * len / 100.0);
> +   if (bar_len > w * len)
> +   bar_len = w * len;
> +
> +   putchar('|');
> +
> +   for (i = bar_len; i >= w; i -= w)
> +   printf("%s", bars[w]);
> +   if (i)
> +   printf("%s", bars[i]);
> +
> +   len -= (bar_len + (w - 1)) / w;
> +   n_spaces(len);
> +
> +   putchar('|');
> +}
> +
> +static int
> +print_client_header(struct igt_drm_client *c, int lines, int con_w, int 
> con_h,
> +   int *engine_w)
> +{
> +   const char *pidname = "PID   NAME ";
> +   int ret, len = strlen(pidname);
> +
> +   if (lines++ >= con_h || len >= con_w)
> +   return lines;
> +   printf("\033[7m");
> +   ret = printf("DRM minor %u", c->drm_minor);
> +   n_spaces(con_w - ret);
> +
> +   if (lines++ >= con_h)
> +   return lines;
> +   printf("\n%s", pidname);
> +
> +   if (c->engines->num_engines) {
> +   unsigned int i;
> +   int width;
> +
> +   *engine_w = width = (con_w - len) / c->engines->num_engines;
> +
> +   for (i = 0; i <= c->engines->max_engine_id; i++) {
> +   const char *name = c->engines->names[i];
> +   int name_len = strlen(name);
> +   int pad = (width - name_len) / 2;
> +   int spaces = width - pad - name_len;
> +
> +   if (!name)
> +   continue;
> +
> +   if (pad < 0 || spaces < 0)
> +   continue;
> +
> +   n_spaces(pad);
> +   printf("%s", name);
> +   n_spaces(spaces);
> +   len += pad + name_len + spaces;
> +   }
> +   }
> +
> +   n_spaces(con_w - len);
> +   printf("\033[0m\n");
> +
> +   return lines;
> +}
> +
> +
> +static bool
> +newheader(const struct igt_drm_client *c, const struct igt_drm_client *pc)
> +{
> +   return !pc || c->drm_minor != pc->drm_minor;
> +}
> +
> +static int
> +print_client(struct igt_drm_client *c, struct igt_drm_client **prevc,
> +double t, int lines, int con_w, int con_h,
> +unsigned int period_us, int *engine_w)
> +{
> +   unsigned int i;
> +
> +   /* Filter out idle clients. */
> +   if (!c->total_runtime || c->samples < 2)
> +   return lines;
> +
> +   /* Print header when moving to a different DRM card. */
> +   if (newheader(c, *prevc)) {
> +   lines = print_client_header(c, lines, con_w, con_h, engine_w);
> +   if (lines >= con_h)
> +   return lines;
> +   }
> +
> +   *prevc = c;
> +
> +   printf("%8u %17s ", c->pid, c->print_name);
> +   lines++;
> +
> +   for (i = 0; c->samples > 1 && i <= c->engines->max_engine_id; i++) {
> +   double pct;
> +
> +   if (!c->engines->capacity[i])
> +   

[Intel-gfx] [PATCH i-g-t 8/8] gputop: Basic vendor agnostic GPU top tool

2023-01-31 Thread Tvrtko Ursulin
From: Tvrtko Ursulin 

Rudimentary vendor agnostic example of how lib_igt_drm_clients can be used
to display a sorted by card and usage list of processes using GPUs.

Borrows a bit of code from intel_gpu_top but for now omits the fancy
features like interactive functionality, card selection, client
aggregation, sort modes, JSON output  and pretty engine names. Also no
support for global GPU or system metrics.

On the other hand it shows clients from all DRM cards which
intel_gpu_top does not do.

Signed-off-by: Tvrtko Ursulin 
Cc: Rob Clark 
Cc: Christian König 
Acked-by: Christian König 
---
 tools/gputop.c| 260 ++
 tools/meson.build |   5 +
 2 files changed, 265 insertions(+)
 create mode 100644 tools/gputop.c

diff --git a/tools/gputop.c b/tools/gputop.c
new file mode 100644
index ..d259cac1ab17
--- /dev/null
+++ b/tools/gputop.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "igt_drm_clients.h"
+#include "igt_drm_fdinfo.h"
+
+static const char *bars[] = { " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█" };
+
+static void n_spaces(const unsigned int n)
+{
+   unsigned int i;
+
+   for (i = 0; i < n; i++)
+   putchar(' ');
+}
+
+static void print_percentage_bar(double percent, int max_len)
+{
+   int bar_len, i, len = max_len - 2;
+   const int w = 8;
+
+   assert(max_len > 0);
+
+   bar_len = ceil(w * percent * len / 100.0);
+   if (bar_len > w * len)
+   bar_len = w * len;
+
+   putchar('|');
+
+   for (i = bar_len; i >= w; i -= w)
+   printf("%s", bars[w]);
+   if (i)
+   printf("%s", bars[i]);
+
+   len -= (bar_len + (w - 1)) / w;
+   n_spaces(len);
+
+   putchar('|');
+}
+
+static int
+print_client_header(struct igt_drm_client *c, int lines, int con_w, int con_h,
+   int *engine_w)
+{
+   const char *pidname = "PID   NAME ";
+   int ret, len = strlen(pidname);
+
+   if (lines++ >= con_h || len >= con_w)
+   return lines;
+   printf("\033[7m");
+   ret = printf("DRM minor %u", c->drm_minor);
+   n_spaces(con_w - ret);
+
+   if (lines++ >= con_h)
+   return lines;
+   printf("\n%s", pidname);
+
+   if (c->engines->num_engines) {
+   unsigned int i;
+   int width;
+
+   *engine_w = width = (con_w - len) / c->engines->num_engines;
+
+   for (i = 0; i <= c->engines->max_engine_id; i++) {
+   const char *name = c->engines->names[i];
+   int name_len = strlen(name);
+   int pad = (width - name_len) / 2;
+   int spaces = width - pad - name_len;
+
+   if (!name)
+   continue;
+
+   if (pad < 0 || spaces < 0)
+   continue;
+
+   n_spaces(pad);
+   printf("%s", name);
+   n_spaces(spaces);
+   len += pad + name_len + spaces;
+   }
+   }
+
+   n_spaces(con_w - len);
+   printf("\033[0m\n");
+
+   return lines;
+}
+
+
+static bool
+newheader(const struct igt_drm_client *c, const struct igt_drm_client *pc)
+{
+   return !pc || c->drm_minor != pc->drm_minor;
+}
+
+static int
+print_client(struct igt_drm_client *c, struct igt_drm_client **prevc,
+double t, int lines, int con_w, int con_h,
+unsigned int period_us, int *engine_w)
+{
+   unsigned int i;
+
+   /* Filter out idle clients. */
+   if (!c->total_runtime || c->samples < 2)
+   return lines;
+
+   /* Print header when moving to a different DRM card. */
+   if (newheader(c, *prevc)) {
+   lines = print_client_header(c, lines, con_w, con_h, engine_w);
+   if (lines >= con_h)
+   return lines;
+   }
+
+   *prevc = c;
+
+   printf("%8u %17s ", c->pid, c->print_name);
+   lines++;
+
+   for (i = 0; c->samples > 1 && i <= c->engines->max_engine_id; i++) {
+   double pct;
+
+   if (!c->engines->capacity[i])
+   continue;
+
+   pct = (double)c->val[i] / period_us / 1e3 * 100 /
+ c->engines->capacity[i];
+
+   /*
+* Guard against fluctuations between our scanning period and
+* GPU times as exported by the kernel in fdinfo.
+*/
+   if (pct > 100.0)
+   pct = 100.0;
+
+   print_percentage_bar(pct, 

Re: [Intel-gfx] [PATCH i-g-t 8/8] gputop: Basic vendor agnostic GPU top tool

2022-11-16 Thread Philipp Zabel
On Fr, 2022-11-11 at 15:58 +, Tvrtko Ursulin wrote:
> From: Tvrtko Ursulin 
> 
> Rudimentary vendor agnostic example of how lib_igt_drm_clients can be used
> to display a sorted by card and usage list of processes using GPUs.
> 
> Borrows a bit of code from intel_gpu_top but for now omits the fancy
> features like interactive functionality, card selection, client
> aggregation, sort modes, JSON output  and pretty engine names. Also no
> support for global GPU or system metrics.
> 
> On the other hand it shows clients from all DRM cards which
> intel_gpu_top does not do.
> 
> Signed-off-by: Tvrtko Ursulin 
> Cc: Rob Clark 
> Cc: Christian König 
> Acked-by: Christian König 

Tested-by: Philipp Zabel 

on etnaviv with [1].

[1] 
https://lore.kernel.org/dri-devel/20220916151205.165687-3-l.st...@pengutronix.de/

regards
Philipp


[Intel-gfx] [PATCH i-g-t 8/8] gputop: Basic vendor agnostic GPU top tool

2022-11-11 Thread Tvrtko Ursulin
From: Tvrtko Ursulin 

Rudimentary vendor agnostic example of how lib_igt_drm_clients can be used
to display a sorted by card and usage list of processes using GPUs.

Borrows a bit of code from intel_gpu_top but for now omits the fancy
features like interactive functionality, card selection, client
aggregation, sort modes, JSON output  and pretty engine names. Also no
support for global GPU or system metrics.

On the other hand it shows clients from all DRM cards which
intel_gpu_top does not do.

Signed-off-by: Tvrtko Ursulin 
Cc: Rob Clark 
Cc: Christian König 
Acked-by: Christian König 
---
 tools/gputop.c| 260 ++
 tools/meson.build |   5 +
 2 files changed, 265 insertions(+)
 create mode 100644 tools/gputop.c

diff --git a/tools/gputop.c b/tools/gputop.c
new file mode 100644
index ..d259cac1ab17
--- /dev/null
+++ b/tools/gputop.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "igt_drm_clients.h"
+#include "igt_drm_fdinfo.h"
+
+static const char *bars[] = { " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█" };
+
+static void n_spaces(const unsigned int n)
+{
+   unsigned int i;
+
+   for (i = 0; i < n; i++)
+   putchar(' ');
+}
+
+static void print_percentage_bar(double percent, int max_len)
+{
+   int bar_len, i, len = max_len - 2;
+   const int w = 8;
+
+   assert(max_len > 0);
+
+   bar_len = ceil(w * percent * len / 100.0);
+   if (bar_len > w * len)
+   bar_len = w * len;
+
+   putchar('|');
+
+   for (i = bar_len; i >= w; i -= w)
+   printf("%s", bars[w]);
+   if (i)
+   printf("%s", bars[i]);
+
+   len -= (bar_len + (w - 1)) / w;
+   n_spaces(len);
+
+   putchar('|');
+}
+
+static int
+print_client_header(struct igt_drm_client *c, int lines, int con_w, int con_h,
+   int *engine_w)
+{
+   const char *pidname = "PID   NAME ";
+   int ret, len = strlen(pidname);
+
+   if (lines++ >= con_h || len >= con_w)
+   return lines;
+   printf("\033[7m");
+   ret = printf("DRM minor %u", c->drm_minor);
+   n_spaces(con_w - ret);
+
+   if (lines++ >= con_h)
+   return lines;
+   printf("\n%s", pidname);
+
+   if (c->engines->num_engines) {
+   unsigned int i;
+   int width;
+
+   *engine_w = width = (con_w - len) / c->engines->num_engines;
+
+   for (i = 0; i <= c->engines->max_engine_id; i++) {
+   const char *name = c->engines->names[i];
+   int name_len = strlen(name);
+   int pad = (width - name_len) / 2;
+   int spaces = width - pad - name_len;
+
+   if (!name)
+   continue;
+
+   if (pad < 0 || spaces < 0)
+   continue;
+
+   n_spaces(pad);
+   printf("%s", name);
+   n_spaces(spaces);
+   len += pad + name_len + spaces;
+   }
+   }
+
+   n_spaces(con_w - len);
+   printf("\033[0m\n");
+
+   return lines;
+}
+
+
+static bool
+newheader(const struct igt_drm_client *c, const struct igt_drm_client *pc)
+{
+   return !pc || c->drm_minor != pc->drm_minor;
+}
+
+static int
+print_client(struct igt_drm_client *c, struct igt_drm_client **prevc,
+double t, int lines, int con_w, int con_h,
+unsigned int period_us, int *engine_w)
+{
+   unsigned int i;
+
+   /* Filter out idle clients. */
+   if (!c->total_runtime || c->samples < 2)
+   return lines;
+
+   /* Print header when moving to a different DRM card. */
+   if (newheader(c, *prevc)) {
+   lines = print_client_header(c, lines, con_w, con_h, engine_w);
+   if (lines >= con_h)
+   return lines;
+   }
+
+   *prevc = c;
+
+   printf("%8u %17s ", c->pid, c->print_name);
+   lines++;
+
+   for (i = 0; c->samples > 1 && i <= c->engines->max_engine_id; i++) {
+   double pct;
+
+   if (!c->engines->capacity[i])
+   continue;
+
+   pct = (double)c->val[i] / period_us / 1e3 * 100 /
+ c->engines->capacity[i];
+
+   /*
+* Guard against fluctuations between our scanning period and
+* GPU times as exported by the kernel in fdinfo.
+*/
+   if (pct > 100.0)
+   pct = 100.0;
+
+   print_percentage_bar(pct, 

Re: [Intel-gfx] [PATCH i-g-t 8/8] gputop: Basic vendor agnostic GPU top tool

2022-06-17 Thread Christian König

Am 17.06.22 um 12:09 schrieb Tvrtko Ursulin:


On 17/06/2022 08:20, Christian König wrote:

Am 16.06.22 um 16:06 schrieb Tvrtko Ursulin:

From: Tvrtko Ursulin 

Rudimentary vendor agnostic example of how lib_igt_drm_clients can 
be used

to display a sorted by card and usage list of processes using GPUs.

Borrows a bit of code from intel_gpu_top but for now omits the fancy
features like interactive functionality, card selection, client
aggregation, sort modes, JSON output  and pretty engine names. Also no
support for global GPU or system metrics.

On the other hand it shows clients from all DRM cards which
intel_gpu_top does not do.

Signed-off-by: Tvrtko Ursulin 
Cc: Rob Clark 
Cc: Christian König 


LGTM, Acked-by: Christian König 


Thanks Christian,

It is a very rudimentary tool, more a reference really. I keep hoping 
some UI/desktop folks actually pick up the idea and implement 
something nicer elsewhere. Or maybe it ends up me spending a little 
bit more time on it, to carry over some more functionality from 
intel_gpu_top.


I see amdgpu patches are in - presumably that means gputop parses it 
and understands fine?


At least the last time I tested it the tool worked like a charm.

And yes, it's indeed rather useful.

Regards,
Christian.



Regards,

Tvrtko


---
  tools/gputop.c    | 260 
++

  tools/meson.build |   5 +
  2 files changed, 265 insertions(+)
  create mode 100644 tools/gputop.c

diff --git a/tools/gputop.c b/tools/gputop.c
new file mode 100644
index ..d259cac1ab17
--- /dev/null
+++ b/tools/gputop.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "igt_drm_clients.h"
+#include "igt_drm_fdinfo.h"
+
+static const char *bars[] = { " ", "▏", "▎", "▍", "▌", "▋", "▊", 
"▉", "█" };

+
+static void n_spaces(const unsigned int n)
+{
+    unsigned int i;
+
+    for (i = 0; i < n; i++)
+    putchar(' ');
+}
+
+static void print_percentage_bar(double percent, int max_len)
+{
+    int bar_len, i, len = max_len - 2;
+    const int w = 8;
+
+    assert(max_len > 0);
+
+    bar_len = ceil(w * percent * len / 100.0);
+    if (bar_len > w * len)
+    bar_len = w * len;
+
+    putchar('|');
+
+    for (i = bar_len; i >= w; i -= w)
+    printf("%s", bars[w]);
+    if (i)
+    printf("%s", bars[i]);
+
+    len -= (bar_len + (w - 1)) / w;
+    n_spaces(len);
+
+    putchar('|');
+}
+
+static int
+print_client_header(struct igt_drm_client *c, int lines, int con_w, 
int con_h,

+    int *engine_w)
+{
+    const char *pidname = "    PID   NAME ";
+    int ret, len = strlen(pidname);
+
+    if (lines++ >= con_h || len >= con_w)
+    return lines;
+    printf("\033[7m");
+    ret = printf("DRM minor %u", c->drm_minor);
+    n_spaces(con_w - ret);
+
+    if (lines++ >= con_h)
+    return lines;
+    printf("\n%s", pidname);
+
+    if (c->engines->num_engines) {
+    unsigned int i;
+    int width;
+
+    *engine_w = width = (con_w - len) / c->engines->num_engines;
+
+    for (i = 0; i <= c->engines->max_engine_id; i++) {
+    const char *name = c->engines->names[i];
+    int name_len = strlen(name);
+    int pad = (width - name_len) / 2;
+    int spaces = width - pad - name_len;
+
+    if (!name)
+    continue;
+
+    if (pad < 0 || spaces < 0)
+    continue;
+
+    n_spaces(pad);
+    printf("%s", name);
+    n_spaces(spaces);
+    len += pad + name_len + spaces;
+    }
+    }
+
+    n_spaces(con_w - len);
+    printf("\033[0m\n");
+
+    return lines;
+}
+
+
+static bool
+newheader(const struct igt_drm_client *c, const struct 
igt_drm_client *pc)

+{
+    return !pc || c->drm_minor != pc->drm_minor;
+}
+
+static int
+print_client(struct igt_drm_client *c, struct igt_drm_client **prevc,
+ double t, int lines, int con_w, int con_h,
+ unsigned int period_us, int *engine_w)
+{
+    unsigned int i;
+
+    /* Filter out idle clients. */
+    if (!c->total_runtime || c->samples < 2)
+    return lines;
+
+    /* Print header when moving to a different DRM card. */
+    if (newheader(c, *prevc)) {
+    lines = print_client_header(c, lines, con_w, con_h, engine_w);
+    if (lines >= con_h)
+    return lines;
+    }
+
+    *prevc = c;
+
+    printf("%8u %17s ", c->pid, c->print_name);
+    lines++;
+
+    for (i = 0; c->samples > 1 && i <= c->engines->max_engine_id; 
i++) {

+    double pct;
+
+    if (!c->engines->capacity[i])
+    continue;
+
+    pct = (double)c->val[i] / period_us / 1e3 * 100 /
+  c->engines->capacity[i];
+
+   

Re: [Intel-gfx] [PATCH i-g-t 8/8] gputop: Basic vendor agnostic GPU top tool

2022-06-17 Thread Tvrtko Ursulin



On 17/06/2022 08:20, Christian König wrote:

Am 16.06.22 um 16:06 schrieb Tvrtko Ursulin:

From: Tvrtko Ursulin 

Rudimentary vendor agnostic example of how lib_igt_drm_clients can be 
used

to display a sorted by card and usage list of processes using GPUs.

Borrows a bit of code from intel_gpu_top but for now omits the fancy
features like interactive functionality, card selection, client
aggregation, sort modes, JSON output  and pretty engine names. Also no
support for global GPU or system metrics.

On the other hand it shows clients from all DRM cards which
intel_gpu_top does not do.

Signed-off-by: Tvrtko Ursulin 
Cc: Rob Clark 
Cc: Christian König 


LGTM, Acked-by: Christian König 


Thanks Christian,

It is a very rudimentary tool, more a reference really. I keep hoping 
some UI/desktop folks actually pick up the idea and implement something 
nicer elsewhere. Or maybe it ends up me spending a little bit more time 
on it, to carry over some more functionality from intel_gpu_top.


I see amdgpu patches are in - presumably that means gputop parses it and 
understands fine?


Regards,

Tvrtko


---
  tools/gputop.c    | 260 ++
  tools/meson.build |   5 +
  2 files changed, 265 insertions(+)
  create mode 100644 tools/gputop.c

diff --git a/tools/gputop.c b/tools/gputop.c
new file mode 100644
index ..d259cac1ab17
--- /dev/null
+++ b/tools/gputop.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "igt_drm_clients.h"
+#include "igt_drm_fdinfo.h"
+
+static const char *bars[] = { " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", 
"█" };

+
+static void n_spaces(const unsigned int n)
+{
+    unsigned int i;
+
+    for (i = 0; i < n; i++)
+    putchar(' ');
+}
+
+static void print_percentage_bar(double percent, int max_len)
+{
+    int bar_len, i, len = max_len - 2;
+    const int w = 8;
+
+    assert(max_len > 0);
+
+    bar_len = ceil(w * percent * len / 100.0);
+    if (bar_len > w * len)
+    bar_len = w * len;
+
+    putchar('|');
+
+    for (i = bar_len; i >= w; i -= w)
+    printf("%s", bars[w]);
+    if (i)
+    printf("%s", bars[i]);
+
+    len -= (bar_len + (w - 1)) / w;
+    n_spaces(len);
+
+    putchar('|');
+}
+
+static int
+print_client_header(struct igt_drm_client *c, int lines, int con_w, 
int con_h,

+    int *engine_w)
+{
+    const char *pidname = "    PID   NAME ";
+    int ret, len = strlen(pidname);
+
+    if (lines++ >= con_h || len >= con_w)
+    return lines;
+    printf("\033[7m");
+    ret = printf("DRM minor %u", c->drm_minor);
+    n_spaces(con_w - ret);
+
+    if (lines++ >= con_h)
+    return lines;
+    printf("\n%s", pidname);
+
+    if (c->engines->num_engines) {
+    unsigned int i;
+    int width;
+
+    *engine_w = width = (con_w - len) / c->engines->num_engines;
+
+    for (i = 0; i <= c->engines->max_engine_id; i++) {
+    const char *name = c->engines->names[i];
+    int name_len = strlen(name);
+    int pad = (width - name_len) / 2;
+    int spaces = width - pad - name_len;
+
+    if (!name)
+    continue;
+
+    if (pad < 0 || spaces < 0)
+    continue;
+
+    n_spaces(pad);
+    printf("%s", name);
+    n_spaces(spaces);
+    len += pad + name_len + spaces;
+    }
+    }
+
+    n_spaces(con_w - len);
+    printf("\033[0m\n");
+
+    return lines;
+}
+
+
+static bool
+newheader(const struct igt_drm_client *c, const struct igt_drm_client 
*pc)

+{
+    return !pc || c->drm_minor != pc->drm_minor;
+}
+
+static int
+print_client(struct igt_drm_client *c, struct igt_drm_client **prevc,
+ double t, int lines, int con_w, int con_h,
+ unsigned int period_us, int *engine_w)
+{
+    unsigned int i;
+
+    /* Filter out idle clients. */
+    if (!c->total_runtime || c->samples < 2)
+    return lines;
+
+    /* Print header when moving to a different DRM card. */
+    if (newheader(c, *prevc)) {
+    lines = print_client_header(c, lines, con_w, con_h, engine_w);
+    if (lines >= con_h)
+    return lines;
+    }
+
+    *prevc = c;
+
+    printf("%8u %17s ", c->pid, c->print_name);
+    lines++;
+
+    for (i = 0; c->samples > 1 && i <= c->engines->max_engine_id; i++) {
+    double pct;
+
+    if (!c->engines->capacity[i])
+    continue;
+
+    pct = (double)c->val[i] / period_us / 1e3 * 100 /
+  c->engines->capacity[i];
+
+    /*
+ * Guard against fluctuations between our scanning period and
+ * GPU times as exported by the kernel in fdinfo.
+ */
+    if (pct > 

Re: [Intel-gfx] [PATCH i-g-t 8/8] gputop: Basic vendor agnostic GPU top tool

2022-06-17 Thread Christian König

Am 16.06.22 um 16:06 schrieb Tvrtko Ursulin:

From: Tvrtko Ursulin 

Rudimentary vendor agnostic example of how lib_igt_drm_clients can be used
to display a sorted by card and usage list of processes using GPUs.

Borrows a bit of code from intel_gpu_top but for now omits the fancy
features like interactive functionality, card selection, client
aggregation, sort modes, JSON output  and pretty engine names. Also no
support for global GPU or system metrics.

On the other hand it shows clients from all DRM cards which
intel_gpu_top does not do.

Signed-off-by: Tvrtko Ursulin 
Cc: Rob Clark 
Cc: Christian König 


LGTM, Acked-by: Christian König 


---
  tools/gputop.c| 260 ++
  tools/meson.build |   5 +
  2 files changed, 265 insertions(+)
  create mode 100644 tools/gputop.c

diff --git a/tools/gputop.c b/tools/gputop.c
new file mode 100644
index ..d259cac1ab17
--- /dev/null
+++ b/tools/gputop.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "igt_drm_clients.h"
+#include "igt_drm_fdinfo.h"
+
+static const char *bars[] = { " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█" };
+
+static void n_spaces(const unsigned int n)
+{
+   unsigned int i;
+
+   for (i = 0; i < n; i++)
+   putchar(' ');
+}
+
+static void print_percentage_bar(double percent, int max_len)
+{
+   int bar_len, i, len = max_len - 2;
+   const int w = 8;
+
+   assert(max_len > 0);
+
+   bar_len = ceil(w * percent * len / 100.0);
+   if (bar_len > w * len)
+   bar_len = w * len;
+
+   putchar('|');
+
+   for (i = bar_len; i >= w; i -= w)
+   printf("%s", bars[w]);
+   if (i)
+   printf("%s", bars[i]);
+
+   len -= (bar_len + (w - 1)) / w;
+   n_spaces(len);
+
+   putchar('|');
+}
+
+static int
+print_client_header(struct igt_drm_client *c, int lines, int con_w, int con_h,
+   int *engine_w)
+{
+   const char *pidname = "PID   NAME ";
+   int ret, len = strlen(pidname);
+
+   if (lines++ >= con_h || len >= con_w)
+   return lines;
+   printf("\033[7m");
+   ret = printf("DRM minor %u", c->drm_minor);
+   n_spaces(con_w - ret);
+
+   if (lines++ >= con_h)
+   return lines;
+   printf("\n%s", pidname);
+
+   if (c->engines->num_engines) {
+   unsigned int i;
+   int width;
+
+   *engine_w = width = (con_w - len) / c->engines->num_engines;
+
+   for (i = 0; i <= c->engines->max_engine_id; i++) {
+   const char *name = c->engines->names[i];
+   int name_len = strlen(name);
+   int pad = (width - name_len) / 2;
+   int spaces = width - pad - name_len;
+
+   if (!name)
+   continue;
+
+   if (pad < 0 || spaces < 0)
+   continue;
+
+   n_spaces(pad);
+   printf("%s", name);
+   n_spaces(spaces);
+   len += pad + name_len + spaces;
+   }
+   }
+
+   n_spaces(con_w - len);
+   printf("\033[0m\n");
+
+   return lines;
+}
+
+
+static bool
+newheader(const struct igt_drm_client *c, const struct igt_drm_client *pc)
+{
+   return !pc || c->drm_minor != pc->drm_minor;
+}
+
+static int
+print_client(struct igt_drm_client *c, struct igt_drm_client **prevc,
+double t, int lines, int con_w, int con_h,
+unsigned int period_us, int *engine_w)
+{
+   unsigned int i;
+
+   /* Filter out idle clients. */
+   if (!c->total_runtime || c->samples < 2)
+   return lines;
+
+   /* Print header when moving to a different DRM card. */
+   if (newheader(c, *prevc)) {
+   lines = print_client_header(c, lines, con_w, con_h, engine_w);
+   if (lines >= con_h)
+   return lines;
+   }
+
+   *prevc = c;
+
+   printf("%8u %17s ", c->pid, c->print_name);
+   lines++;
+
+   for (i = 0; c->samples > 1 && i <= c->engines->max_engine_id; i++) {
+   double pct;
+
+   if (!c->engines->capacity[i])
+   continue;
+
+   pct = (double)c->val[i] / period_us / 1e3 * 100 /
+ c->engines->capacity[i];
+
+   /*
+* Guard against fluctuations between our scanning period and
+* GPU times as exported by the kernel in fdinfo.
+*/
+   if (pct > 100.0)
+  

[Intel-gfx] [PATCH i-g-t 8/8] gputop: Basic vendor agnostic GPU top tool

2022-06-16 Thread Tvrtko Ursulin
From: Tvrtko Ursulin 

Rudimentary vendor agnostic example of how lib_igt_drm_clients can be used
to display a sorted by card and usage list of processes using GPUs.

Borrows a bit of code from intel_gpu_top but for now omits the fancy
features like interactive functionality, card selection, client
aggregation, sort modes, JSON output  and pretty engine names. Also no
support for global GPU or system metrics.

On the other hand it shows clients from all DRM cards which
intel_gpu_top does not do.

Signed-off-by: Tvrtko Ursulin 
Cc: Rob Clark 
Cc: Christian König 
---
 tools/gputop.c| 260 ++
 tools/meson.build |   5 +
 2 files changed, 265 insertions(+)
 create mode 100644 tools/gputop.c

diff --git a/tools/gputop.c b/tools/gputop.c
new file mode 100644
index ..d259cac1ab17
--- /dev/null
+++ b/tools/gputop.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "igt_drm_clients.h"
+#include "igt_drm_fdinfo.h"
+
+static const char *bars[] = { " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█" };
+
+static void n_spaces(const unsigned int n)
+{
+   unsigned int i;
+
+   for (i = 0; i < n; i++)
+   putchar(' ');
+}
+
+static void print_percentage_bar(double percent, int max_len)
+{
+   int bar_len, i, len = max_len - 2;
+   const int w = 8;
+
+   assert(max_len > 0);
+
+   bar_len = ceil(w * percent * len / 100.0);
+   if (bar_len > w * len)
+   bar_len = w * len;
+
+   putchar('|');
+
+   for (i = bar_len; i >= w; i -= w)
+   printf("%s", bars[w]);
+   if (i)
+   printf("%s", bars[i]);
+
+   len -= (bar_len + (w - 1)) / w;
+   n_spaces(len);
+
+   putchar('|');
+}
+
+static int
+print_client_header(struct igt_drm_client *c, int lines, int con_w, int con_h,
+   int *engine_w)
+{
+   const char *pidname = "PID   NAME ";
+   int ret, len = strlen(pidname);
+
+   if (lines++ >= con_h || len >= con_w)
+   return lines;
+   printf("\033[7m");
+   ret = printf("DRM minor %u", c->drm_minor);
+   n_spaces(con_w - ret);
+
+   if (lines++ >= con_h)
+   return lines;
+   printf("\n%s", pidname);
+
+   if (c->engines->num_engines) {
+   unsigned int i;
+   int width;
+
+   *engine_w = width = (con_w - len) / c->engines->num_engines;
+
+   for (i = 0; i <= c->engines->max_engine_id; i++) {
+   const char *name = c->engines->names[i];
+   int name_len = strlen(name);
+   int pad = (width - name_len) / 2;
+   int spaces = width - pad - name_len;
+
+   if (!name)
+   continue;
+
+   if (pad < 0 || spaces < 0)
+   continue;
+
+   n_spaces(pad);
+   printf("%s", name);
+   n_spaces(spaces);
+   len += pad + name_len + spaces;
+   }
+   }
+
+   n_spaces(con_w - len);
+   printf("\033[0m\n");
+
+   return lines;
+}
+
+
+static bool
+newheader(const struct igt_drm_client *c, const struct igt_drm_client *pc)
+{
+   return !pc || c->drm_minor != pc->drm_minor;
+}
+
+static int
+print_client(struct igt_drm_client *c, struct igt_drm_client **prevc,
+double t, int lines, int con_w, int con_h,
+unsigned int period_us, int *engine_w)
+{
+   unsigned int i;
+
+   /* Filter out idle clients. */
+   if (!c->total_runtime || c->samples < 2)
+   return lines;
+
+   /* Print header when moving to a different DRM card. */
+   if (newheader(c, *prevc)) {
+   lines = print_client_header(c, lines, con_w, con_h, engine_w);
+   if (lines >= con_h)
+   return lines;
+   }
+
+   *prevc = c;
+
+   printf("%8u %17s ", c->pid, c->print_name);
+   lines++;
+
+   for (i = 0; c->samples > 1 && i <= c->engines->max_engine_id; i++) {
+   double pct;
+
+   if (!c->engines->capacity[i])
+   continue;
+
+   pct = (double)c->val[i] / period_us / 1e3 * 100 /
+ c->engines->capacity[i];
+
+   /*
+* Guard against fluctuations between our scanning period and
+* GPU times as exported by the kernel in fdinfo.
+*/
+   if (pct > 100.0)
+   pct = 100.0;
+
+   print_percentage_bar(pct, *engine_w);
+   }
+
+ 

Re: [Intel-gfx] [PATCH i-g-t 8/8] gputop: Basic vendor agnostic GPU top tool

2022-05-11 Thread Tvrtko Ursulin



On 11/05/2022 15:42, Christian König wrote:

Just two bugs I've found and you should probably handle:

1. On amdgpu we probably want to filter engines which are not used by an 
application. This confuses gputop in it's display. E.g. when you have 
one application using only gfx and the other only sdma both are grouped 
together which is not correct at all.


Grouped as displayed as single line? Pid/name? But either way if they 
have different client ids they shouldn't be grouped. That would be a bug 
which I don't quite see in the code so if you could please confirm these 
details I will look into it some more.


The situation where one application uses one engine, and another uses 
another is exactly present in my "screenshot" from the cover letter so 
it is supposed to work.


2. Invalid inputs, especially engines with the same name let the tool 
crash in a segmentation fault.


Take this input for example:
drm-engine-gfx:    21475769304 ns
drm-engine-compute:    0 ns
drm-engine-dma:    0 ns
drm-engine-dec:    0 ns
drm-engine-enc:    0 ns
drm-engine-enc_1:    0 ns
drm-engine-dec:    0 ns
drm-engine-enc:    0 ns
drm-engine-jpeg:    0 ns

Not really an issue, cause that shouldn't happen in practice, but quite 
annoying during testing.


I can easily make it ignore that sort of a (broken) client, not sure 
that anything smarter than that would be useful.


Regards,

Tvrtko


Maybe I will find time tomorrow looking over the code.

Thanks,
Christian.

Am 11.05.22 um 14:18 schrieb Tvrtko Ursulin:

From: Tvrtko Ursulin 

Rudimentary vendor agnostic example of how lib_igt_drm_clients can be 
used

to display a sorted by card and usage list of processes using GPUs.

Borrows a bit of code from intel_gpu_top but for now omits the fancy
features like interactive functionality, card selection, client
aggregation, sort modes, JSON output  and pretty engine names. Also no
support for global GPU or system metrics.

On the other hand it shows clients from all DRM cards which
intel_gpu_top does not do.

Signed-off-by: Tvrtko Ursulin 
Cc: Rob Clark 
Cc: Christian König 
---
  tools/gputop.c    | 260 ++
  tools/meson.build |   5 +
  2 files changed, 265 insertions(+)
  create mode 100644 tools/gputop.c

diff --git a/tools/gputop.c b/tools/gputop.c
new file mode 100644
index ..d259cac1ab17
--- /dev/null
+++ b/tools/gputop.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "igt_drm_clients.h"
+#include "igt_drm_fdinfo.h"
+
+static const char *bars[] = { " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", 
"█" };

+
+static void n_spaces(const unsigned int n)
+{
+    unsigned int i;
+
+    for (i = 0; i < n; i++)
+    putchar(' ');
+}
+
+static void print_percentage_bar(double percent, int max_len)
+{
+    int bar_len, i, len = max_len - 2;
+    const int w = 8;
+
+    assert(max_len > 0);
+
+    bar_len = ceil(w * percent * len / 100.0);
+    if (bar_len > w * len)
+    bar_len = w * len;
+
+    putchar('|');
+
+    for (i = bar_len; i >= w; i -= w)
+    printf("%s", bars[w]);
+    if (i)
+    printf("%s", bars[i]);
+
+    len -= (bar_len + (w - 1)) / w;
+    n_spaces(len);
+
+    putchar('|');
+}
+
+static int
+print_client_header(struct igt_drm_client *c, int lines, int con_w, 
int con_h,

+    int *engine_w)
+{
+    const char *pidname = "    PID   NAME ";
+    int ret, len = strlen(pidname);
+
+    if (lines++ >= con_h || len >= con_w)
+    return lines;
+    printf("\033[7m");
+    ret = printf("DRM minor %u", c->drm_minor);
+    n_spaces(con_w - ret);
+
+    if (lines++ >= con_h)
+    return lines;
+    printf("\n%s", pidname);
+
+    if (c->engines->num_engines) {
+    unsigned int i;
+    int width;
+
+    *engine_w = width = (con_w - len) / c->engines->num_engines;
+
+    for (i = 0; i <= c->engines->max_engine_id; i++) {
+    const char *name = c->engines->names[i];
+    int name_len = strlen(name);
+    int pad = (width - name_len) / 2;
+    int spaces = width - pad - name_len;
+
+    if (!name)
+    continue;
+
+    if (pad < 0 || spaces < 0)
+    continue;
+
+    n_spaces(pad);
+    printf("%s", name);
+    n_spaces(spaces);
+    len += pad + name_len + spaces;
+    }
+    }
+
+    n_spaces(con_w - len);
+    printf("\033[0m\n");
+
+    return lines;
+}
+
+
+static bool
+newheader(const struct igt_drm_client *c, const struct igt_drm_client 
*pc)

+{
+    return !pc || c->drm_minor != pc->drm_minor;
+}
+
+static int
+print_client(struct igt_drm_client *c, struct igt_drm_client **prevc,
+ double 

[Intel-gfx] [PATCH i-g-t 8/8] gputop: Basic vendor agnostic GPU top tool

2022-05-11 Thread Tvrtko Ursulin
From: Tvrtko Ursulin 

Rudimentary vendor agnostic example of how lib_igt_drm_clients can be used
to display a sorted by card and usage list of processes using GPUs.

Borrows a bit of code from intel_gpu_top but for now omits the fancy
features like interactive functionality, card selection, client
aggregation, sort modes, JSON output  and pretty engine names. Also no
support for global GPU or system metrics.

On the other hand it shows clients from all DRM cards which
intel_gpu_top does not do.

Signed-off-by: Tvrtko Ursulin 
Cc: Rob Clark 
Cc: Christian König 
---
 tools/gputop.c| 260 ++
 tools/meson.build |   5 +
 2 files changed, 265 insertions(+)
 create mode 100644 tools/gputop.c

diff --git a/tools/gputop.c b/tools/gputop.c
new file mode 100644
index ..d259cac1ab17
--- /dev/null
+++ b/tools/gputop.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "igt_drm_clients.h"
+#include "igt_drm_fdinfo.h"
+
+static const char *bars[] = { " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█" };
+
+static void n_spaces(const unsigned int n)
+{
+   unsigned int i;
+
+   for (i = 0; i < n; i++)
+   putchar(' ');
+}
+
+static void print_percentage_bar(double percent, int max_len)
+{
+   int bar_len, i, len = max_len - 2;
+   const int w = 8;
+
+   assert(max_len > 0);
+
+   bar_len = ceil(w * percent * len / 100.0);
+   if (bar_len > w * len)
+   bar_len = w * len;
+
+   putchar('|');
+
+   for (i = bar_len; i >= w; i -= w)
+   printf("%s", bars[w]);
+   if (i)
+   printf("%s", bars[i]);
+
+   len -= (bar_len + (w - 1)) / w;
+   n_spaces(len);
+
+   putchar('|');
+}
+
+static int
+print_client_header(struct igt_drm_client *c, int lines, int con_w, int con_h,
+   int *engine_w)
+{
+   const char *pidname = "PID   NAME ";
+   int ret, len = strlen(pidname);
+
+   if (lines++ >= con_h || len >= con_w)
+   return lines;
+   printf("\033[7m");
+   ret = printf("DRM minor %u", c->drm_minor);
+   n_spaces(con_w - ret);
+
+   if (lines++ >= con_h)
+   return lines;
+   printf("\n%s", pidname);
+
+   if (c->engines->num_engines) {
+   unsigned int i;
+   int width;
+
+   *engine_w = width = (con_w - len) / c->engines->num_engines;
+
+   for (i = 0; i <= c->engines->max_engine_id; i++) {
+   const char *name = c->engines->names[i];
+   int name_len = strlen(name);
+   int pad = (width - name_len) / 2;
+   int spaces = width - pad - name_len;
+
+   if (!name)
+   continue;
+
+   if (pad < 0 || spaces < 0)
+   continue;
+
+   n_spaces(pad);
+   printf("%s", name);
+   n_spaces(spaces);
+   len += pad + name_len + spaces;
+   }
+   }
+
+   n_spaces(con_w - len);
+   printf("\033[0m\n");
+
+   return lines;
+}
+
+
+static bool
+newheader(const struct igt_drm_client *c, const struct igt_drm_client *pc)
+{
+   return !pc || c->drm_minor != pc->drm_minor;
+}
+
+static int
+print_client(struct igt_drm_client *c, struct igt_drm_client **prevc,
+double t, int lines, int con_w, int con_h,
+unsigned int period_us, int *engine_w)
+{
+   unsigned int i;
+
+   /* Filter out idle clients. */
+   if (!c->total_runtime || c->samples < 2)
+   return lines;
+
+   /* Print header when moving to a different DRM card. */
+   if (newheader(c, *prevc)) {
+   lines = print_client_header(c, lines, con_w, con_h, engine_w);
+   if (lines >= con_h)
+   return lines;
+   }
+
+   *prevc = c;
+
+   printf("%8u %17s ", c->pid, c->print_name);
+   lines++;
+
+   for (i = 0; c->samples > 1 && i <= c->engines->max_engine_id; i++) {
+   double pct;
+
+   if (!c->engines->capacity[i])
+   continue;
+
+   pct = (double)c->val[i] / period_us / 1e3 * 100 /
+ c->engines->capacity[i];
+
+   /*
+* Guard against fluctuations between our scanning period and
+* GPU times as exported by the kernel in fdinfo.
+*/
+   if (pct > 100.0)
+   pct = 100.0;
+
+   print_percentage_bar(pct, *engine_w);
+   }
+
+