From: Tvrtko Ursulin <tvrtko.ursulin@xxxxxxxxx> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@xxxxxxxxx> --- tools/intel_gpu_top.c | 268 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 263 insertions(+), 5 deletions(-) diff --git a/tools/intel_gpu_top.c b/tools/intel_gpu_top.c index 59a112240092..63f0c1941258 100644 --- a/tools/intel_gpu_top.c +++ b/tools/intel_gpu_top.c @@ -407,8 +407,222 @@ static void pmu_sample(struct engines *engines) } } +enum client_status { + FREE = 0, /* mbz */ + ALIVE, + PROBE +}; + +struct client { + enum client_status status; + unsigned int id; + unsigned int pid; + char name[128]; + unsigned int samples; + unsigned long total; + struct engines *engines; + unsigned long *val; + uint64_t *last; +}; + +#define SYSFS_ENABLE "/sys/class/drm/card0/clients/enable_stats" +#define SYSFS_CLIENTS "/sys/class/drm/card0/clients/" + +#define PERIOD_US (1000e3) + +static struct client *clients; +static unsigned int num_clients; + +#define for_each_client(c, tmp) \ + for (tmp = num_clients, c = clients; tmp > 0; tmp--, c++) + +static uint64_t read_client_busy(unsigned int id, const char *engine) +{ + char buf[256]; + ssize_t ret; + + ret = snprintf(buf, sizeof(buf), SYSFS_CLIENTS "/%u/busy/%s", + id, engine); + assert(ret > 0); + + return filename_to_u64(buf, 10); +} + +static struct client *find_client(enum client_status status, unsigned int id) +{ + struct client *c; + unsigned int tmp; + + for_each_client(c, tmp) { + if ((status == FREE && c->status == FREE) || + (status == c->status && c->id == id)) { + return c; + } + } + + return NULL; +} + +static void update_client(struct client *c, unsigned int pid, char *name) +{ + uint64_t val[c->engines->num_engines]; + unsigned int i; + + if (c->pid != pid) + c->pid = pid; + + if (strncmp(c->name, name, sizeof(c->name))) + strncpy(c->name, name, sizeof(c->name)); + + for (i = 0; i < c->engines->num_engines; i++) { + struct engine *engine = engine_ptr(c->engines, i); + + val[i] = read_client_busy(c->id, engine->name); + } + + c->total = 0; + + for (i = 0; i < c->engines->num_engines; i++) { + assert(val[i] >= c->last[i]); + c->val[i] = val[i] - c->last[i]; + c->total += c->val[i]; + c->last[i] = val[i]; + } + + c->samples++; + c->status = ALIVE; +} + +static void +add_client(unsigned int id, unsigned int pid, char *name, + struct engines *engines) +{ + struct client *c; + + assert(!find_client(ALIVE, id)); + + c = find_client(FREE, 0); + if (!c) { + unsigned int idx = num_clients; + + num_clients += (num_clients + 2) / 2; + clients = realloc(clients, num_clients * sizeof(*c)); + assert(clients); + c = &clients[idx]; + memset(c, 0, (num_clients - idx) * sizeof(*c)); + } + + c->id = id; + c->engines = engines; + c->val = calloc(engines->num_engines, sizeof(c->val)); + c->last = calloc(engines->num_engines, sizeof(c->last)); + assert(c->val && c->last); + + update_client(c, pid, name); + +// c = find_client(c->status, c->id); +} + +static void free_client(struct client *c) +{ + free(c->val); + free(c->last); + memset(c, 0, sizeof(*c)); +} + +static char *read_client_sysfs(unsigned int id, const char *field) +{ + char buf[256]; + ssize_t ret; + + ret = snprintf(buf, sizeof(buf), SYSFS_CLIENTS "/%u/%s", id, field); + assert(ret > 0); + + ret = filename_to_buf(buf, buf, sizeof(buf)); + assert(ret == 0); + + return strdup(buf); +} + +static void scan(struct engines *engines) +{ + struct dirent *dent; + struct client *c; + char *pid, *name; + unsigned int tmp; + unsigned int id; + DIR *d; + + for_each_client(c, tmp) { + if (c->status == ALIVE) + c->status = PROBE; + } + + d = opendir(SYSFS_CLIENTS); + assert(!NULL); + + while ((dent = readdir(d)) != NULL) { + if (dent->d_type != DT_DIR) + continue; + if (!isdigit(dent->d_name[0])) + continue; + + id = atoi(dent->d_name); + + name = read_client_sysfs(id, "name"); + assert(name); + + pid = read_client_sysfs(id, "pid"); + assert(pid); + + c = find_client(PROBE, id); + if (c) { + update_client(c, atoi(pid), name); + continue; + } + + add_client(id, atoi(pid), name, engines); + + free(name); + free(pid); + } + + closedir(d); + + for_each_client(c, tmp) { + if (c->status == PROBE) + free_client(c); + } +} + +static int cmp(const void *_a, const void *_b) +{ + const struct client *a = _a; + const struct client *b = _b; + long tot_a = a->total; + long tot_b = b->total; + + if (a->status != ALIVE || a->samples < 2) + tot_a = -1; + if (b->status != ALIVE || b->samples < 2) + tot_b = -1; + + if (tot_a == tot_b) + return a->pid - b->pid; + else + return -(tot_a - tot_b); +} + 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) { @@ -422,8 +636,7 @@ print_percentage_bar(double percent, int max_len) if (i) printf("%s", bars[i]); - for (i = 0; i < (max_len - 2 - (bar_len + 7) / 8); i++) - putchar(' '); + n_spaces(max_len - 2 - (bar_len + 7) / 8); putchar('|'); } @@ -500,16 +713,21 @@ int main(int argc, char **argv) engines->load_exp[i] = exp(-period / load_period[i]); pmu_sample(engines); + scan(engines); for (;;) { double t, freq[2], irq, rc6, power; double qd = 0; int lines = 0; + struct client *c; + unsigned int len, engine_w; unsigned int j; usleep(period_us); pmu_sample(engines); + scan(engines); + t = (double)(engines->ts.cur - engines->ts.prev) / 1e9; printf("\033[H\033[J"); @@ -561,8 +779,6 @@ int main(int argc, char **argv) for (i = 0; i < engines->num_engines && lines < con_h; i++) { struct engine *engine = engine_ptr(engines, i); - unsigned int max_w = con_w - 1; - unsigned int len; double val[2]; char buf[128]; @@ -579,7 +795,7 @@ int main(int argc, char **argv) engine->qd[0], engine->qd[1], engine->qd[2]); - print_percentage_bar(val[0], max_w - len); + print_percentage_bar(val[0], con_w - 1 - len); printf("%s\n", buf); @@ -587,6 +803,48 @@ int main(int argc, char **argv) } printf("\n"); + + printf("\033[7m"); + len = printf("%5s%16s", "PID", "NAME"); + engine_w = (con_w - len) / engines->num_engines; + for (i = 0; i < engines->num_engines && lines < con_h; i++) { + struct engine *engine = engine_ptr(engines, i); + unsigned int pad = (engine_w - strlen(engine->name)) / 2; + + n_spaces(pad); + printf("%s", engine->name); + n_spaces(engine_w - pad - strlen(engine->name)); + len += pad + strlen(engine->name) + + (engine_w - pad - strlen(engine->name)); + } + n_spaces(con_w - len); + printf("\033[0m\n"); + lines++; + + qsort(clients, num_clients, sizeof(*c), cmp); + + for_each_client(c, i) { + if (lines > con_h) + break; + + assert(c->status != PROBE); + if (c->status != ALIVE || c->samples < 2) + break; + + printf("%5u%16s ", c->pid, c->name); + + for (i = 0; i < engines->num_engines; i++) { + double pct; + + pct = (double)c->val[i] / period_us / 1e3 * 100; + + print_percentage_bar(pct, engine_w); + } + + putchar('\n'); + lines++; + } + } return 0; -- 2.14.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx