With integrated graphics the TDP is shared between the gpu and the cpu, knowing the total energy consumed by the package is relevant to understanding throttling. v2: Tidy integration by eliminating struct rapl and improve output formatting. Signed-off-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> Cc: Tvrtko Ursulin <tvrtko.ursulin@xxxxxxxxx> --- tools/intel_gpu_top.c | 218 +++++++++++++++++++++++++----------------- 1 file changed, 130 insertions(+), 88 deletions(-) diff --git a/tools/intel_gpu_top.c b/tools/intel_gpu_top.c index 86de09aa9..0a49cfecc 100644 --- a/tools/intel_gpu_top.c +++ b/tools/intel_gpu_top.c @@ -50,10 +50,12 @@ struct pmu_pair { }; struct pmu_counter { - bool present; + uint64_t type; uint64_t config; unsigned int idx; struct pmu_pair val; + double scale; + bool present; }; struct engine { @@ -79,8 +81,8 @@ struct engines { struct pmu_pair ts; int rapl_fd; - double rapl_scale; - const char *rapl_unit; + struct pmu_counter r_gpu, r_pkg; + unsigned int num_rapl; int imc_fd; double imc_reads_scale; @@ -92,7 +94,6 @@ struct engines { struct pmu_counter freq_act; struct pmu_counter irq; struct pmu_counter rc6; - struct pmu_counter rapl; struct pmu_counter imc_reads; struct pmu_counter imc_writes; @@ -108,6 +109,109 @@ struct engines { }; +__attribute__((format(scanf,3,4))) +static int igt_sysfs_scanf(int dir, const char *attr, const char *fmt, ...) +{ + FILE *file; + int fd; + int ret = -1; + + fd = openat(dir, attr, O_RDONLY); + if (fd < 0) + return -1; + + file = fdopen(fd, "r"); + if (file) { + va_list ap; + + va_start(ap, fmt); + ret = vfscanf(file, fmt, ap); + va_end(ap); + + fclose(file); + } else { + close(fd); + } + + return ret; +} + +static int rapl_parse(struct pmu_counter *pmu, const char *str) +{ + locale_t locale, oldlocale; + bool result = true; + char buf[128] = {}; + int dir; + + dir = open("/sys/devices/power", O_RDONLY); + if (dir < 0) + return -errno; + + /* Replace user environment with plain C to match kernel format */ + locale = newlocale(LC_ALL, "C", 0); + oldlocale = uselocale(locale); + + result &= igt_sysfs_scanf(dir, "type", "%"PRIu64, &pmu->type) == 1; + + snprintf(buf, sizeof(buf) - 1, "events/energy-%s", str); + result &= igt_sysfs_scanf(dir, buf, "event=%"PRIx64, &pmu->config) == 1; + + snprintf(buf, sizeof(buf) - 1, "events/energy-%s.scale", str); + result &= igt_sysfs_scanf(dir, buf, "%lf", &pmu->scale) == 1; + + snprintf(buf, sizeof(buf) - 1, "events/energy-%s.unit", str); + if (igt_sysfs_scanf(dir, buf, "%127s", buf) == 1 && + strcmp(buf, "Joules")) + fprintf(stderr, "Unexpected units for RAPL %s: found %s\n", + str, buf); + + uselocale(oldlocale); + freelocale(locale); + + close(dir); + + if (!result) + return -EINVAL; + + if (isnan(pmu->scale) || !pmu->scale) + return -ERANGE; + + return 0; +} + +static void +rapl_open(struct pmu_counter *pmu, + const char *domain, + struct engines *engines) +{ + int fd; + + if (rapl_parse(pmu, domain) < 0) + return; + + fd = igt_perf_open_group(pmu->type, pmu->config, engines->rapl_fd); + if (fd < 0) + return; + + if (engines->rapl_fd == -1) + engines->rapl_fd = fd; + + pmu->idx = engines->num_rapl++; + pmu->present = true; +} + +static void gpu_power_open(struct pmu_counter *pmu, + struct engines *engines) +{ + rapl_open(pmu, "gpu", engines); +} + +static void pkg_power_open(struct pmu_counter *pmu, + struct engines *engines) +{ + rapl_open(pmu, "pkg", engines); +} + static uint64_t get_pmu_config(int dirfd, const char *name, const char *counter) { @@ -357,38 +461,6 @@ static double filename_to_double(const char *filename) return v; } -#define RAPL_ROOT "/sys/devices/power/" -#define RAPL_EVENT "/sys/devices/power/events/" - -static uint64_t rapl_type_id(void) -{ - return filename_to_u64(RAPL_ROOT "type", 10); -} - -static uint64_t rapl_gpu_power(void) -{ - return filename_to_u64(RAPL_EVENT "energy-gpu", 0); -} - -static double rapl_gpu_power_scale(void) -{ - return filename_to_double(RAPL_EVENT "energy-gpu.scale"); -} - -static const char *rapl_gpu_power_unit(void) -{ - char buf[32]; - - if (filename_to_buf(RAPL_EVENT "energy-gpu.unit", - buf, sizeof(buf)) == 0) - if (!strcmp(buf, "Joules")) - return strdup("Watts"); - else - return strdup(buf); - else - return NULL; -} - #define IMC_ROOT "/sys/devices/uncore_imc/" #define IMC_EVENT "/sys/devices/uncore_imc/events/" @@ -517,22 +589,9 @@ static int pmu_init(struct engines *engines) } engines->rapl_fd = -1; - if (!engines->discrete && rapl_type_id()) { - engines->rapl_scale = rapl_gpu_power_scale(); - engines->rapl_unit = rapl_gpu_power_unit(); - if (!engines->rapl_unit) - return -1; - - engines->rapl.config = rapl_gpu_power(); - if (!engines->rapl.config) - return -1; - - engines->rapl_fd = igt_perf_open(rapl_type_id(), - engines->rapl.config); - if (engines->rapl_fd < 0) - return -1; - - engines->rapl.present = true; + if (!engines->discrete) { + gpu_power_open(&engines->r_gpu, engines); + pkg_power_open(&engines->r_pkg, engines); } engines->imc_fd = -1; @@ -614,25 +673,6 @@ static void fill_str(char *buf, unsigned int bufsz, char c, unsigned int num) *buf = 0; } -static uint64_t __pmu_read_single(int fd, uint64_t *ts) -{ - uint64_t data[2] = { }; - ssize_t len; - - len = read(fd, data, sizeof(data)); - assert(len == sizeof(data)); - - if (ts) - *ts = data[1]; - - return data[0]; -} - -static uint64_t pmu_read_single(int fd) -{ - return __pmu_read_single(fd, NULL); -} - static void __update_sample(struct pmu_counter *counter, uint64_t val) { counter->val.prev = counter->val.cur; @@ -653,10 +693,6 @@ static void pmu_sample(struct engines *engines) engines->ts.prev = engines->ts.cur; - if (engines->rapl_fd >= 0) - __update_sample(&engines->rapl, - pmu_read_single(engines->rapl_fd)); - if (engines->imc_fd >= 0) { pmu_read_multi(engines->imc_fd, 2, val); update_sample(&engines->imc_reads, val); @@ -677,6 +713,12 @@ static void pmu_sample(struct engines *engines) update_sample(&engine->sema, val); update_sample(&engine->wait, val); } + + if (engines->num_rapl) { + pmu_read_multi(engines->rapl_fd, engines->num_rapl, val); + update_sample(&engines->r_gpu, val); + update_sample(&engines->r_pkg, val); + } } static const char *bars[] = { " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█" }; @@ -1076,14 +1118,14 @@ print_header(const struct igt_device_card *card, .items = rc6_items, }; struct cnt_item power_items[] = { - { &engines->rapl, 4, 2, 1.0, t, engines->rapl_scale, "value", - "W" }, + { &engines->r_gpu, 4, 2, 1.0, t, engines->r_gpu.scale, "GPU", "gpu" }, + { &engines->r_pkg, 4, 2, 1.0, t, engines->r_pkg.scale, "Package", "pkg" }, { NULL, 0, 0, 0.0, 0.0, 0.0, "unit", "W" }, { }, }; struct cnt_group power_group = { .name = "power", - .display_name = "Power", + .display_name = "Power W", .items = power_items, }; struct cnt_group *groups[] = { @@ -1108,17 +1150,17 @@ print_header(const struct igt_device_card *card, if (lines++ < con_h) { printf("intel-gpu-top: %s - ", card->card); - if (!engines->discrete) - printf("%s/%s MHz; %s%% RC6; %s %s; %s irqs/s\n", - freq_items[1].buf, freq_items[0].buf, - rc6_items[0].buf, power_items[0].buf, - engines->rapl_unit, - irq_items[0].buf); - else - printf("%s/%s MHz; %s%% RC6; %s irqs/s\n", - freq_items[1].buf, freq_items[0].buf, - rc6_items[0].buf, irq_items[0].buf); + printf("%s/%s MHz; %s%% RC6; ", + freq_items[1].buf, freq_items[0].buf, + rc6_items[0].buf); + if (engines->r_gpu.present) { + printf("%s/%s W; ", + power_items[0].buf, + power_items[1].buf); + } + printf("%s irqs/s\n", irq_items[0].buf); } + if (lines++ < con_h) printf("\n"); } -- 2.29.2 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx