[Intel-gfx] [PATCH i-g-t 11/12] tools/intel_gpu_top: Add per client memory info

2023-09-29 Thread Tvrtko Ursulin
From: Tvrtko Ursulin 

JSON output has the full breakdown but for now the interactive mode only
shows total and resident aggregated for all memory regions.

Signed-off-by: Tvrtko Ursulin 
---
 tools/intel_gpu_top.c | 114 +-
 1 file changed, 112 insertions(+), 2 deletions(-)

diff --git a/tools/intel_gpu_top.c b/tools/intel_gpu_top.c
index 4b9ef306ca8e..958df42e8c20 100644
--- a/tools/intel_gpu_top.c
+++ b/tools/intel_gpu_top.c
@@ -133,11 +133,24 @@ struct intel_clients {
const char *pci_slot;
struct igt_drm_client_engines classes;
struct igt_drm_clients *clients;
+   struct igt_drm_client_regions *regions; /* Borrowed from first client */
 };
 
 static struct termios termios_orig;
 static bool class_view;
 
+/* Maps i915 fdinfo names to indices */
+static const char *memory_region_map[] = {
+   "system0",
+   "local0",
+};
+
+/* For JSON, 1:1 with indices above. */
+static const char *json_memory_region_names[] = {
+   "system",
+   "local",
+};
+
 __attribute__((format(scanf,3,4)))
 static int igt_sysfs_scanf(int dir, const char *attr, const char *fmt, ...)
 {
@@ -880,6 +893,9 @@ static struct igt_drm_clients *display_clients(struct 
igt_drm_clients *clients)
ac->val = calloc(c->engines->max_engine_id + 1,
 sizeof(ac->val[0]));
assert(ac->val);
+   ac->regions = c->regions;
+   ac->memory = calloc(c->regions->max_region_id + 1,
+   sizeof(ac->memory[0]));
ac->samples = 1;
}
 
@@ -894,6 +910,14 @@ static struct igt_drm_clients *display_clients(struct 
igt_drm_clients *clients)
 
for (i = 0; i <= c->engines->max_engine_id; i++)
ac->val[i] += c->val[i];
+
+   for (i = 0; i <= c->regions->max_region_id; i++) {
+   ac->memory[i].total += c->memory[i].total;
+   ac->memory[i].shared += c->memory[i].shared;
+   ac->memory[i].resident += c->memory[i].resident;
+   ac->memory[i].purgeable += c->memory[i].purgeable;
+   ac->memory[i].active += c->memory[i].active;
+   }
}
 
aggregated->num_clients = num;
@@ -918,8 +942,10 @@ static void free_display_clients(struct igt_drm_clients 
*clients)
 * "display" clients are not proper clients and have un-initialized
 * or borrowed fields which we don't want the library to try and free.
 */
-   igt_for_each_drm_client(clients, c, tmp)
+   igt_for_each_drm_client(clients, c, tmp) {
free(c->val);
+   free(c->memory);
+   }
 
free(clients->client);
free(clients);
@@ -2012,6 +2038,9 @@ print_clients_header(struct igt_drm_clients *clients, int 
lines,
if (lines++ >= con_h || len >= con_w)
return lines;
 
+   if (iclients->regions)
+   len += printf(" MEM  RSS ");
+
if (iclients->classes.num_engines) {
unsigned int i;
int width;
@@ -2055,6 +2084,20 @@ print_clients_header(struct igt_drm_clients *clients, 
int lines,
 static bool numeric_clients;
 static bool filter_idle;
 
+static int print_size(uint64_t sz)
+{
+   char units[] = { ' ', 'K', 'M', 'G' };
+   unsigned int u;
+
+   for (u = 0; u < ARRAY_SIZE(units) - 1; u++) {
+   if (sz & 1023 || sz < 1024)
+   break;
+   sz /= 1024;
+   }
+
+   return printf("%7"PRIu64"%c ", sz, units[u]);
+}
+
 static int
 print_client(struct igt_drm_client *c, struct engines *engines, double t, int 
lines,
 int con_w, int con_h, unsigned int period_us, int *class_w)
@@ -2072,6 +2115,18 @@ print_client(struct igt_drm_client *c, struct engines 
*engines, double t, int li
 
len = printf("%*s ", clients->max_pid_len, c->pid_str);
 
+   if (iclients->regions) {
+   uint64_t sz;
+
+   for (sz = 0, i = 0; i <= c->regions->max_region_id; i++)
+   sz += c->memory[i].total;
+   len += print_size(sz);
+
+   for (sz = 0, i = 0; i <= c->regions->max_region_id; i++)
+   sz += c->memory[i].resident;
+   len += print_size(sz);
+   }
+
for (i = 0; i <= iclients->classes.max_engine_id; i++) {
double pct, max;
 
@@ -2111,6 +2166,42 @@ print_client(struct igt_drm_client *c, struct engines 
*engines, double t, int li
snprintf(buf, sizeof(buf), "%u", c->pid);
__json_add_member("pid", buf);
 
+   if (iclients->regions) {
+   

[Intel-gfx] [PATCH i-g-t 11/12] tools/intel_gpu_top: Add per client memory info

2023-09-22 Thread Tvrtko Ursulin
From: Tvrtko Ursulin 

JSON output has the full breakdown but for now the interactive mode only
shows total and resident aggregated for all memory regions.

Signed-off-by: Tvrtko Ursulin 
---
 tools/intel_gpu_top.c | 114 +-
 1 file changed, 112 insertions(+), 2 deletions(-)

diff --git a/tools/intel_gpu_top.c b/tools/intel_gpu_top.c
index 27503ac03ebd..c239a0d4f350 100644
--- a/tools/intel_gpu_top.c
+++ b/tools/intel_gpu_top.c
@@ -133,11 +133,24 @@ struct intel_clients {
const char *pci_slot;
struct igt_drm_client_engines classes;
struct igt_drm_clients *clients;
+   struct igt_drm_client_regions *regions; /* Borrowed from first client */
 };
 
 static struct termios termios_orig;
 static bool class_view;
 
+/* Maps i915 fdinfo names to indices */
+static const char *memory_region_map[] = {
+   "system0",
+   "local0",
+};
+
+/* For JSON, 1:1 with indices above. */
+static const char *json_memory_region_names[] = {
+   "system",
+   "local",
+};
+
 __attribute__((format(scanf,3,4)))
 static int igt_sysfs_scanf(int dir, const char *attr, const char *fmt, ...)
 {
@@ -884,6 +897,9 @@ static struct igt_drm_clients *display_clients(struct 
igt_drm_clients *clients)
ac->val = calloc(c->engines->max_engine_id + 1,
 sizeof(ac->val[0]));
assert(ac->val);
+   ac->regions = c->regions;
+   ac->memory = calloc(c->regions->max_region_id + 1,
+   sizeof(ac->memory[0]));
ac->samples = 1;
}
 
@@ -898,6 +914,14 @@ static struct igt_drm_clients *display_clients(struct 
igt_drm_clients *clients)
 
for (i = 0; i <= c->engines->max_engine_id; i++)
ac->val[i] += c->val[i];
+
+   for (i = 0; i <= c->regions->max_region_id; i++) {
+   ac->memory[i].total += c->memory[i].total;
+   ac->memory[i].shared += c->memory[i].shared;
+   ac->memory[i].resident += c->memory[i].resident;
+   ac->memory[i].purgeable += c->memory[i].purgeable;
+   ac->memory[i].active += c->memory[i].active;
+   }
}
 
aggregated->num_clients = num;
@@ -922,8 +946,10 @@ static void free_display_clients(struct igt_drm_clients 
*clients)
 * "display" clients are not proper clients and have un-initialized
 * or borrowed fields which we don't want the library to try and free.
 */
-   igt_for_each_drm_client(clients, c, tmp)
+   igt_for_each_drm_client(clients, c, tmp) {
free(c->val);
+   free(c->memory);
+   }
 
free(clients->client);
free(clients);
@@ -2016,6 +2042,9 @@ print_clients_header(struct igt_drm_clients *clients, int 
lines,
if (lines++ >= con_h || len >= con_w)
return lines;
 
+   if (iclients->regions)
+   len += printf(" MEM  RSS ");
+
if (iclients->classes.num_engines) {
unsigned int i;
int width;
@@ -2059,6 +2088,20 @@ print_clients_header(struct igt_drm_clients *clients, 
int lines,
 static bool numeric_clients;
 static bool filter_idle;
 
+static int print_size(uint64_t sz)
+{
+   char units[] = { ' ', 'K', 'M', 'G' };
+   unsigned int u;
+
+   for (u = 0; u < ARRAY_SIZE(units) - 1; u++) {
+   if (sz & 1023 || sz < 1024)
+   break;
+   sz /= 1024;
+   }
+
+   return printf("%7"PRIu64"%c ", sz, units[u]);
+}
+
 static int
 print_client(struct igt_drm_client *c, struct engines *engines, double t, int 
lines,
 int con_w, int con_h, unsigned int period_us, int *class_w)
@@ -2076,6 +2119,18 @@ print_client(struct igt_drm_client *c, struct engines 
*engines, double t, int li
 
len = printf("%*s ", clients->max_pid_len, c->pid_str);
 
+   if (iclients->regions) {
+   uint64_t sz;
+
+   for (sz = 0, i = 0; i <= c->regions->max_region_id; i++)
+   sz += c->memory[i].total;
+   len += print_size(sz);
+
+   for (sz = 0, i = 0; i <= c->regions->max_region_id; i++)
+   sz += c->memory[i].resident;
+   len += print_size(sz);
+   }
+
for (i = 0; i <= iclients->classes.max_engine_id; i++) {
double pct, max;
 
@@ -2115,6 +2170,42 @@ print_client(struct igt_drm_client *c, struct engines 
*engines, double t, int li
snprintf(buf, sizeof(buf), "%u", c->pid);
__json_add_member("pid", buf);
 
+   if (iclients->regions) {
+