* [Intel-gfx] [RFC i-g-t 0/1] Per client intel_gpu_top
@ 2020-03-09 18:32 Tvrtko Ursulin
2020-03-09 18:32 ` [igt-dev] [RFC i-g-t 1/1] intel-gpu-top: Support for client stats Tvrtko Ursulin
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Tvrtko Ursulin @ 2020-03-09 18:32 UTC (permalink / raw)
To: igt-dev; +Cc: Intel-gfx
From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Just a demo to follow the the i915 feature.
Tvrtko Ursulin (1):
intel-gpu-top: Support for client stats
tools/intel_gpu_top.c | 539 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 528 insertions(+), 11 deletions(-)
--
2.20.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 9+ messages in thread* [igt-dev] [RFC i-g-t 1/1] intel-gpu-top: Support for client stats 2020-03-09 18:32 [Intel-gfx] [RFC i-g-t 0/1] Per client intel_gpu_top Tvrtko Ursulin @ 2020-03-09 18:32 ` Tvrtko Ursulin 2020-03-10 13:04 ` [igt-dev] ✓ Fi.CI.BAT: success for Per client intel_gpu_top Patchwork 2020-03-10 16:43 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork 2 siblings, 0 replies; 9+ messages in thread From: Tvrtko Ursulin @ 2020-03-09 18:32 UTC (permalink / raw) To: igt-dev; +Cc: Intel-gfx, Tvrtko Ursulin From: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Adds support for per-client engine busyness stats i915 exports in sysfs and produces output like the below: ========================================================================== intel-gpu-top - 935/ 935 MHz; 0% RC6; 14.73 Watts; 1097 irqs/s IMC reads: 1401 MiB/s IMC writes: 4 MiB/s ENGINE BUSY MI_SEMA MI_WAIT Render/3D/0 63.73% |███████████████████ | 3% 0% Blitter/0 9.53% |██▊ | 6% 0% Video/0 39.32% |███████████▊ | 16% 0% Video/1 15.62% |████▋ | 0% 0% VideoEnhance/0 0.00% | | 0% 0% PID NAME RCS BCS VCS VECS 4084 gem_wsim |█████▌ ||█ || || | 4086 gem_wsim |█▌ || ||███ || | ========================================================================== Apart from the existing physical engine utilization it now also shows utilization per client and per engine class. v2: * Version to match removal of global enable_stats toggle. * Plus various fixes. v3: * Support brief backward jumps in client stats. Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> --- tools/intel_gpu_top.c | 539 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 528 insertions(+), 11 deletions(-) diff --git a/tools/intel_gpu_top.c b/tools/intel_gpu_top.c index 8197482dd6c2..3f8e14f4e8a9 100644 --- a/tools/intel_gpu_top.c +++ b/tools/intel_gpu_top.c @@ -659,23 +659,347 @@ 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[128]; + unsigned int samples; + unsigned long total; + struct engines *engines; + unsigned long *val; + uint64_t *last; +}; + +struct engine_class { + unsigned int class; + const char *name; + unsigned int num_engines; +}; + +struct clients { + unsigned int num_classes; + struct engine_class *class; + + unsigned int num_clients; + 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(void) +{ + struct clients *clients = malloc(sizeof(*clients)); + + return memset(clients, 0, sizeof(*clients)); +} + +#define SYSFS_CLIENTS "/sys/class/drm/card0/clients" + +static uint64_t read_client_busy(unsigned int id, unsigned int class) +{ + char buf[256]; + ssize_t ret; + + ret = snprintf(buf, sizeof(buf), + SYSFS_CLIENTS "/%u/busy/%u", + id, class); + assert(ret > 0 && ret < sizeof(buf)); + if (ret <= 0 || ret == sizeof(buf)) + return 0; + + return filename_to_u64(buf, 10); +} + +static struct client * +find_client(struct clients *clients, enum client_status status, unsigned int id) +{ + struct client *c; + int tmp; + + for_each_client(clients, 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->clients->num_classes]; + unsigned int i; + + if (c->pid != pid) + c->pid = pid; + + if (strcmp(c->name, name)) + strncpy(c->name, name, sizeof(c->name) - 1); + + for (i = 0; i < c->clients->num_classes; i++) + val[i] = read_client_busy(c->id, c->clients->class[i].class); + + c->total = 0; + + for (i = 0; i < c->clients->num_classes; i++) { + if (val[i] < c->last[i]) + continue; /* It will catch up soon. */ + + c->val[i] = val[i] - c->last[i]; + c->total += c->val[i]; + c->last[i] = val[i]; + } + + c->samples++; + c->status = ALIVE; +} + +static int class_cmp(const void *_a, const void *_b) +{ + const struct engine_class *a = _a; + const struct engine_class *b = _b; + + return a->class - b->class; +} + +static void scan_classes(struct clients *clients, unsigned int id) +{ + struct engine_class *classes; + unsigned int num, i; + struct dirent *dent; + char buf[256]; + int ret; + DIR *d; + + ret = snprintf(buf, sizeof(buf), SYSFS_CLIENTS "/%u/busy", id); + assert(ret > 0 && ret < sizeof(buf)); + if (ret <= 0 || ret == sizeof(buf)) + return; + + d = opendir(buf); + if (!d) + return; + +restart: + rewinddir(d); + + num = 0; + while ((dent = readdir(d)) != NULL) { + if (dent->d_type != DT_REG) + continue; + + num++; + } + + rewinddir(d); + + classes = calloc(num, sizeof(*classes)); + assert(classes); + + i = 0; + while ((dent = readdir(d)) != NULL) { + if (i > num) { + // FIXME: free individual names + free(classes); + goto restart; + } + + if (dent->d_type != DT_REG) + continue; + + classes[i].class = atoi(dent->d_name); + classes[i].name = class_display_name(classes[i].class); + i++; + } + + closedir(d); + + qsort(classes, num, sizeof(*classes), class_cmp); + + clients->num_classes = num; + clients->class = classes; +} + +static void +add_client(struct clients *clients, unsigned int id, unsigned int pid, + char *name) +{ + struct client *c; + + if (find_client(clients, ALIVE, id)) + return; + + c = find_client(clients, FREE, 0); + if (!c) { + unsigned int idx = clients->num_clients; + + clients->num_clients += (clients->num_clients + 2) / 2; + clients->client = realloc(clients->client, + clients->num_clients * sizeof(*c)); + assert(clients->client); + + c = &clients->client[idx]; + memset(c, 0, (clients->num_clients - idx) * sizeof(*c)); + } + + if (!clients->num_classes) + scan_classes(clients, id); + + c->id = id; + c->clients = clients; + c->val = calloc(clients->num_classes, sizeof(c->val)); + c->last = calloc(clients->num_classes, sizeof(c->last)); + assert(c->val && c->last); + + update_client(c, pid, name); +} + +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 < sizeof(buf)); + if (ret <= 0 || ret == sizeof(buf)) + return NULL; + + ret = filename_to_buf(buf, buf, sizeof(buf)); + if (ret) + return NULL; /* Client exited. */ + + return strdup(buf); +} + +static void scan_clients(struct clients *clients) +{ + struct dirent *dent; + struct client *c; + char *pid, *name; + unsigned int id; + int tmp; + DIR *d; + + if (!clients) + return; + + for_each_client(clients, c, tmp) { + if (c->status == ALIVE) + c->status = PROBE; + } + + d = opendir(SYSFS_CLIENTS); + if (!d) + return; + + while ((dent = readdir(d)) != NULL) { + if (dent->d_type != DT_DIR) + continue; + if (!isdigit(dent->d_name[0])) + continue; + + id = atoi(dent->d_name); + + c = find_client(clients, PROBE, id); + + name = read_client_sysfs(id, "name"); + pid = read_client_sysfs(id, "pid"); + + if (name && pid) { + if (!c) + add_client(clients, id, atoi(pid), name); + else + update_client(c, atoi(pid), name); + } else if (c) { + c->status = PROBE; /* Will be deleted below. */ + } + + if (name) + free(name); + if (pid) + free(pid); + } + + closedir(d); + + for_each_client(clients, 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; + + tot_a *= a->status == ALIVE && a->samples > 1; + tot_b *= b->status == ALIVE && b->samples > 1; + + tot_b -= tot_a; + + if (!tot_b) + return (int)b->id - a->id; + + while (tot_b > INT_MAX || tot_b < INT_MIN) + tot_b /= 2; + + return 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) { - int bar_len = percent * (8 * (max_len - 2)) / 100.0; - int i; + int bar_len, i, len = max_len - 2; + const int w = 8; + + assert(max_len > 0); + + bar_len = percent * (w * len) / 100.0; + if (bar_len > (len * w)) + bar_len = len * w; putchar('|'); - for (i = bar_len; i >= 8; i -= 8) - printf("%s", bars[8]); + for (i = bar_len; i >= w; i -= w) + printf("%s", bars[w]); if (i) printf("%s", bars[i]); - for (i = 0; i < (max_len - 2 - (bar_len + 7) / 8); i++) - putchar(' '); + len -= (bar_len + (w - 1)) / w; + n_spaces(len); putchar('|'); } @@ -775,6 +1099,18 @@ json_close_struct(void) fflush(stdout); } +static void +__json_add_member(const char *key, const char *val) +{ + assert(json_indent_level < ARRAY_SIZE(json_indent)); + + fprintf(out, "%s%s\"%s\": \"%s\"", + json_struct_members ? ",\n" : "", + json_indent[json_indent_level], key, val); + + json_struct_members++; +} + static unsigned int json_add_member(const struct cnt_group *parent, struct cnt_item *item, unsigned int headers) @@ -1075,8 +1411,6 @@ print_header(struct engines *engines, double t, memmove(&groups[0], &groups[1], sizeof(groups) - sizeof(groups[0])); - pops->open_struct(NULL); - *consumed = print_groups(groups); if (output_mode == INTERACTIVE) { @@ -1217,7 +1551,7 @@ print_engine(struct engines *engines, unsigned int i, double t, engine->display_name, engine_items[0].buf); val = pmu_calc(&engine->busy.val, 1e9, t, 100); - print_percentage_bar(val, max_w - len); + print_percentage_bar(val, max_w > len ? max_w - len : 0); printf("%s\n", buf); @@ -1232,7 +1566,6 @@ print_engines_footer(struct engines *engines, double t, int lines, int con_w, int con_h) { pops->close_struct(); - pops->close_struct(); if (output_mode == INTERACTIVE) { if (lines++ < con_h) @@ -1242,6 +1575,147 @@ print_engines_footer(struct engines *engines, double t, return lines; } +static int +print_clients_header(struct clients *clients, int lines, + int con_w, int con_h, int *class_w) +{ + int len; + + if (output_mode == INTERACTIVE) { + if (lines++ >= con_h) + return lines; + + printf("\033[7m"); + len = printf("%5s%16s", "PID", "NAME"); + + if (lines++ >= con_h || len >= con_w) + return lines; + + if (clients->num_classes) { + unsigned int i; + int width; + + *class_w = width = (con_w - len) / clients->num_classes; + + for (i = 0; i < clients->num_classes; i++) { + const char *name = clients->class[i].name; + int name_len = strlen(name); + int pad = (width - name_len) / 2; + int spaces = width - pad - name_len; + + if (pad < 0 || spaces < 0) + continue; + + n_spaces(pad); + printf("%s", name); + n_spaces(spaces); + len += pad + name_len + spaces; + } + } + + n_spaces(con_w - len); + printf("\033[0m\n"); + } else { + if (clients->num_classes) + pops->open_struct("clients"); + } + + return lines; +} + +static void count_engines(struct clients *clients, struct engines *engines) +{ + unsigned int i; + + for (i = 0; i < engines->num_engines; i++) { + struct engine *engine = engine_ptr(engines, i); + + clients->class[engine->class].num_engines++; + } +} + +static int +print_client(struct client *c, struct engines *engines, double t, int lines, + int con_w, int con_h, unsigned int period_us, int *class_w) +{ + struct clients *clients = c->clients; + unsigned int i; + + if (output_mode == INTERACTIVE) { + printf("%5u%16s ", c->pid, c->name); + + for (i = 0; i < clients->num_classes; i++) { + double pct; + + if (!clients->class[i].num_engines) + count_engines(clients, engines); + + pct = (double)c->val[i] / period_us / 1e3 * 100 / + clients->class[i].num_engines; + + /* + * Guard against possible time-drift between sampling + * client data and time we obtained our time-delta from + * PMU. + */ + if (pct > 100.0) + pct = 100.0; + + print_percentage_bar(pct, *class_w); + } + + putchar('\n'); + } else if (output_mode == JSON) { + char buf[64]; + + snprintf(buf, sizeof(buf), "%u", c->id); + pops->open_struct(buf); + + __json_add_member("name", c->name); + + snprintf(buf, sizeof(buf), "%u", c->pid); + __json_add_member("pid", buf); + + pops->open_struct("engine-classes"); + + for (i = 0; i < clients->num_classes; i++) { + double pct; + + snprintf(buf, sizeof(buf), "%s", + clients->class[i].name); + pops->open_struct(buf); + + pct = (double)c->val[i] / period_us / 1e3 * 100; + snprintf(buf, sizeof(buf), "%f", pct); + __json_add_member("busy", buf); + + __json_add_member("unit", "%"); + + pops->close_struct(); + } + + pops->close_struct(); + pops->close_struct(); + } + + return lines; +} + +static int +print_clients_footer(struct clients *clients, double t, + int lines, int con_w, int con_h) +{ + if (output_mode == INTERACTIVE) { + if (lines++ < con_h) + printf("\n"); + } else { + if (clients->num_classes) + pops->close_struct(); + } + + return lines; +} + static bool stop_top; static void sigint_handler(int sig) @@ -1252,6 +1726,7 @@ static void sigint_handler(int sig) int main(int argc, char **argv) { unsigned int period_us = DEFAULT_PERIOD_MS * 1000; + struct clients *clients = NULL; int con_w = -1, con_h = -1; char *output_path = NULL; struct engines *engines; @@ -1335,12 +1810,16 @@ int main(int argc, char **argv) return 1; } + clients = init_clients(); + pmu_sample(engines); + scan_clients(clients); while (!stop_top) { bool consumed = false; - int lines = 0; + int j, lines = 0; struct winsize ws; + struct client *c; double t; /* Update terminal size. */ @@ -1354,10 +1833,18 @@ int main(int argc, char **argv) pmu_sample(engines); t = (double)(engines->ts.cur - engines->ts.prev) / 1e9; + scan_clients(clients); + if (clients) { + qsort(clients->client, clients->num_clients, + sizeof(*clients->client), cmp); + } + if (stop_top) break; while (!consumed) { + pops->open_struct(NULL); + lines = print_header(engines, t, lines, con_w, con_h, &consumed); @@ -1376,6 +1863,36 @@ int main(int argc, char **argv) lines = print_engines_footer(engines, t, lines, con_w, con_h); + + if (clients) { + int class_w; + + lines = print_clients_header(clients, lines, + con_w, con_h, + &class_w); + + for_each_client(clients, c, j) { + if (lines++ > con_h) + break; + + assert(c->status != PROBE); + if (c->status != ALIVE) + break; + + if (c->samples < 2) + continue; + + lines = print_client(c, engines, t, + lines, con_w, + con_h, period_us, + &class_w); + } + + lines = print_clients_footer(clients, t, lines, + con_w, con_h); + } + + pops->close_struct(); } if (stop_top) -- 2.20.1 _______________________________________________ igt-dev mailing list igt-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/igt-dev ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [igt-dev] ✓ Fi.CI.BAT: success for Per client intel_gpu_top 2020-03-09 18:32 [Intel-gfx] [RFC i-g-t 0/1] Per client intel_gpu_top Tvrtko Ursulin 2020-03-09 18:32 ` [igt-dev] [RFC i-g-t 1/1] intel-gpu-top: Support for client stats Tvrtko Ursulin @ 2020-03-10 13:04 ` Patchwork 2020-03-10 16:43 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork 2 siblings, 0 replies; 9+ messages in thread From: Patchwork @ 2020-03-10 13:04 UTC (permalink / raw) To: Tvrtko Ursulin; +Cc: igt-dev == Series Details == Series: Per client intel_gpu_top URL : https://patchwork.freedesktop.org/series/74465/ State : success == Summary == CI Bug Log - changes from CI_DRM_8106 -> IGTPW_4283 ==================================================== Summary ------- **SUCCESS** No regressions found. External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/index.html Known issues ------------ Here are the changes found in IGTPW_4283 that come from known issues: ### IGT changes ### #### Issues hit #### * igt@gem_flink_basic@basic: - fi-tgl-y: [PASS][1] -> [DMESG-WARN][2] ([CI#94] / [i915#402]) +1 similar issue [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/fi-tgl-y/igt@gem_flink_basic@basic.html [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/fi-tgl-y/igt@gem_flink_basic@basic.html #### Possible fixes #### * igt@gem_flink_basic@bad-open: - fi-tgl-y: [DMESG-WARN][3] ([CI#94] / [i915#402]) -> [PASS][4] [3]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/fi-tgl-y/igt@gem_flink_basic@bad-open.html [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/fi-tgl-y/igt@gem_flink_basic@bad-open.html {name}: This element is suppressed. This means it is ignored when computing the status of the difference (SUCCESS, WARNING, or FAILURE). [CI#94]: https://gitlab.freedesktop.org/gfx-ci/i915-infra/issues/94 [i915#402]: https://gitlab.freedesktop.org/drm/intel/issues/402 [i915#998]: https://gitlab.freedesktop.org/drm/intel/issues/998 Participating hosts (44 -> 43) ------------------------------ Additional (5): fi-bdw-5557u fi-kbl-7500u fi-cfl-8109u fi-skl-6600u fi-snb-2600 Missing (6): fi-hsw-4200u fi-skl-6770hq fi-bsw-cyan fi-ctg-p8600 fi-byt-clapper fi-bdw-samus Build changes ------------- * CI: CI-20190529 -> None * IGT: IGT_5504 -> IGTPW_4283 CI-20190529: 20190529 CI_DRM_8106: 5b0076e8066ea8218e7857ee1aa28b0670acde94 @ git://anongit.freedesktop.org/gfx-ci/linux IGTPW_4283: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/index.html IGT_5504: d6788bf0404f76b66170e18eb26c85004b5ccb25 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools == Logs == For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/index.html _______________________________________________ igt-dev mailing list igt-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/igt-dev ^ permalink raw reply [flat|nested] 9+ messages in thread
* [igt-dev] ✓ Fi.CI.IGT: success for Per client intel_gpu_top 2020-03-09 18:32 [Intel-gfx] [RFC i-g-t 0/1] Per client intel_gpu_top Tvrtko Ursulin 2020-03-09 18:32 ` [igt-dev] [RFC i-g-t 1/1] intel-gpu-top: Support for client stats Tvrtko Ursulin 2020-03-10 13:04 ` [igt-dev] ✓ Fi.CI.BAT: success for Per client intel_gpu_top Patchwork @ 2020-03-10 16:43 ` Patchwork 2 siblings, 0 replies; 9+ messages in thread From: Patchwork @ 2020-03-10 16:43 UTC (permalink / raw) To: Tvrtko Ursulin; +Cc: igt-dev == Series Details == Series: Per client intel_gpu_top URL : https://patchwork.freedesktop.org/series/74465/ State : success == Summary == CI Bug Log - changes from CI_DRM_8106_full -> IGTPW_4283_full ==================================================== Summary ------- **SUCCESS** No regressions found. External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/index.html Possible new issues ------------------- Here are the unknown changes that may have been introduced in IGTPW_4283_full: ### IGT changes ### #### Suppressed #### The following results come from untrusted machines, tests, or statuses. They do not affect the overall result. * {igt@gem_userptr_blits@map-fixed-invalidate-busy@gtt}: - shard-hsw: [DMESG-WARN][1] ([i915#478]) -> [DMESG-WARN][2] [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-hsw4/igt@gem_userptr_blits@map-fixed-invalidate-busy@gtt.html [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-hsw2/igt@gem_userptr_blits@map-fixed-invalidate-busy@gtt.html Known issues ------------ Here are the changes found in IGTPW_4283_full that come from known issues: ### IGT changes ### #### Issues hit #### * igt@gem_ctx_isolation@vcs0-s3: - shard-kbl: [PASS][3] -> [DMESG-WARN][4] ([i915#180]) [3]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-kbl1/igt@gem_ctx_isolation@vcs0-s3.html [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-kbl1/igt@gem_ctx_isolation@vcs0-s3.html * igt@gem_ctx_isolation@vcs1-dirty-create: - shard-iclb: [PASS][5] -> [SKIP][6] ([fdo#112080]) +11 similar issues [5]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-iclb1/igt@gem_ctx_isolation@vcs1-dirty-create.html [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-iclb5/igt@gem_ctx_isolation@vcs1-dirty-create.html * igt@gem_ctx_persistence@engines-mixed-process@vecs0: - shard-tglb: [PASS][7] -> [FAIL][8] ([i915#679]) [7]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-tglb1/igt@gem_ctx_persistence@engines-mixed-process@vecs0.html [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-tglb3/igt@gem_ctx_persistence@engines-mixed-process@vecs0.html * igt@gem_exec_balancer@smoke: - shard-iclb: [PASS][9] -> [SKIP][10] ([fdo#110854]) [9]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-iclb1/igt@gem_exec_balancer@smoke.html [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-iclb5/igt@gem_exec_balancer@smoke.html * igt@gem_exec_schedule@implicit-read-write-bsd2: - shard-iclb: [PASS][11] -> [SKIP][12] ([fdo#109276] / [i915#677]) +1 similar issue [11]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-iclb4/igt@gem_exec_schedule@implicit-read-write-bsd2.html [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-iclb8/igt@gem_exec_schedule@implicit-read-write-bsd2.html * igt@gem_exec_schedule@pi-common-bsd: - shard-iclb: [PASS][13] -> [SKIP][14] ([i915#677]) +1 similar issue [13]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-iclb5/igt@gem_exec_schedule@pi-common-bsd.html [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-iclb4/igt@gem_exec_schedule@pi-common-bsd.html * igt@gem_exec_schedule@preempt-queue-bsd: - shard-iclb: [PASS][15] -> [SKIP][16] ([fdo#112146]) +4 similar issues [15]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-iclb6/igt@gem_exec_schedule@preempt-queue-bsd.html [16]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-iclb1/igt@gem_exec_schedule@preempt-queue-bsd.html * igt@gem_exec_schedule@preempt-queue-bsd1: - shard-iclb: [PASS][17] -> [SKIP][18] ([fdo#109276]) +12 similar issues [17]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-iclb1/igt@gem_exec_schedule@preempt-queue-bsd1.html [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-iclb5/igt@gem_exec_schedule@preempt-queue-bsd1.html * igt@gem_userptr_blits@dmabuf-unsync: - shard-hsw: [PASS][19] -> [DMESG-WARN][20] ([fdo#111870]) [19]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-hsw7/igt@gem_userptr_blits@dmabuf-unsync.html [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-hsw7/igt@gem_userptr_blits@dmabuf-unsync.html - shard-snb: [PASS][21] -> [DMESG-WARN][22] ([fdo#111870] / [i915#478]) [21]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-snb4/igt@gem_userptr_blits@dmabuf-unsync.html [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-snb4/igt@gem_userptr_blits@dmabuf-unsync.html * igt@gen9_exec_parse@allowed-all: - shard-glk: [PASS][23] -> [DMESG-WARN][24] ([i915#716]) [23]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-glk5/igt@gen9_exec_parse@allowed-all.html [24]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-glk1/igt@gen9_exec_parse@allowed-all.html * igt@i915_module_load@reload: - shard-tglb: [PASS][25] -> [INCOMPLETE][26] ([i915#1390]) [25]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-tglb2/igt@i915_module_load@reload.html [26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-tglb8/igt@i915_module_load@reload.html - shard-snb: [PASS][27] -> [INCOMPLETE][28] ([i915#82]) [27]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-snb2/igt@i915_module_load@reload.html [28]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-snb5/igt@i915_module_load@reload.html - shard-iclb: [PASS][29] -> [INCOMPLETE][30] ([i915#140]) [29]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-iclb8/igt@i915_module_load@reload.html [30]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-iclb8/igt@i915_module_load@reload.html - shard-kbl: [PASS][31] -> [INCOMPLETE][32] ([i915#1390]) [31]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-kbl2/igt@i915_module_load@reload.html [32]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-kbl7/igt@i915_module_load@reload.html - shard-hsw: [PASS][33] -> [INCOMPLETE][34] ([i915#1312] / [i915#61]) [33]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-hsw5/igt@i915_module_load@reload.html [34]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-hsw5/igt@i915_module_load@reload.html - shard-glk: [PASS][35] -> [INCOMPLETE][36] ([i915#1390] / [i915#58] / [k.org#198133]) [35]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-glk7/igt@i915_module_load@reload.html [36]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-glk5/igt@i915_module_load@reload.html - shard-apl: [PASS][37] -> [INCOMPLETE][38] ([fdo#103927] / [i915#1390]) [37]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-apl6/igt@i915_module_load@reload.html [38]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-apl3/igt@i915_module_load@reload.html * igt@i915_pm_rpm@modeset-lpsp: - shard-tglb: [PASS][39] -> [SKIP][40] ([i915#1316]) [39]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-tglb7/igt@i915_pm_rpm@modeset-lpsp.html [40]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-tglb8/igt@i915_pm_rpm@modeset-lpsp.html - shard-iclb: [PASS][41] -> [SKIP][42] ([i915#1316]) [41]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-iclb5/igt@i915_pm_rpm@modeset-lpsp.html [42]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-iclb3/igt@i915_pm_rpm@modeset-lpsp.html * igt@kms_color@pipe-a-ctm-blue-to-red: - shard-apl: [PASS][43] -> [FAIL][44] ([i915#129]) [43]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-apl3/igt@kms_color@pipe-a-ctm-blue-to-red.html [44]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-apl3/igt@kms_color@pipe-a-ctm-blue-to-red.html * igt@kms_cursor_crc@pipe-b-cursor-64x64-sliding: - shard-apl: [PASS][45] -> [FAIL][46] ([i915#54]) +1 similar issue [45]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-apl1/igt@kms_cursor_crc@pipe-b-cursor-64x64-sliding.html [46]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-apl2/igt@kms_cursor_crc@pipe-b-cursor-64x64-sliding.html - shard-kbl: [PASS][47] -> [FAIL][48] ([i915#54]) +1 similar issue [47]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-kbl7/igt@kms_cursor_crc@pipe-b-cursor-64x64-sliding.html [48]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-kbl6/igt@kms_cursor_crc@pipe-b-cursor-64x64-sliding.html * igt@kms_flip@flip-vs-expired-vblank: - shard-glk: [PASS][49] -> [FAIL][50] ([i915#79]) [49]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-glk5/igt@kms_flip@flip-vs-expired-vblank.html [50]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-glk7/igt@kms_flip@flip-vs-expired-vblank.html * igt@kms_flip@flip-vs-suspend: - shard-apl: [PASS][51] -> [DMESG-WARN][52] ([i915#180]) [51]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-apl8/igt@kms_flip@flip-vs-suspend.html [52]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-apl2/igt@kms_flip@flip-vs-suspend.html * igt@kms_frontbuffer_tracking@fbc-1p-primscrn-cur-indfb-onoff: - shard-apl: [PASS][53] -> [FAIL][54] ([i915#49]) [53]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-apl1/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-cur-indfb-onoff.html [54]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-apl3/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-cur-indfb-onoff.html - shard-kbl: [PASS][55] -> [FAIL][56] ([i915#49]) [55]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-kbl4/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-cur-indfb-onoff.html [56]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-kbl2/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-cur-indfb-onoff.html * igt@kms_plane_lowres@pipe-a-tiling-y: - shard-glk: [PASS][57] -> [FAIL][58] ([i915#899]) [57]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-glk9/igt@kms_plane_lowres@pipe-a-tiling-y.html [58]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-glk7/igt@kms_plane_lowres@pipe-a-tiling-y.html * igt@kms_psr2_su@frontbuffer: - shard-iclb: [PASS][59] -> [SKIP][60] ([fdo#109642] / [fdo#111068]) [59]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-iclb2/igt@kms_psr2_su@frontbuffer.html [60]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-iclb4/igt@kms_psr2_su@frontbuffer.html * igt@kms_psr@psr2_cursor_render: - shard-iclb: [PASS][61] -> [SKIP][62] ([fdo#109441]) +1 similar issue [61]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-iclb2/igt@kms_psr@psr2_cursor_render.html [62]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-iclb6/igt@kms_psr@psr2_cursor_render.html * igt@kms_setmode@basic: - shard-apl: [PASS][63] -> [FAIL][64] ([i915#31]) [63]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-apl1/igt@kms_setmode@basic.html [64]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-apl4/igt@kms_setmode@basic.html #### Possible fixes #### * igt@gem_ctx_isolation@rcs0-s3: - shard-kbl: [DMESG-WARN][65] ([i915#180]) -> [PASS][66] +2 similar issues [65]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-kbl1/igt@gem_ctx_isolation@rcs0-s3.html [66]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-kbl4/igt@gem_ctx_isolation@rcs0-s3.html * igt@gem_ctx_persistence@processes: - shard-kbl: [FAIL][67] ([i915#570] / [i915#679]) -> [PASS][68] [67]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-kbl2/igt@gem_ctx_persistence@processes.html [68]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-kbl7/igt@gem_ctx_persistence@processes.html * igt@gem_exec_balancer@hang: - shard-tglb: [FAIL][69] ([i915#1277]) -> [PASS][70] [69]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-tglb1/igt@gem_exec_balancer@hang.html [70]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-tglb6/igt@gem_exec_balancer@hang.html * igt@gem_exec_schedule@implicit-both-bsd: - shard-iclb: [SKIP][71] ([i915#677]) -> [PASS][72] +1 similar issue [71]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-iclb4/igt@gem_exec_schedule@implicit-both-bsd.html [72]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-iclb6/igt@gem_exec_schedule@implicit-both-bsd.html * igt@gem_exec_schedule@implicit-both-bsd2: - shard-iclb: [SKIP][73] ([fdo#109276] / [i915#677]) -> [PASS][74] [73]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-iclb7/igt@gem_exec_schedule@implicit-both-bsd2.html [74]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-iclb2/igt@gem_exec_schedule@implicit-both-bsd2.html * igt@gem_exec_schedule@preempt-other-chain-bsd: - shard-iclb: [SKIP][75] ([fdo#112146]) -> [PASS][76] +6 similar issues [75]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-iclb4/igt@gem_exec_schedule@preempt-other-chain-bsd.html [76]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-iclb6/igt@gem_exec_schedule@preempt-other-chain-bsd.html * igt@gem_exec_whisper@basic-queues-forked: - shard-glk: [DMESG-WARN][77] ([i915#118] / [i915#95]) -> [PASS][78] +1 similar issue [77]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-glk2/igt@gem_exec_whisper@basic-queues-forked.html [78]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-glk1/igt@gem_exec_whisper@basic-queues-forked.html * igt@i915_suspend@sysfs-reader: - shard-snb: [DMESG-WARN][79] ([i915#42]) -> [PASS][80] [79]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-snb4/igt@i915_suspend@sysfs-reader.html [80]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-snb2/igt@i915_suspend@sysfs-reader.html * igt@kms_cursor_crc@pipe-b-cursor-64x64-offscreen: - shard-apl: [FAIL][81] ([i915#54]) -> [PASS][82] [81]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-apl6/igt@kms_cursor_crc@pipe-b-cursor-64x64-offscreen.html [82]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-apl4/igt@kms_cursor_crc@pipe-b-cursor-64x64-offscreen.html * igt@kms_flip@2x-flip-vs-expired-vblank-interruptible: - shard-glk: [FAIL][83] ([i915#79]) -> [PASS][84] [83]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-glk9/igt@kms_flip@2x-flip-vs-expired-vblank-interruptible.html [84]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-glk1/igt@kms_flip@2x-flip-vs-expired-vblank-interruptible.html * igt@kms_flip@flip-vs-suspend-interruptible: - shard-kbl: [DMESG-WARN][85] ([i915#180] / [i915#56]) -> [PASS][86] [85]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-kbl1/igt@kms_flip@flip-vs-suspend-interruptible.html [86]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-kbl2/igt@kms_flip@flip-vs-suspend-interruptible.html * igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a: - shard-kbl: [INCOMPLETE][87] -> [PASS][88] [87]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-kbl2/igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a.html [88]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-kbl3/igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a.html * igt@kms_plane_multiple@atomic-pipe-c-tiling-x: - shard-hsw: [DMESG-WARN][89] ([i915#478]) -> [PASS][90] [89]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-hsw7/igt@kms_plane_multiple@atomic-pipe-c-tiling-x.html [90]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-hsw5/igt@kms_plane_multiple@atomic-pipe-c-tiling-x.html * igt@kms_psr2_su@page_flip: - shard-iclb: [SKIP][91] ([fdo#109642] / [fdo#111068]) -> [PASS][92] [91]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-iclb1/igt@kms_psr2_su@page_flip.html [92]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-iclb2/igt@kms_psr2_su@page_flip.html * igt@kms_psr@psr2_dpms: - shard-iclb: [SKIP][93] ([fdo#109441]) -> [PASS][94] +1 similar issue [93]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-iclb5/igt@kms_psr@psr2_dpms.html [94]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-iclb2/igt@kms_psr@psr2_dpms.html * igt@kms_setmode@basic: - shard-kbl: [FAIL][95] ([i915#31]) -> [PASS][96] [95]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-kbl7/igt@kms_setmode@basic.html [96]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-kbl1/igt@kms_setmode@basic.html * igt@kms_vblank@pipe-a-ts-continuation-suspend: - shard-apl: [DMESG-WARN][97] ([i915#180]) -> [PASS][98] +1 similar issue [97]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-apl1/igt@kms_vblank@pipe-a-ts-continuation-suspend.html [98]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-apl3/igt@kms_vblank@pipe-a-ts-continuation-suspend.html * igt@perf_pmu@busy-vcs1: - shard-iclb: [SKIP][99] ([fdo#112080]) -> [PASS][100] +12 similar issues [99]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-iclb7/igt@perf_pmu@busy-vcs1.html [100]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-iclb4/igt@perf_pmu@busy-vcs1.html * igt@prime_busy@hang-bsd2: - shard-iclb: [SKIP][101] ([fdo#109276]) -> [PASS][102] +18 similar issues [101]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-iclb5/igt@prime_busy@hang-bsd2.html [102]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-iclb4/igt@prime_busy@hang-bsd2.html * igt@prime_vgem@basic-gtt: - shard-snb: [DMESG-WARN][103] ([i915#478]) -> [PASS][104] [103]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-snb4/igt@prime_vgem@basic-gtt.html [104]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-snb4/igt@prime_vgem@basic-gtt.html #### Warnings #### * igt@gem_linear_blits@normal: - shard-apl: [TIMEOUT][105] ([i915#1322]) -> [TIMEOUT][106] ([fdo#111732] / [i915#1322]) [105]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-apl4/igt@gem_linear_blits@normal.html [106]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-apl8/igt@gem_linear_blits@normal.html * igt@gem_userptr_blits@dmabuf-sync: - shard-snb: [DMESG-WARN][107] ([fdo#110789] / [fdo#111870] / [i915#478]) -> [DMESG-WARN][108] ([fdo#111870] / [i915#478]) [107]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-snb6/igt@gem_userptr_blits@dmabuf-sync.html [108]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-snb4/igt@gem_userptr_blits@dmabuf-sync.html - shard-hsw: [DMESG-WARN][109] ([fdo#110789] / [fdo#111870]) -> [DMESG-WARN][110] ([fdo#111870]) [109]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-hsw8/igt@gem_userptr_blits@dmabuf-sync.html [110]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-hsw5/igt@gem_userptr_blits@dmabuf-sync.html * igt@i915_pm_rpm@fences: - shard-snb: [INCOMPLETE][111] ([i915#82]) -> [SKIP][112] ([fdo#109271]) [111]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-snb4/igt@i915_pm_rpm@fences.html [112]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-snb2/igt@i915_pm_rpm@fences.html * igt@runner@aborted: - shard-hsw: ([FAIL][113], [FAIL][114], [FAIL][115], [FAIL][116], [FAIL][117], [FAIL][118], [FAIL][119], [FAIL][120], [FAIL][121]) ([fdo#111870]) -> ([FAIL][122], [FAIL][123], [FAIL][124], [FAIL][125], [FAIL][126], [FAIL][127], [FAIL][128], [FAIL][129], [FAIL][130]) ([fdo#111870] / [k.org#204565]) [113]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-hsw1/igt@runner@aborted.html [114]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-hsw1/igt@runner@aborted.html [115]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-hsw4/igt@runner@aborted.html [116]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-hsw7/igt@runner@aborted.html [117]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-hsw8/igt@runner@aborted.html [118]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-hsw4/igt@runner@aborted.html [119]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-hsw5/igt@runner@aborted.html [120]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-hsw4/igt@runner@aborted.html [121]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-hsw7/igt@runner@aborted.html [122]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-hsw5/igt@runner@aborted.html [123]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-hsw7/igt@runner@aborted.html [124]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-hsw1/igt@runner@aborted.html [125]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-hsw8/igt@runner@aborted.html [126]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-hsw2/igt@runner@aborted.html [127]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-hsw5/igt@runner@aborted.html [128]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-hsw2/igt@runner@aborted.html [129]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-hsw5/igt@runner@aborted.html [130]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-hsw2/igt@runner@aborted.html - shard-kbl: ([FAIL][131], [FAIL][132]) ([i915#1389] / [i915#1402] / [i915#92]) -> ([FAIL][133], [FAIL][134], [FAIL][135]) ([i915#1389] / [i915#1402] / [i915#92] / [k.org#204565]) [131]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-kbl7/igt@runner@aborted.html [132]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-kbl4/igt@runner@aborted.html [133]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-kbl7/igt@runner@aborted.html [134]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-kbl4/igt@runner@aborted.html [135]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-kbl3/igt@runner@aborted.html - shard-apl: ([FAIL][136], [FAIL][137]) ([fdo#103927] / [i915#1402]) -> ([FAIL][138], [FAIL][139]) ([i915#1402] / [k.org#204565]) [136]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-apl1/igt@runner@aborted.html [137]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-apl2/igt@runner@aborted.html [138]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-apl8/igt@runner@aborted.html [139]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-apl3/igt@runner@aborted.html - shard-glk: [FAIL][140] ([i915#1402] / [k.org#202321]) -> ([FAIL][141], [FAIL][142], [FAIL][143]) ([i915#1402] / [k.org#202321] / [k.org#204565]) [140]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-glk6/igt@runner@aborted.html [141]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-glk2/igt@runner@aborted.html [142]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-glk1/igt@runner@aborted.html [143]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-glk5/igt@runner@aborted.html - shard-snb: ([FAIL][144], [FAIL][145], [FAIL][146], [FAIL][147], [FAIL][148], [FAIL][149], [FAIL][150], [FAIL][151], [FAIL][152]) ([fdo#111870] / [i915#1077]) -> ([FAIL][153], [FAIL][154], [FAIL][155], [FAIL][156], [FAIL][157], [FAIL][158], [FAIL][159], [FAIL][160], [FAIL][161]) ([fdo#111870] / [i915#1077] / [k.org#204565]) [144]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-snb6/igt@runner@aborted.html [145]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-snb4/igt@runner@aborted.html [146]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-snb6/igt@runner@aborted.html [147]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-snb2/igt@runner@aborted.html [148]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-snb5/igt@runner@aborted.html [149]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-snb5/igt@runner@aborted.html [150]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-snb6/igt@runner@aborted.html [151]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-snb6/igt@runner@aborted.html [152]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8106/shard-snb4/igt@runner@aborted.html [153]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-snb6/igt@runner@aborted.html [154]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-snb5/igt@runner@aborted.html [155]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-snb6/igt@runner@aborted.html [156]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-snb4/igt@runner@aborted.html [157]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-snb4/igt@runner@aborted.html [158]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-snb4/igt@runner@aborted.html [159]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-snb4/igt@runner@aborted.html [160]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-snb6/igt@runner@aborted.html [161]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/shard-snb4/igt@runner@aborted.html {name}: This element is suppressed. This means it is ignored when computing the status of the difference (SUCCESS, WARNING, or FAILURE). [fdo#103927]: https://bugs.freedesktop.org/show_bug.cgi?id=103927 [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271 [fdo#109276]: https://bugs.freedesktop.org/show_bug.cgi?id=109276 [fdo#109441]: https://bugs.freedesktop.org/show_bug.cgi?id=109441 [fdo#109642]: https://bugs.freedesktop.org/show_bug.cgi?id=109642 [fdo#110789]: https://bugs.freedesktop.org/show_bug.cgi?id=110789 [fdo#110854]: https://bugs.freedesktop.org/show_bug.cgi?id=110854 [fdo#111068]: https://bugs.freedesktop.org/show_bug.cgi?id=111068 [fdo#111732]: https://bugs.freedesktop.org/show_bug.cgi?id=111732 [fdo#111870]: https://bugs.freedesktop.org/show_bug.cgi?id=111870 [fdo#112080]: https://bugs.freedesktop.org/show_bug.cgi?id=112080 [fdo#112146]: https://bugs.freedesktop.org/show_bug.cgi?id=112146 [i915#1077]: https://gitlab.freedesktop.org/drm/intel/issues/1077 [i915#118]: https://gitlab.freedesktop.org/drm/intel/issues/118 [i915#1277]: https://gitlab.freedesktop.org/drm/intel/issues/1277 [i915#129]: https://gitlab.freedesktop.org/drm/intel/issues/129 [i915#1312]: https://gitlab.freedesktop.org/drm/intel/issues/1312 [i915#1316]: https://gitlab.freedesktop.org/drm/intel/issues/1316 [i915#1322]: https://gitlab.freedesktop.org/drm/intel/issues/1322 [i915#1389]: https://gitlab.freedesktop.org/drm/intel/issues/1389 [i915#1390]: https://gitlab.freedesktop.org/drm/intel/issues/1390 [i915#140]: https://gitlab.freedesktop.org/drm/intel/issues/140 [i915#1402]: https://gitlab.freedesktop.org/drm/intel/issues/1402 [i915#180]: https://gitlab.freedesktop.org/drm/intel/issues/180 [i915#31]: https://gitlab.freedesktop.org/drm/intel/issues/31 [i915#42]: https://gitlab.freedesktop.org/drm/intel/issues/42 [i915#478]: https://gitlab.freedesktop.org/drm/intel/issues/478 [i915#49]: https://gitlab.freedesktop.org/drm/intel/issues/49 [i915#54]: https://gitlab.freedesktop.org/drm/intel/issues/54 [i915#56]: https://gitlab.freedesktop.org/drm/intel/issues/56 [i915#570]: https://gitlab.freedesktop.org/drm/intel/issues/570 [i915#58]: https://gitlab.freedesktop.org/drm/intel/issues/58 [i915#61]: https://gitlab.freedesktop.org/drm/intel/issues/61 [i915#677]: https://gitlab.freedesktop.org/drm/intel/issues/677 [i915#679]: https://gitlab.freedesktop.org/drm/intel/issues/679 [i915#716]: https://gitlab.freedesktop.org/drm/intel/issues/716 [i915#79]: https://gitlab.freedesktop.org/drm/intel/issues/79 [i915#82]: https://gitlab.freedesktop.org/drm/intel/issues/82 [i915#899]: https://gitlab.freedesktop.org/drm/intel/issues/899 [i915#92]: https://gitlab.freedesktop.org/drm/intel/issues/92 [i915#95]: https://gitlab.freedesktop.org/drm/intel/issues/95 [k.org#198133]: https://bugzilla.kernel.org/show_bug.cgi?id=198133 [k.org#202321]: https://bugzilla.kernel.org/show_bug.cgi?id=202321 [k.org#204565]: https://bugzilla.kernel.org/show_bug.cgi?id=204565 Participating hosts (10 -> 8) ------------------------------ Missing (2): pig-skl-6260u pig-glk-j5005 Build changes ------------- * CI: CI-20190529 -> None * IGT: IGT_5504 -> IGTPW_4283 * Piglit: piglit_4509 -> None CI-20190529: 20190529 CI_DRM_8106: 5b0076e8066ea8218e7857ee1aa28b0670acde94 @ git://anongit.freedesktop.org/gfx-ci/linux IGTPW_4283: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/index.html IGT_5504: d6788bf0404f76b66170e18eb26c85004b5ccb25 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit == Logs == For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_4283/index.html _______________________________________________ igt-dev mailing list igt-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/igt-dev ^ permalink raw reply [flat|nested] 9+ messages in thread
* [igt-dev] [RFC i-g-t 0/1] Per client engine busyness @ 2019-10-25 14:24 Tvrtko Ursulin 2019-10-25 14:24 ` [igt-dev] [RFC i-g-t 1/1] intel-gpu-top: Support for client stats Tvrtko Ursulin 0 siblings, 1 reply; 9+ messages in thread From: Tvrtko Ursulin @ 2019-10-25 14:24 UTC (permalink / raw) To: igt-dev; +Cc: Intel-gfx, Tvrtko Ursulin From: Tvrtko Ursulin <tvrtko.ursulin@intel.com> intel_gpu_top counterpart for the equally named i915 series. For reference only at this stage. Tvrtko Ursulin (1): intel-gpu-top: Support for client stats tools/intel_gpu_top.c | 590 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 584 insertions(+), 6 deletions(-) -- 2.20.1 _______________________________________________ igt-dev mailing list igt-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/igt-dev ^ permalink raw reply [flat|nested] 9+ messages in thread
* [igt-dev] [RFC i-g-t 1/1] intel-gpu-top: Support for client stats 2019-10-25 14:24 [igt-dev] [RFC i-g-t 0/1] Per client engine busyness Tvrtko Ursulin @ 2019-10-25 14:24 ` Tvrtko Ursulin 2019-10-25 15:13 ` Chris Wilson 0 siblings, 1 reply; 9+ messages in thread From: Tvrtko Ursulin @ 2019-10-25 14:24 UTC (permalink / raw) To: igt-dev; +Cc: Intel-gfx, Tvrtko Ursulin From: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Adds support for per-client engine busyness stats i915 exports in sysfs and produces output like the below: ========================================================================== intel-gpu-top - 935/ 935 MHz; 0% RC6; 14.73 Watts; 1097 irqs/s IMC reads: 1401 MiB/s IMC writes: 4 MiB/s ENGINE BUSY MI_SEMA MI_WAIT Render/3D/0 63.73% |███████████████████ | 3% 0% Blitter/0 9.53% |██▊ | 6% 0% Video/0 39.32% |███████████▊ | 16% 0% Video/1 15.62% |████▋ | 0% 0% VideoEnhance/0 0.00% | | 0% 0% PID NAME RCS BCS VCS VECS 4084 gem_wsim |█████▌ ||█ || || | 4086 gem_wsim |█▌ || ||███ || | ========================================================================== Apart from the existing physical engine utilization it now also shows utilization per client and per engine class. Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> --- tools/intel_gpu_top.c | 590 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 584 insertions(+), 6 deletions(-) diff --git a/tools/intel_gpu_top.c b/tools/intel_gpu_top.c index cc8db7c539ed..50e9c153329a 100644 --- a/tools/intel_gpu_top.c +++ b/tools/intel_gpu_top.c @@ -659,8 +659,403 @@ 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[128]; + unsigned int samples; + unsigned long total; + struct engines *engines; + unsigned long *val; + uint64_t *last; +}; + +struct engine_class { + unsigned int class; + const char *name; + unsigned int num_engines; +}; + +struct clients { + unsigned int num_classes; + struct engine_class *class; + + unsigned int num_clients; + struct client *client; +}; + +#define for_each_client(clients, c, tmp) \ + for ((tmp) = (clients)->num_clients, c = (clients)->client; \ + (tmp > 0); (tmp)--, (c)++) + +#define SYSFS_ENABLE "/sys/class/drm/card0/clients/enable_stats" + +bool __stats_enabled; + +static int __set_stats(bool val) +{ + int fd, ret; + + fd = open(SYSFS_ENABLE, O_WRONLY); + if (fd < 0) + return -errno; + + ret = write(fd, val ? "1" : "0", 2); + if (ret < 0) + return -errno; + else if (ret < 2) + return 1; + + close(fd); + + return 0; +} + +static void __restore_stats(void) +{ + int ret; + + if (__stats_enabled) + return; + + ret = __set_stats(false); + if (ret) + fprintf(stderr, "Failed to disable per-client stats! (%d)\n", + ret); +} + +static void __restore_stats_signal(int sig) +{ + exit(0); +} + +static int enable_stats(void) +{ + int fd, ret; + + fd = open(SYSFS_ENABLE, O_RDONLY); + if (fd < 0) + return -errno; + + close(fd); + + __stats_enabled = filename_to_u64(SYSFS_ENABLE, 10); + if (__stats_enabled) + return 0; + + ret = __set_stats(true); + if (!ret) { + if (atexit(__restore_stats)) + fprintf(stderr, "Failed to register exit handler!"); + + if (signal(SIGINT, __restore_stats_signal)) + fprintf(stderr, "Failed to register signal handler!"); + } else { + fprintf(stderr, "Failed to enable per-client stats! (%d)\n", + ret); + } + + return ret; +} + +static struct clients *init_clients(void) +{ + struct clients *clients = malloc(sizeof(*clients)); + + if (enable_stats()) { + free(clients); + return NULL; + } + + return memset(clients, 0, sizeof(*clients)); +} + +#define SYSFS_CLIENTS "/sys/class/drm/card0/clients" + +static uint64_t read_client_busy(unsigned int id, unsigned int class) +{ + char buf[256]; + ssize_t ret; + + ret = snprintf(buf, sizeof(buf), + SYSFS_CLIENTS "/%u/busy/%u", + id, class); + assert(ret > 0 && ret < sizeof(buf)); + if (ret <= 0 || ret == sizeof(buf)) + return 0; + + return filename_to_u64(buf, 10); +} + +static struct client * +find_client(struct clients *clients, enum client_status status, unsigned int id) +{ + struct client *c; + int tmp; + + for_each_client(clients, 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->clients->num_classes]; + 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->clients->num_classes; i++) + val[i] = read_client_busy(c->id, c->clients->class[i].class); + + c->total = 0; + + for (i = 0; i < c->clients->num_classes; 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 int class_cmp(const void *_a, const void *_b) +{ + const struct engine_class *a = _a; + const struct engine_class *b = _b; + + return a->class - b->class; +} + +static void scan_classes(struct clients *clients, unsigned int id) +{ + struct engine_class *classes; + unsigned int num, i; + struct dirent *dent; + char buf[256]; + int ret; + DIR *d; + + ret = snprintf(buf, sizeof(buf), SYSFS_CLIENTS "/%u/busy", id); + assert(ret > 0 && ret < sizeof(buf)); + if (ret <= 0 || ret == sizeof(buf)) + return; + + d = opendir(buf); + if (!d) + return; + +restart: + rewinddir(d); + + num = 0; + while ((dent = readdir(d)) != NULL) { + if (dent->d_type != DT_REG) + continue; + + num++; + } + + rewinddir(d); + + classes = calloc(num, sizeof(*classes)); + assert(classes); + + i = 0; + while ((dent = readdir(d)) != NULL) { + if (i > num) { + // FIXME: free individual names + free(classes); + goto restart; + } + + if (dent->d_type != DT_REG) + continue; + + classes[i].class = atoi(dent->d_name); + classes[i].name = class_short_name(classes[i].class); + i++; + } + + closedir(d); + + qsort(classes, num, sizeof(*classes), class_cmp); + + clients->num_classes = num; + clients->class = classes; +} + +static void +add_client(struct clients *clients, unsigned int id, unsigned int pid, + char *name) +{ + struct client *c; + + assert(!find_client(clients, ALIVE, id)); + + c = find_client(clients, FREE, 0); + if (!c) { + unsigned int idx = clients->num_clients; + + clients->num_clients += (clients->num_clients + 2) / 2; + clients->client = realloc(clients->client, + clients->num_clients * sizeof(*c)); + assert(clients->client); + + c = &clients->client[idx]; + memset(c, 0, (clients->num_clients - idx) * sizeof(*c)); + } + + if (!clients->num_classes) + scan_classes(clients, id); + + c->id = id; + c->clients = clients; + c->val = calloc(clients->num_classes, sizeof(c->val)); + c->last = calloc(clients->num_classes, sizeof(c->last)); + assert(c->val && c->last); + + update_client(c, pid, name); +} + +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 < sizeof(buf)); + if (ret <= 0 || ret == sizeof(buf)) + return NULL; + + ret = filename_to_buf(buf, buf, sizeof(buf)); + assert(ret == 0); + if (ret) + return NULL; + + return strdup(buf); +} + +static void scan_clients(struct clients *clients) +{ + struct dirent *dent; + struct client *c; + char *pid, *name; + unsigned int id; + int tmp; + DIR *d; + + if (!clients) + return; + + for_each_client(clients, c, tmp) { + if (c->status == ALIVE) + c->status = PROBE; + } + + d = opendir(SYSFS_CLIENTS); + if (!d) + return; + + 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); + if (!name) + continue; + + pid = read_client_sysfs(id, "pid"); + assert(pid); + if (!pid) { + free(name); + continue; + } + + c = find_client(clients, PROBE, id); + if (c) { + update_client(c, atoi(pid), name); + continue; + } + + add_client(clients, id, atoi(pid), name); + + free(name); + free(pid); + } + + closedir(d); + + for_each_client(clients, 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; + + tot_a *= a->status == ALIVE && a->samples > 1; + tot_b *= b->status == ALIVE && b->samples > 1; + + tot_b -= tot_a; + + if (!tot_b) + return (int)b->id - a->id; + + while (tot_b > INT_MAX || tot_b < INT_MIN) + tot_b /= 2; + + return 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) { @@ -674,8 +1069,10 @@ 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(' '); + bar_len = max_len - 2 - (bar_len + 7) / 8; + if (bar_len > max_len) + bar_len = max_len; + n_spaces(bar_len); putchar('|'); } @@ -775,6 +1172,18 @@ json_close_struct(void) fflush(stdout); } +static void +__json_add_member(const char *key, const char *val) +{ + assert(json_indent_level < ARRAY_SIZE(json_indent)); + + fprintf(out, "%s%s\"%s\": \"%s\"", + json_struct_members ? ",\n" : "", + json_indent[json_indent_level], key, val); + + json_struct_members++; +} + static unsigned int json_add_member(const struct cnt_group *parent, struct cnt_item *item, unsigned int headers) @@ -1075,8 +1484,6 @@ print_header(struct engines *engines, double t, memmove(&groups[0], &groups[1], sizeof(groups) - sizeof(groups[0])); - pops->open_struct(NULL); - *consumed = print_groups(groups); if (output_mode == INTERACTIVE) { @@ -1232,7 +1639,6 @@ print_engines_footer(struct engines *engines, double t, int lines, int con_w, int con_h) { pops->close_struct(); - pops->close_struct(); if (output_mode == INTERACTIVE) { if (lines++ < con_h) @@ -1242,6 +1648,136 @@ print_engines_footer(struct engines *engines, double t, return lines; } +static int +print_clients_header(struct clients *clients, int lines, + int con_w, int con_h, unsigned int *class_w) +{ + int len; + + if (output_mode == INTERACTIVE) { + if (lines++ >= con_h) + return lines; + + printf("\033[7m"); + len = printf("%5s%16s", "PID", "NAME"); + + if (lines++ >= con_h) + return lines; + + if (clients->num_classes) { + unsigned int i; + + *class_w = (con_w - len) / clients->num_classes; + + for (i = 0; i < clients->num_classes; i++) { + unsigned int name_len = + strlen(clients->class[i].name); + unsigned int pad = (*class_w - name_len) / 2; + + n_spaces(pad); + printf("%s", clients->class[i].name); + n_spaces(*class_w - pad - name_len); + len += pad + name_len + + (*class_w - pad - name_len); + } + } + + n_spaces(con_w - len); + printf("\033[0m\n"); + } else { + if (clients->num_classes) + pops->open_struct("clients"); + } + + return lines; +} + +static void count_engines(struct clients *clients, struct engines *engines) +{ + unsigned int i; + + for (i = 0; i < engines->num_engines; i++) { + struct engine *engine = engine_ptr(engines, i); + + clients->class[engine->class].num_engines++; + } +} + +static int +print_client(struct client *c, struct engines *engines, double t, int lines, + int con_w, int con_h, unsigned int period_us, + unsigned int *class_w) +{ + struct clients *clients = c->clients; + unsigned int i; + + if (output_mode == INTERACTIVE) { + printf("%5u%16s ", c->pid, c->name); + + for (i = 0; i < clients->num_classes; i++) { + double pct; + + if (!clients->class[i].num_engines) + count_engines(clients, engines); + + pct = (double)c->val[i] / period_us / 1e3 * 100 / + clients->class[i].num_engines; + + print_percentage_bar(pct, *class_w); + } + + putchar('\n'); + } else if (output_mode == JSON) { + char buf[64]; + + snprintf(buf, sizeof(buf), "%u", c->id); + pops->open_struct(buf); + + __json_add_member("name", c->name); + + snprintf(buf, sizeof(buf), "%u", c->pid); + __json_add_member("pid", buf); + + pops->open_struct("engine-classes"); + + for (i = 0; i < clients->num_classes; i++) { + double pct; + + snprintf(buf, sizeof(buf), "%s", + clients->class[i].name); + pops->open_struct(buf); + + pct = (double)c->val[i] / period_us / 1e3 * 100; + snprintf(buf, sizeof(buf), "%f", pct); + __json_add_member("busy", buf); + + __json_add_member("unit", "%"); + + pops->close_struct(); + } + + pops->close_struct(); + pops->close_struct(); + } + + return lines; +} + +static int +print_clients_footer(struct clients *clients, double t, + int lines, int con_w, int con_h) +{ + if (output_mode == INTERACTIVE) { + if (lines++ < con_h) + printf("\n"); + } else { + if (clients->num_classes) + pops->close_struct(); + } + + return lines; +} + static bool stop_top; static void sigint_handler(int sig) @@ -1252,6 +1788,7 @@ static void sigint_handler(int sig) int main(int argc, char **argv) { unsigned int period_us = DEFAULT_PERIOD_MS * 1000; + struct clients *clients = NULL; int con_w = -1, con_h = -1; char *output_path = NULL; struct engines *engines; @@ -1335,12 +1872,17 @@ int main(int argc, char **argv) return 1; } + clients = init_clients(); + pmu_sample(engines); + scan_clients(clients); while (!stop_top) { bool consumed = false; - int lines = 0; + int j, lines = 0; + unsigned int class_w; struct winsize ws; + struct client *c; double t; /* Update terminal size. */ @@ -1354,10 +1896,18 @@ int main(int argc, char **argv) pmu_sample(engines); t = (double)(engines->ts.cur - engines->ts.prev) / 1e9; + scan_clients(clients); + if (clients) { + qsort(clients->client, clients->num_clients, + sizeof(*clients->client), cmp); + } + if (stop_top) break; while (!consumed) { + pops->open_struct(NULL); + lines = print_header(engines, t, lines, con_w, con_h, &consumed); @@ -1376,6 +1926,34 @@ int main(int argc, char **argv) lines = print_engines_footer(engines, t, lines, con_w, con_h); + + if (clients) { + lines = print_clients_header(clients, lines, + con_w, con_h, + &class_w); + + for_each_client(clients, c, j) { + if (lines++ > con_h) + break; + + assert(c->status != PROBE); + if (c->status != ALIVE) + break; + + if (c->samples < 2) + continue; + + lines = print_client(c, engines, t, + lines, con_w, + con_h, period_us, + &class_w); + } + + lines = print_clients_footer(clients, t, lines, + con_w, con_h); + } + + pops->close_struct(); } if (stop_top) -- 2.20.1 _______________________________________________ igt-dev mailing list igt-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/igt-dev ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [igt-dev] [RFC i-g-t 1/1] intel-gpu-top: Support for client stats 2019-10-25 14:24 ` [igt-dev] [RFC i-g-t 1/1] intel-gpu-top: Support for client stats Tvrtko Ursulin @ 2019-10-25 15:13 ` Chris Wilson 2019-10-25 15:38 ` Tvrtko Ursulin 0 siblings, 1 reply; 9+ messages in thread From: Chris Wilson @ 2019-10-25 15:13 UTC (permalink / raw) To: Tvrtko Ursulin, igt-dev; +Cc: Intel-gfx, Tvrtko Ursulin Quoting Tvrtko Ursulin (2019-10-25 15:24:10) > From: Tvrtko Ursulin <tvrtko.ursulin@intel.com> > > Adds support for per-client engine busyness stats i915 exports in sysfs > and produces output like the below: > > ========================================================================== > intel-gpu-top - 935/ 935 MHz; 0% RC6; 14.73 Watts; 1097 irqs/s Could we get "gpu / pkg Watts" pretty please? Are irq/s interesting with execlists? Originally the idea was to say how many times clients were sleeping and being woken up. Now we interrupt to wipe the gpu's nose when it sneezes. > > IMC reads: 1401 MiB/s > IMC writes: 4 MiB/s > > ENGINE BUSY MI_SEMA MI_WAIT > Render/3D/0 63.73% |███████████████████ | 3% 0% > Blitter/0 9.53% |██▊ | 6% 0% > Video/0 39.32% |███████████▊ | 16% 0% > Video/1 15.62% |████▋ | 0% 0% > VideoEnhance/0 0.00% | | 0% 0% > > PID NAME RCS BCS VCS VECS > 4084 gem_wsim |█████▌ ||█ || || | > 4086 gem_wsim |█▌ || ||███ || | > ========================================================================== > > Apart from the existing physical engine utilization it now also shows > utilization per client and per engine class. > > Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> > --- > +#define SYSFS_CLIENTS "/sys/class/drm/card0/clients" We need to somehow pull the right card. Nothing shocking here. Where's the intel-gpu-overlay integration? ;) -Chris _______________________________________________ igt-dev mailing list igt-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/igt-dev ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [igt-dev] [RFC i-g-t 1/1] intel-gpu-top: Support for client stats 2019-10-25 15:13 ` Chris Wilson @ 2019-10-25 15:38 ` Tvrtko Ursulin 0 siblings, 0 replies; 9+ messages in thread From: Tvrtko Ursulin @ 2019-10-25 15:38 UTC (permalink / raw) To: Chris Wilson, igt-dev; +Cc: Intel-gfx, Tvrtko Ursulin On 25/10/2019 16:13, Chris Wilson wrote: > Quoting Tvrtko Ursulin (2019-10-25 15:24:10) >> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com> >> >> Adds support for per-client engine busyness stats i915 exports in sysfs >> and produces output like the below: >> >> ========================================================================== >> intel-gpu-top - 935/ 935 MHz; 0% RC6; 14.73 Watts; 1097 irqs/s > > Could we get "gpu / pkg Watts" pretty please? Sure, next week or so. > Are irq/s interesting with execlists? Originally the idea was to say how > many times clients were sleeping and being woken up. Now we interrupt > to wipe the gpu's nose when it sneezes. > >> >> IMC reads: 1401 MiB/s >> IMC writes: 4 MiB/s >> >> ENGINE BUSY MI_SEMA MI_WAIT >> Render/3D/0 63.73% |███████████████████ | 3% 0% >> Blitter/0 9.53% |██▊ | 6% 0% >> Video/0 39.32% |███████████▊ | 16% 0% >> Video/1 15.62% |████▋ | 0% 0% >> VideoEnhance/0 0.00% | | 0% 0% >> >> PID NAME RCS BCS VCS VECS >> 4084 gem_wsim |█████▌ ||█ || || | >> 4086 gem_wsim |█▌ || ||███ || | >> ========================================================================== >> >> Apart from the existing physical engine utilization it now also shows >> utilization per client and per engine class. >> >> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> >> --- > >> +#define SYSFS_CLIENTS "/sys/class/drm/card0/clients" > > We need to somehow pull the right card. Yeah, as I said RFC and reference only. :) > Nothing shocking here. Where's the intel-gpu-overlay integration? ;) Maybe intel-gpu-overlay should become an output plugin for intel_gpu_top. :) Regards, Tvrtko _______________________________________________ igt-dev mailing list igt-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/igt-dev ^ permalink raw reply [flat|nested] 9+ messages in thread
* [igt-dev] [RFC i-g-t 0/1] intel_gpu_top: Per-client engine busyness
@ 2019-05-10 13:23 Tvrtko Ursulin
2019-05-10 13:23 ` [igt-dev] [RFC i-g-t 1/1] intel-gpu-top: Support for client stats Tvrtko Ursulin
0 siblings, 1 reply; 9+ messages in thread
From: Tvrtko Ursulin @ 2019-05-10 13:23 UTC (permalink / raw)
To: igt-dev; +Cc: Intel-gfx, Tvrtko Ursulin
From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Extension to intel_gpu_top which uses the corresponding sysfs interface proposal
to implement per client and per class engine utilization view. Example output:
==========================================================================
intel-gpu-top - 935/ 935 MHz; 0% RC6; 14.73 Watts; 1097 irqs/s
IMC reads: 1401 MiB/s
IMC writes: 4 MiB/s
ENGINE BUSY MI_SEMA MI_WAIT
Render/3D/0 63.73% |███████████████████ | 3% 0%
Blitter/0 9.53% |██▊ | 6% 0%
Video/0 39.32% |███████████▊ | 16% 0%
Video/1 15.62% |████▋ | 0% 0%
VideoEnhance/0 0.00% | | 0% 0%
PID NAME RCS BCS VCS VECS
4084 gem_wsim |█████▌ ||█ || || |
4086 gem_wsim |█▌ || ||███ || |
==========================================================================
Tvrtko Ursulin (1):
intel-gpu-top: Support for client stats
tools/intel_gpu_top.c | 590 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 584 insertions(+), 6 deletions(-)
--
2.19.1
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev
^ permalink raw reply [flat|nested] 9+ messages in thread* [igt-dev] [RFC i-g-t 1/1] intel-gpu-top: Support for client stats 2019-05-10 13:23 [igt-dev] [RFC i-g-t 0/1] intel_gpu_top: Per-client engine busyness Tvrtko Ursulin @ 2019-05-10 13:23 ` Tvrtko Ursulin 2019-05-10 15:33 ` Chris Wilson 0 siblings, 1 reply; 9+ messages in thread From: Tvrtko Ursulin @ 2019-05-10 13:23 UTC (permalink / raw) To: igt-dev; +Cc: Intel-gfx, Tvrtko Ursulin From: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Adds support for per-client engine busyness stats i915 exports in sysfs and produces output like the below: ========================================================================== intel-gpu-top - 935/ 935 MHz; 0% RC6; 14.73 Watts; 1097 irqs/s IMC reads: 1401 MiB/s IMC writes: 4 MiB/s ENGINE BUSY MI_SEMA MI_WAIT Render/3D/0 63.73% |███████████████████ | 3% 0% Blitter/0 9.53% |██▊ | 6% 0% Video/0 39.32% |███████████▊ | 16% 0% Video/1 15.62% |████▋ | 0% 0% VideoEnhance/0 0.00% | | 0% 0% PID NAME RCS BCS VCS VECS 4084 gem_wsim |█████▌ ||█ || || | 4086 gem_wsim |█▌ || ||███ || | ========================================================================== Apart from the existing physical engine utilization it now also shows utilization per client and per engine class. Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> --- tools/intel_gpu_top.c | 590 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 584 insertions(+), 6 deletions(-) diff --git a/tools/intel_gpu_top.c b/tools/intel_gpu_top.c index cc8db7c539ed..88e1ad52d17c 100644 --- a/tools/intel_gpu_top.c +++ b/tools/intel_gpu_top.c @@ -659,8 +659,403 @@ 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[128]; + unsigned int samples; + unsigned long total; + struct engines *engines; + unsigned long *val; + uint64_t *last; +}; + +struct engine_class { + unsigned int class; + const char *name; + unsigned int num_engines; +}; + +struct clients { + unsigned int num_classes; + struct engine_class *class; + + unsigned int num_clients; + struct client *client; +}; + +#define for_each_client(clients, c, tmp) \ + for ((tmp) = (clients)->num_clients, c = (clients)->client; \ + (tmp > 0); (tmp)--, (c)++) + +#define SYSFS_ENABLE "/sys/class/drm/card0/clients/enable_stats" + +bool __stats_enabled; + +static int __set_stats(bool val) +{ + int fd, ret; + + fd = open(SYSFS_ENABLE, O_WRONLY); + if (fd < 0) + return -errno; + + ret = write(fd, val ? "1" : "0", 2); + if (ret < 0) + return -errno; + else if (ret < 2) + return 1; + + close(fd); + + return 0; +} + +static void __restore_stats(void) +{ + int ret; + + if (__stats_enabled) + return; + + ret = __set_stats(false); + if (ret) + fprintf(stderr, "Failed to disable per-client stats! (%d)\n", + ret); +} + +static void __restore_stats_signal(int sig) +{ + exit(0); +} + +static int enable_stats(void) +{ + int fd, ret; + + fd = open(SYSFS_ENABLE, O_RDONLY); + if (fd < 0) + return -errno; + + close(fd); + + __stats_enabled = filename_to_u64(SYSFS_ENABLE, 10); + if (__stats_enabled) + return 0; + + ret = __set_stats(true); + if (!ret) { + if (atexit(__restore_stats)) + fprintf(stderr, "Failed to register exit handler!"); + + if (signal(SIGINT, __restore_stats_signal)) + fprintf(stderr, "Failed to register signal handler!"); + } else { + fprintf(stderr, "Failed to enable per-client stats! (%d)\n", + ret); + } + + return ret; +} + +static struct clients *init_clients(void) +{ + struct clients *clients = malloc(sizeof(*clients)); + + if (enable_stats()) { + free(clients); + return NULL; + } + + return memset(clients, 0, sizeof(*clients)); +} + +#define SYSFS_CLIENTS "/sys/class/drm/card0/clients" + +static uint64_t read_client_busy(unsigned int id, unsigned int class) +{ + char buf[256]; + ssize_t ret; + + ret = snprintf(buf, sizeof(buf), + SYSFS_CLIENTS "/%u/busy/%u", + id, class); + assert(ret > 0 && ret < sizeof(buf)); + if (ret <= 0 || ret == sizeof(buf)) + return 0; + + return filename_to_u64(buf, 10); +} + +static struct client * +find_client(struct clients *clients, enum client_status status, unsigned int id) +{ + struct client *c; + int tmp; + + for_each_client(clients, 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->clients->num_classes]; + 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->clients->num_classes; i++) + val[i] = read_client_busy(c->id, c->clients->class[i].class); + + c->total = 0; + + for (i = 0; i < c->clients->num_classes; 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 int class_cmp(const void *_a, const void *_b) +{ + const struct engine_class *a = _a; + const struct engine_class *b = _b; + + return a->class - b->class; +} + +static void scan_classes(struct clients *clients, unsigned int id) +{ + struct engine_class *classes; + unsigned int num, i; + struct dirent *dent; + char buf[256]; + int ret; + DIR *d; + + ret = snprintf(buf, sizeof(buf), SYSFS_CLIENTS "/%u/busy", id); + assert(ret > 0 && ret < sizeof(buf)); + if (ret <= 0 || ret == sizeof(buf)) + return; + + d = opendir(buf); + if (!d) + return; + +restart: + rewinddir(d); + + num = 0; + while ((dent = readdir(d)) != NULL) { + if (dent->d_type != DT_REG) + continue; + + num++; + } + + rewinddir(d); + + classes = calloc(num, sizeof(*classes)); + assert(classes); + + i = 0; + while ((dent = readdir(d)) != NULL) { + if (i > num) { + // FIXME: free individual names + free(classes); + goto restart; + } + + if (dent->d_type != DT_REG) + continue; + + classes[i].class = atoi(dent->d_name); + classes[i].name = class_short_name(classes[i].class); + i++; + } + + closedir(d); + + qsort(classes, num, sizeof(*classes), class_cmp); + + clients->num_classes = num; + clients->class = classes; +} + +static void +add_client(struct clients *clients, unsigned int id, unsigned int pid, + char *name) +{ + struct client *c; + + assert(!find_client(clients, ALIVE, id)); + + c = find_client(clients, FREE, 0); + if (!c) { + unsigned int idx = clients->num_clients; + + clients->num_clients += (clients->num_clients + 2) / 2; + clients->client = realloc(clients->client, + clients->num_clients * sizeof(*c)); + assert(clients->client); + + c = &clients->client[idx]; + memset(c, 0, (clients->num_clients - idx) * sizeof(*c)); + } + + if (!clients->num_classes) + scan_classes(clients, id); + + c->id = id; + c->clients = clients; + c->val = calloc(clients->num_classes, sizeof(c->val)); + c->last = calloc(clients->num_classes, sizeof(c->last)); + assert(c->val && c->last); + + update_client(c, pid, name); +} + +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 < sizeof(buf)); + if (ret <= 0 || ret == sizeof(buf)) + return NULL; + + ret = filename_to_buf(buf, buf, sizeof(buf)); + assert(ret == 0); + if (ret) + return NULL; + + return strdup(buf); +} + +static void scan_clients(struct clients *clients) +{ + struct dirent *dent; + struct client *c; + char *pid, *name; + unsigned int id; + int tmp; + DIR *d; + + if (!clients) + return; + + for_each_client(clients, c, tmp) { + if (c->status == ALIVE) + c->status = PROBE; + } + + d = opendir(SYSFS_CLIENTS); + if (!d) + return; + + 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); + if (!name) + continue; + + pid = read_client_sysfs(id, "pid"); + assert(pid); + if (!pid) { + free(name); + continue; + } + + c = find_client(clients, PROBE, id); + if (c) { + update_client(c, atoi(pid), name); + continue; + } + + add_client(clients, id, atoi(pid), name); + + free(name); + free(pid); + } + + closedir(d); + + for_each_client(clients, 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; + + tot_a *= a->status == ALIVE && a->samples > 1; + tot_b *= b->status == ALIVE && b->samples > 1; + + tot_b -= tot_a; + + if (!tot_b) + return (int)b->id - a->id; + + while (tot_b > INT_MAX || tot_b < INT_MIN) + tot_b /= 2; + + return 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) { @@ -674,8 +1069,10 @@ 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(' '); + bar_len = max_len - 2 - (bar_len + 7) / 8; + if (bar_len > max_len) + bar_len = max_len; + n_spaces(bar_len); putchar('|'); } @@ -775,6 +1172,18 @@ json_close_struct(void) fflush(stdout); } +static void +__json_add_member(const char *key, const char *val) +{ + assert(json_indent_level < ARRAY_SIZE(json_indent)); + + fprintf(out, "%s%s\"%s\": \"%s\"", + json_struct_members ? ",\n" : "", + json_indent[json_indent_level], key, val); + + json_struct_members++; +} + static unsigned int json_add_member(const struct cnt_group *parent, struct cnt_item *item, unsigned int headers) @@ -1075,8 +1484,6 @@ print_header(struct engines *engines, double t, memmove(&groups[0], &groups[1], sizeof(groups) - sizeof(groups[0])); - pops->open_struct(NULL); - *consumed = print_groups(groups); if (output_mode == INTERACTIVE) { @@ -1232,7 +1639,6 @@ print_engines_footer(struct engines *engines, double t, int lines, int con_w, int con_h) { pops->close_struct(); - pops->close_struct(); if (output_mode == INTERACTIVE) { if (lines++ < con_h) @@ -1242,6 +1648,136 @@ print_engines_footer(struct engines *engines, double t, return lines; } +static int +print_clients_header(struct clients *clients, int lines, + int con_w, int con_h, unsigned int *class_w) +{ + int len; + + if (output_mode == INTERACTIVE) { + if (lines++ >= con_h) + return lines; + + printf("\033[7m"); + len = printf("%5s%16s", "PID", "NAME"); + + if (lines++ >= con_h) + return lines; + + if (clients->num_classes) { + unsigned int i; + + *class_w = (con_w - len) / clients->num_classes; + + for (i = 0; i < clients->num_classes; i++) { + unsigned int name_len = + strlen(clients->class[i].name); + unsigned int pad = (*class_w - name_len) / 2; + + n_spaces(pad); + printf("%s", clients->class[i].name); + n_spaces(*class_w - pad - name_len); + len += pad + name_len + + (*class_w - pad - name_len); + } + } + + n_spaces(con_w - len); + printf("\033[0m\n"); + } else { + if (clients->num_classes) + pops->open_struct("clients"); + } + + return lines; +} + +static void count_engines(struct clients *clients, struct engines *engines) +{ + unsigned int i; + + for (i = 0; i < engines->num_engines; i++) { + struct engine *engine = engine_ptr(engines, i); + + clients->class[engine->class].num_engines++; + } +} + +static int +print_client(struct client *c, struct engines *engines, double t, int lines, + int con_w, int con_h, unsigned int period_us, + unsigned int *class_w) +{ + struct clients *clients = c->clients; + unsigned int i; + + if (output_mode == INTERACTIVE) { + printf("%5u%16s ", c->pid, c->name); + + for (i = 0; i < clients->num_classes; i++) { + double pct; + + if (!clients->class[i].num_engines) + count_engines(clients, engines); + + pct = (double)c->val[i] / period_us / 1e3 * 100 / + clients->class[i].num_engines; + + print_percentage_bar(pct, *class_w); + } + + putchar('\n'); + } else if (output_mode == JSON) { + char buf[64]; + + snprintf(buf, sizeof(buf), "%u", c->id); + pops->open_struct(buf); + + __json_add_member("name", c->name); + + snprintf(buf, sizeof(buf), "%u", c->pid); + __json_add_member("pid", buf); + + pops->open_struct("engine-classes"); + + for (i = 0; i < clients->num_classes; i++) { + double pct; + + snprintf(buf, sizeof(buf), "%s", + clients->class[i].name); + pops->open_struct(buf); + + pct = (double)c->val[i] / period_us / 1e3 * 100; + snprintf(buf, sizeof(buf), "%f", pct); + __json_add_member("busy", buf); + + __json_add_member("unit", "%"); + + pops->close_struct(); + } + + pops->close_struct(); + pops->close_struct(); + } + + return lines; +} + +static int +print_clients_footer(struct clients *clients, double t, + int lines, int con_w, int con_h) +{ + if (output_mode == INTERACTIVE) { + if (lines++ < con_h) + printf("\n"); + } else { + if (clients->num_classes) + pops->close_struct(); + } + + return lines; +} + static bool stop_top; static void sigint_handler(int sig) @@ -1252,6 +1788,7 @@ static void sigint_handler(int sig) int main(int argc, char **argv) { unsigned int period_us = DEFAULT_PERIOD_MS * 1000; + struct clients *clients = NULL; int con_w = -1, con_h = -1; char *output_path = NULL; struct engines *engines; @@ -1335,12 +1872,17 @@ int main(int argc, char **argv) return 1; } + clients = init_clients(); + pmu_sample(engines); + scan_clients(clients); while (!stop_top) { bool consumed = false; - int lines = 0; + int j, lines = 0; + unsigned int class_w; struct winsize ws; + struct client *c; double t; /* Update terminal size. */ @@ -1354,10 +1896,18 @@ int main(int argc, char **argv) pmu_sample(engines); t = (double)(engines->ts.cur - engines->ts.prev) / 1e9; + scan_clients(clients); + if (clients) { + qsort(&clients->client, clients->num_clients, + sizeof(clients->client), cmp); + } + if (stop_top) break; while (!consumed) { + pops->open_struct(NULL); + lines = print_header(engines, t, lines, con_w, con_h, &consumed); @@ -1376,6 +1926,34 @@ int main(int argc, char **argv) lines = print_engines_footer(engines, t, lines, con_w, con_h); + + if (clients) { + lines = print_clients_header(clients, lines, + con_w, con_h, + &class_w); + + for_each_client(clients, c, j) { + if (lines++ > con_h) + break; + + assert(c->status != PROBE); + if (c->status != ALIVE) + break; + + if (c->samples < 2) + continue; + + lines = print_client(c, engines, t, + lines, con_w, + con_h, period_us, + &class_w); + } + + lines = print_clients_footer(clients, t, lines, + con_w, con_h); + } + + pops->close_struct(); } if (stop_top) -- 2.19.1 _______________________________________________ igt-dev mailing list igt-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/igt-dev ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [igt-dev] [RFC i-g-t 1/1] intel-gpu-top: Support for client stats 2019-05-10 13:23 ` [igt-dev] [RFC i-g-t 1/1] intel-gpu-top: Support for client stats Tvrtko Ursulin @ 2019-05-10 15:33 ` Chris Wilson 0 siblings, 0 replies; 9+ messages in thread From: Chris Wilson @ 2019-05-10 15:33 UTC (permalink / raw) To: Tvrtko Ursulin, igt-dev; +Cc: Intel-gfx, Tvrtko Ursulin Quoting Tvrtko Ursulin (2019-05-10 14:23:12) > From: Tvrtko Ursulin <tvrtko.ursulin@intel.com> > > Adds support for per-client engine busyness stats i915 exports in sysfs > and produces output like the below: > > ========================================================================== > intel-gpu-top - 935/ 935 MHz; 0% RC6; 14.73 Watts; 1097 irqs/s > > IMC reads: 1401 MiB/s > IMC writes: 4 MiB/s > > ENGINE BUSY MI_SEMA MI_WAIT > Render/3D/0 63.73% |███████████████████ | 3% 0% > Blitter/0 9.53% |██▊ | 6% 0% > Video/0 39.32% |███████████▊ | 16% 0% > Video/1 15.62% |████▋ | 0% 0% > VideoEnhance/0 0.00% | | 0% 0% > > PID NAME RCS BCS VCS VECS > 4084 gem_wsim |█████▌ ||█ || || | > 4086 gem_wsim |█▌ || ||███ || | > ========================================================================== > > Apart from the existing physical engine utilization it now also shows > utilization per client and per engine class. > > Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> > --- > tools/intel_gpu_top.c | 590 +++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 584 insertions(+), 6 deletions(-) > > diff --git a/tools/intel_gpu_top.c b/tools/intel_gpu_top.c > index cc8db7c539ed..88e1ad52d17c 100644 > --- a/tools/intel_gpu_top.c > +++ b/tools/intel_gpu_top.c > @@ -659,8 +659,403 @@ 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[128]; > + unsigned int samples; > + unsigned long total; > + struct engines *engines; > + unsigned long *val; > + uint64_t *last; > +}; > + > +struct engine_class { > + unsigned int class; > + const char *name; > + unsigned int num_engines; > +}; > + > +struct clients { > + unsigned int num_classes; > + struct engine_class *class; > + > + unsigned int num_clients; > + struct client *client; > +}; > + > +#define for_each_client(clients, c, tmp) \ > + for ((tmp) = (clients)->num_clients, c = (clients)->client; \ > + (tmp > 0); (tmp)--, (c)++) > + > +#define SYSFS_ENABLE "/sys/class/drm/card0/clients/enable_stats" > + > +bool __stats_enabled; > + > +static int __set_stats(bool val) > +{ > + int fd, ret; > + > + fd = open(SYSFS_ENABLE, O_WRONLY); > + if (fd < 0) > + return -errno; > + > + ret = write(fd, val ? "1" : "0", 2); close(fd); Might as well still be tidy on error when it's trivial to do so. > + if (ret < 0) > + return -errno; > + else if (ret < 2) > + return 1; > + > + close(fd); > + > + return 0; > +} > + > +static void __restore_stats(void) > +{ > + int ret; > + > + if (__stats_enabled) > + return; > + > + ret = __set_stats(false); > + if (ret) > + fprintf(stderr, "Failed to disable per-client stats! (%d)\n", > + ret); > +} > + > +static void __restore_stats_signal(int sig) > +{ > + exit(0); > +} > + > +static int enable_stats(void) > +{ > + int fd, ret; > + > + fd = open(SYSFS_ENABLE, O_RDONLY); > + if (fd < 0) > + return -errno; > + > + close(fd); > + > + __stats_enabled = filename_to_u64(SYSFS_ENABLE, 10); > + if (__stats_enabled) > + return 0; > + > + ret = __set_stats(true); > + if (!ret) { > + if (atexit(__restore_stats)) > + fprintf(stderr, "Failed to register exit handler!"); > + > + if (signal(SIGINT, __restore_stats_signal)) > + fprintf(stderr, "Failed to register signal handler!"); That really suggests an alternative mechanism where the stats are only active for as long as the open(sysfs/stats) is. However, iirc, sysfs doesn't allow us to hook into the open! In which case we could hook into the write, and keep it enabled for as long as the user write("1") until the fd is closed. Food for thought, I hope you convince me we don't need optional stats in the first place :) > + } else { > + fprintf(stderr, "Failed to enable per-client stats! (%d)\n", > + ret); > + } > + > + return ret; > +} > + > +static struct clients *init_clients(void) > +{ > + struct clients *clients = malloc(sizeof(*clients)); We purport this to be a user-facing tool, it should generally avoid nasty errors. > + > + if (enable_stats()) { > + free(clients); > + return NULL; > + } > + > + return memset(clients, 0, sizeof(*clients)); > +} > + > +#define SYSFS_CLIENTS "/sys/class/drm/card0/clients" We need to detect which cardN. Which turns into scan all possible dirents. > +static uint64_t read_client_busy(unsigned int id, unsigned int class) > +{ > + char buf[256]; > + ssize_t ret; > + > + ret = snprintf(buf, sizeof(buf), > + SYSFS_CLIENTS "/%u/busy/%u", > + id, class); > + assert(ret > 0 && ret < sizeof(buf)); > + if (ret <= 0 || ret == sizeof(buf)) > + return 0; > + > + return filename_to_u64(buf, 10); > +} > + > +static struct client * > +find_client(struct clients *clients, enum client_status status, unsigned int id) > +{ > + struct client *c; > + int tmp; > + > + for_each_client(clients, c, tmp) { > + if ((status == FREE && c->status == FREE) || > + (status == c->status && c->id == id)) > + return c; 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[c->clients->num_classes]; > + 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->clients->num_classes; i++) > + val[i] = read_client_busy(c->id, c->clients->class[i].class); > + > + c->total = 0; > + > + for (i = 0; i < c->clients->num_classes; 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]; Where's the normalisation for capacity? Ok, later on, but only for interactive conversion to %%. What about json output, how do they know capacity? Wait.. json is using %% as well without scaling for num_engines. Should we not say timestamp the sampling and compute the % here? -Chris _______________________________________________ igt-dev mailing list igt-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/igt-dev ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2020-03-10 16:43 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2020-03-09 18:32 [Intel-gfx] [RFC i-g-t 0/1] Per client intel_gpu_top Tvrtko Ursulin 2020-03-09 18:32 ` [igt-dev] [RFC i-g-t 1/1] intel-gpu-top: Support for client stats Tvrtko Ursulin 2020-03-10 13:04 ` [igt-dev] ✓ Fi.CI.BAT: success for Per client intel_gpu_top Patchwork 2020-03-10 16:43 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork -- strict thread matches above, loose matches on Subject: below -- 2019-10-25 14:24 [igt-dev] [RFC i-g-t 0/1] Per client engine busyness Tvrtko Ursulin 2019-10-25 14:24 ` [igt-dev] [RFC i-g-t 1/1] intel-gpu-top: Support for client stats Tvrtko Ursulin 2019-10-25 15:13 ` Chris Wilson 2019-10-25 15:38 ` Tvrtko Ursulin 2019-05-10 13:23 [igt-dev] [RFC i-g-t 0/1] intel_gpu_top: Per-client engine busyness Tvrtko Ursulin 2019-05-10 13:23 ` [igt-dev] [RFC i-g-t 1/1] intel-gpu-top: Support for client stats Tvrtko Ursulin 2019-05-10 15:33 ` Chris Wilson
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox