From: Tvrtko Ursulin <tvrtko.ursulin@xxxxxxxxx> Similarly to how top(1) handles SMP, we can default to showing engines of a same class as a single bar graph entry. To achieve this a little bit of hackery is employed. PMU sampling is left as is and only at the presentation layer we create a fake set of engines, one for each class, summing and normalizing the load respectively. Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@xxxxxxxxx> --- man/intel_gpu_top.rst | 1 + tools/intel_gpu_top.c | 192 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 180 insertions(+), 13 deletions(-) diff --git a/man/intel_gpu_top.rst b/man/intel_gpu_top.rst index 2e0c3a05acc1..35ab10da9bb4 100644 --- a/man/intel_gpu_top.rst +++ b/man/intel_gpu_top.rst @@ -54,6 +54,7 @@ RUNTIME CONTROL Supported keys: 'q' Exit from the tool. + '1' Toggle between aggregated engine class and physical engine mode. DEVICE SELECTION ================ diff --git a/tools/intel_gpu_top.c b/tools/intel_gpu_top.c index 68911940f1d0..8c4280aa19b9 100644 --- a/tools/intel_gpu_top.c +++ b/tools/intel_gpu_top.c @@ -76,8 +76,16 @@ struct engine { struct pmu_counter sema; }; +struct engine_class { + unsigned int class; + const char *name; + unsigned int num_engines; +}; + struct engines { unsigned int num_engines; + unsigned int num_classes; + struct engine_class *class; unsigned int num_counters; DIR *root; int fd; @@ -1118,6 +1126,8 @@ print_imc(struct engines *engines, double t, int lines, int con_w, int con_h) return lines; } +static bool class_view; + static int print_engines_header(struct engines *engines, double t, int lines, int con_w, int con_h) @@ -1133,8 +1143,13 @@ print_engines_header(struct engines *engines, double t, pops->open_struct("engines"); if (output_mode == INTERACTIVE) { - const char *a = " ENGINE BUSY "; const char *b = " MI_SEMA MI_WAIT"; + const char *a; + + if (class_view) + a = " ENGINES BUSY "; + else + a = " ENGINE BUSY "; printf("\033[7m%s%*s%s\033[0m\n", a, (int)(con_w - 1 - strlen(a) - strlen(b)), @@ -1214,6 +1229,164 @@ print_engines_footer(struct engines *engines, double t, return lines; } +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 init_engine_classes(struct engines *engines) +{ + struct engine_class *classes; + unsigned int i, num; + int max = -1; + + for (i = 0; i < engines->num_engines; i++) { + struct engine *engine = engine_ptr(engines, i); + + if ((int)engine->class > max) + max = engine->class; + } + assert(max >= 0); + + num = max + 1; + + classes = calloc(num, sizeof(*classes)); + assert(classes); + + for (i = 0; i < engines->num_engines; i++) { + struct engine *engine = engine_ptr(engines, i); + + classes[engine->class].num_engines++; + } + + for (i = 0; i < num; i++) { + classes[i].class = i; + classes[i].name = class_display_name(i); + } + + qsort(classes, num, sizeof(*classes), class_cmp); + + engines->num_classes = num; + engines->class = classes; +} + +static void __pmu_sum(struct pmu_pair *dst, struct pmu_pair *src) +{ + dst->prev += src->prev; + dst->cur += src->cur; +} + +static void __pmu_normalize(struct pmu_pair *val, unsigned int n) +{ + val->prev /= n; + val->cur /= n; +} + +static struct engines *init_classes(struct engines *engines) +{ + struct engines *classes; + unsigned int i, j; + + init_engine_classes(engines); + + classes = calloc(1, sizeof(struct engines) + + engines->num_classes * sizeof(struct engine)); + assert(classes); + + classes->num_engines = engines->num_classes; + classes->num_classes = engines->num_classes; + classes->class = engines->class; + + for (i = 0; i < engines->num_classes; i++) { + struct engine *engine = engine_ptr(classes, i); + + engine->class = i; + engine->instance = -1; + + if (!engines->class[i].num_engines) + continue; + + engine->display_name = strdup(class_display_name(i)); + assert(engine->display_name); + engine->short_name = strdup(class_short_name(i)); + assert(engine->short_name); + + for (j = 0; j < engines->num_engines; j++) { + struct engine *e = engine_ptr(engines, j); + + if (e->class == i) { + engine->num_counters = e->num_counters; + engine->busy = e->busy; + engine->sema = e->sema; + engine->wait = e->wait; + } + } + } + + return classes; +} + +static struct engines * +update_classes(struct engines *classes, struct engines *engines) +{ + unsigned int i, j; + + if (!classes) + classes = init_classes(engines); + + for (i = 0; i < classes->num_engines; i++) { + unsigned int num_engines = classes->class[i].num_engines; + struct engine *engine = engine_ptr(classes, i); + + if (!num_engines) + continue; + + memset(&engine->busy.val, 0, sizeof(engine->busy.val)); + memset(&engine->sema.val, 0, sizeof(engine->sema.val)); + memset(&engine->wait.val, 0, sizeof(engine->wait.val)); + + for (j = 0; j < engines->num_engines; j++) { + struct engine *e = engine_ptr(engines, j); + + if (e->class == i) { + __pmu_sum(&engine->busy.val, &e->busy.val); + __pmu_sum(&engine->sema.val, &e->sema.val); + __pmu_sum(&engine->wait.val, &e->wait.val); + } + } + + __pmu_normalize(&engine->busy.val, num_engines); + __pmu_normalize(&engine->sema.val, num_engines); + __pmu_normalize(&engine->wait.val, num_engines); + } + + return classes; +} + +static int +print_engines(struct engines *engines, double t, int lines, int w, int h) +{ + static struct engines *classes; + struct engines *show; + + if (class_view) + classes = show = update_classes(classes, engines); + else + show = engines; + + lines = print_engines_header(show, t, lines, w, h); + + for (unsigned int i = 0; i < show->num_engines && lines < h; i++) + lines = print_engine(show, i, t, lines, w, h); + + lines = print_engines_footer(show, t, lines, w, h); + + return lines; +} + static bool stop_top; static void sigint_handler(int sig) @@ -1292,6 +1465,9 @@ static void process_stdin(unsigned int timeout_us) case 'q': stop_top = true; break; + case '1': + class_view ^= true; + break; }; } } @@ -1302,7 +1478,6 @@ int main(int argc, char **argv) int con_w = -1, con_h = -1; char *output_path = NULL; struct engines *engines; - unsigned int i; int ret = 0, ch; bool list_device = false; char *pmu_device, *opt_device = NULL; @@ -1366,6 +1541,7 @@ int main(int argc, char **argv) case INTERACTIVE: pops = &term_pops; interactive_stdin(); + class_view = true; break; case STDOUT: pops = &stdout_pops; @@ -1462,17 +1638,7 @@ int main(int argc, char **argv) lines = print_imc(engines, t, lines, con_w, con_h); - lines = print_engines_header(engines, t, lines, con_w, - con_h); - - for (i = 0; - i < engines->num_engines && lines < con_h; - i++) - lines = print_engine(engines, i, t, lines, - con_w, con_h); - - lines = print_engines_footer(engines, t, lines, con_w, - con_h); + lines = print_engines(engines, t, lines, con_w, con_h); } if (stop_top) -- 2.25.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx