From: Tvrtko Ursulin
Use the i915 exported data in /proc//fdinfo to show GPU utilization
per DRM client.
Example of the output:
intel-gpu-top: Intel Tigerlake (Gen12) @ /dev/dri/card0 - 220/ 221 MHz
70% RC6; 0.62/ 7.08 W; 760 irqs/s
ENGINES BUSY MI_SEMA MI_WAIT
Render/3D 23.06% |██▊ | 0% 0%
Blitter0.00% | | 0% 0%
Video5.40% |█▋ | 0% 0%
VideoEnhance 20.67% |██ | 0% 0%
PID NAME Render/3DBlitter VideoVideoEnhance
3082 mpv | || ||▌ ||██|
3117 neverball |█▉|| || || |
1 systemd |▍ || || || |
2338 gnome-shell | || || || |
Signed-off-by: Tvrtko Ursulin
---
man/intel_gpu_top.rst | 4 +
tools/intel_gpu_top.c | 866 +-
2 files changed, 868 insertions(+), 2 deletions(-)
diff --git a/man/intel_gpu_top.rst b/man/intel_gpu_top.rst
index b3b765b05feb..f4dbfc5b44d9 100644
--- a/man/intel_gpu_top.rst
+++ b/man/intel_gpu_top.rst
@@ -56,6 +56,10 @@ Supported keys:
'q'Exit from the tool.
'h'Show interactive help.
'1'Toggle between aggregated engine class and physical engine mode.
+'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 81c724d1fe1c..5c9a195ea275 100644
--- a/tools/intel_gpu_top.c
+++ b/tools/intel_gpu_top.c
@@ -43,6 +43,7 @@
#include
#include
#include
+#include
#include "igt_perf.h"
@@ -309,7 +310,8 @@ static int engine_cmp(const void *__a, const void *__b)
return a->instance - b->instance;
}
-#define is_igpu_pci(x) (strcmp(x, ":00:02.0") == 0)
+#define IGPU_PCI ":00:02.0"
+#define is_igpu_pci(x) (strcmp(x, IGPU_PCI) == 0)
#define is_igpu(x) (strcmp(x, "i915") == 0)
static struct engines *discover_engines(char *device)
@@ -633,6 +635,613 @@ static void pmu_sample(struct engines *engines)
}
}
+enum client_status {
+ FREE = 0, /* mbz */
+ ALIVE,
+ PROBE
+};
+
+struct clients;
+
+struct client {
+ struct clients *clients;
+
+ enum client_status status;
+ unsigned int id;
+ unsigned int pid;
+ char name[24];
+ char print_name[24];
+ unsigned int samples;
+ unsigned long total_runtime;
+ unsigned long last_runtime;
+ struct engines *engines;
+ unsigned long *val;
+ uint64_t *last;
+};
+
+struct clients {
+ unsigned int num_clients;
+ unsigned int active_clients;
+
+ unsigned int num_classes;
+ struct engine_class *class;
+
+ char pci_slot[64];
+
+ struct client *client;
+};
+
+#define for_each_client(clients, c, tmp) \
+ for ((tmp) = (clients)->num_clients, c = (clients)->client; \
+(tmp > 0); (tmp)--, (c)++)
+
+static struct clients *init_clients(const char *pci_slot)
+{
+ struct clients *clients;
+
+ clients = malloc(sizeof(*clients));
+ if (!clients)
+ return NULL;
+
+ memset(clients, 0, sizeof(*clients));
+
+ strncpy(clients->pci_slot, pci_slot, sizeof(clients->pci_slot));
+
+ return clients;
+}
+
+static struct client *
+find_client(struct clients *clients, enum client_status status, unsigned int
id)
+{
+ unsigned int start, num;
+ struct client *c;
+
+ start = status == FREE ? clients->active_clients : 0; /* Free block at
the end. */
+ num = clients->num_clients - start;
+
+ for (c = >client[start]; num; c++, num--) {
+ if (status != c->status)
+ continue;
+
+ if (status == FREE || c->id == id)
+ return c;
+ }
+
+ return NULL;
+}
+
+static void
+update_client(struct client *c, unsigned int pid, char *name, uint64_t val[16])
+{
+ unsigned int i;
+
+ if (c->pid != pid)
+ c->pid = pid;
+
+ if (strcmp(c->name, name)) {
+ char *p;
+
+ strncpy(c->name, name, sizeof(c->name) - 1);
+ strncpy(c->print_name, name, sizeof(c->print_name) - 1);
+
+ p = c->print_name;
+ while (*p) {
+ if (!isprint(*p))
+ *p = '*';
+ p++;
+ }
+ }
+
+ c->last_runtime = 0;
+ c->total_runtime = 0;
+
+ for (i = 0; i <