summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorTvrtko Ursulin <tvrtko.ursulin@intel.com>2023-10-12 09:15:46 +0100
committerKamil Konieczny <kamil.konieczny@linux.intel.com>2023-11-06 15:47:09 +0100
commit79454b8098757117618d1f610c2998479116a788 (patch)
tree6bb84d7121235a913c9d25a39ac3067bc79bef9a /tools
parent9a3d30320fd5be03a7afc4854830535fe1ccb9db (diff)
tools/intel_gpu_top: Add per client memory info
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>
Diffstat (limited to 'tools')
-rw-r--r--tools/intel_gpu_top.c114
1 files changed, 112 insertions, 2 deletions
diff --git a/tools/intel_gpu_top.c b/tools/intel_gpu_top.c
index b2e81d5f9..2c09895c7 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)