Message ID | 20231012081547.852052-9-tvrtko.ursulin@linux.intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Client memory fdinfo test and intel_gpu_top support | expand |
Hi Tvrtko, On 2023-10-12 at 09:15:46 +0100, Tvrtko Ursulin wrote: > From: Tvrtko Ursulin <tvrtko.ursulin@intel.com> > > 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 <tvrtko.ursulin@intel.com> Reviewed-by: Kamil Konieczny <kamil.konieczny@linux.intel.com> > --- > 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 b2e81d5f9ffb..2c09895c79dd 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, ...) > { > @@ -882,6 +895,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; > } > > @@ -896,6 +912,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; > @@ -920,8 +944,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) { > + pops->open_struct("memory"); > + > + for (i = 0; i < ARRAY_SIZE(json_memory_region_names); > + i++) { > + if (i > c->regions->max_region_id) > + break; > + > + pops->open_struct(json_memory_region_names[i]); > + > + snprintf(buf, sizeof(buf), "%" PRIu64, > + c->memory[i].total); > + __json_add_member("total", buf); > + > + snprintf(buf, sizeof(buf), "%" PRIu64, > + c->memory[i].shared); > + __json_add_member("shared", buf); > + > + snprintf(buf, sizeof(buf), "%" PRIu64, > + c->memory[i].resident); > + __json_add_member("resident", buf); > + > + snprintf(buf, sizeof(buf), "%" PRIu64, > + c->memory[i].purgeable); > + __json_add_member("purgeable", buf); > + > + snprintf(buf, sizeof(buf), "%" PRIu64, > + c->memory[i].active); > + __json_add_member("active", buf); > + > + pops->close_struct(); > + } > + > + pops->close_struct(); > + } > + > if (c->samples > 1) { > pops->open_struct("engine-classes"); > > @@ -2460,10 +2551,29 @@ static void intel_scan_clients(struct intel_clients *iclients) > "video-enhance", > "compute", > }; > + struct igt_drm_client *c; > + unsigned int i; > > igt_drm_clients_scan(iclients->clients, client_match, > engine_map, ARRAY_SIZE(engine_map), > - NULL, 0); > + memory_region_map, ARRAY_SIZE(memory_region_map)); > + > + iclients->regions = NULL; > + > + if (!iclients->clients) > + return; > + > + /* > + * Borrow memory region data from first client so we can use it > + * when displaying stuff. All regions are the same due our client_match. > + */ > + igt_for_each_drm_client(iclients->clients, c, i) { > + if (c->status == IGT_DRM_CLIENT_ALIVE) { > + if (c->regions->num_regions) > + iclients->regions = c->regions; > + break; > + } > + } > } > > int main(int argc, char **argv) > -- > 2.39.2 >
diff --git a/tools/intel_gpu_top.c b/tools/intel_gpu_top.c index b2e81d5f9ffb..2c09895c79dd 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, ...) { @@ -882,6 +895,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; } @@ -896,6 +912,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; @@ -920,8 +944,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) { + pops->open_struct("memory"); + + for (i = 0; i < ARRAY_SIZE(json_memory_region_names); + i++) { + if (i > c->regions->max_region_id) + break; + + pops->open_struct(json_memory_region_names[i]); + + snprintf(buf, sizeof(buf), "%" PRIu64, + c->memory[i].total); + __json_add_member("total", buf); + + snprintf(buf, sizeof(buf), "%" PRIu64, + c->memory[i].shared); + __json_add_member("shared", buf); + + snprintf(buf, sizeof(buf), "%" PRIu64, + c->memory[i].resident); + __json_add_member("resident", buf); + + snprintf(buf, sizeof(buf), "%" PRIu64, + c->memory[i].purgeable); + __json_add_member("purgeable", buf); + + snprintf(buf, sizeof(buf), "%" PRIu64, + c->memory[i].active); + __json_add_member("active", buf); + + pops->close_struct(); + } + + pops->close_struct(); + } + if (c->samples > 1) { pops->open_struct("engine-classes"); @@ -2460,10 +2551,29 @@ static void intel_scan_clients(struct intel_clients *iclients) "video-enhance", "compute", }; + struct igt_drm_client *c; + unsigned int i; igt_drm_clients_scan(iclients->clients, client_match, engine_map, ARRAY_SIZE(engine_map), - NULL, 0); + memory_region_map, ARRAY_SIZE(memory_region_map)); + + iclients->regions = NULL; + + if (!iclients->clients) + return; + + /* + * Borrow memory region data from first client so we can use it + * when displaying stuff. All regions are the same due our client_match. + */ + igt_for_each_drm_client(iclients->clients, c, i) { + if (c->status == IGT_DRM_CLIENT_ALIVE) { + if (c->regions->num_regions) + iclients->regions = c->regions; + break; + } + } } int main(int argc, char **argv)