Run a command; print how much power rapl reported the system using. Signed-off-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> Cc: Andi Shyti <andi.shyti@xxxxxxxxx> Cc: Tvrtko Ursulin <tvrtko.ursulin@xxxxxxxxx> --- tools/igt_rapl.c | 202 ++++++++++++++++++++++++++++++++++++++++++++++ tools/meson.build | 5 ++ 2 files changed, 207 insertions(+) create mode 100644 tools/igt_rapl.c diff --git a/tools/igt_rapl.c b/tools/igt_rapl.c new file mode 100644 index 000000000..8d985681f --- /dev/null +++ b/tools/igt_rapl.c @@ -0,0 +1,202 @@ +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <locale.h> +#include <math.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "igt_perf.h" + +struct parse { + uint64_t config, type; +}; + +struct rapl { + const char *name; + double scale; + int fd; +}; + +__attribute__((format(scanf,3,4))) +static int dir_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 parse *r, const char *str, double *scale) +{ + locale_t locale, oldlocale; + bool result = true; + char buf[128]; + int dir; + + memset(r, 0, sizeof(*r)); + + 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 &= dir_scanf(dir, "type", "%"PRIu64, &r->type) == 1; + + snprintf(buf, sizeof(buf), "events/energy-%s", str); + result &= dir_scanf(dir, buf, "event=%"PRIx64, &r->config) == 1; + + snprintf(buf, sizeof(buf), "events/energy-%s.scale", str); + result &= dir_scanf(dir, buf, "%lf", scale) == 1; + + uselocale(oldlocale); + freelocale(locale); + + close(dir); + + if (!result) + return -EINVAL; + + if (isnan(*scale) || !*scale) + return -ERANGE; + + return 0; +} + +static int rapl_open(int fd, const char *domain, double *scale) +{ + struct parse r; + int err; + + err = rapl_parse(&r, domain, scale); + if (err < 0) + goto err; + + return igt_perf_open_group(r.type, r.config, fd); + +err: + errno = 0; + return err; +} + +static int runit(struct rapl *r, int count, int argc, char **argv) +{ + int ret, status; + + switch (ret = fork()) { + case -1: return errno; + case 0: /* child */ + while (count--) + close(r[count].fd); + execvp(argv[0], argv); + exit(1); + break; + default: /* parent */ + if (wait(&status) < 0) { + kill(ret, SIGKILL); + return errno; + } + + return status; + } +} + +static inline double power_J(const uint64_t p0, + const uint64_t p1, + const double scale) +{ + return (p1 - p0) * scale; +} + +static inline double power_s(const uint64_t t0, + const uint64_t t1) +{ + return (t1 - t0) * 1e-9; +} + +static inline double power_W(const uint64_t *s0, + const uint64_t *s1, + int idx, + const double scale) +{ + return power_J(s0[idx+2], s1[idx+2], scale) / power_s(s0[1], s1[1]); +} + +static int rapl_read(int fd, uint64_t *data, int count) +{ + if (read(fd, data, (count + 2) * sizeof(data[0])) < 0) + return -errno; + + return 0; +} + +int main(int argc, char **argv) +{ + static const char *domains[] = { "gpu", "pkg", /* "ram" */}; + uint64_t before[8] = {}, after[8] = {}; + struct rapl r[4]; + int count = 0; + int ret; + int i; + + r[0].fd = -1; + for (i = 0; i < sizeof(domains)/sizeof(*domains); i++) { + r[count].fd = rapl_open(r[0].fd, domains[i], &r[count].scale); + if (r[count].fd < 0) + continue; + + r[count++].name = domains[i]; + } + if (!count) { + fprintf(stderr, "Unable to open any rapl power domains\n"); + return 1; + } + + ret = rapl_read(r[0].fd, before, count); + if (ret < 0) { + fprintf(stderr, "Unable to read perf event\n"); + return 1; + } + + ret = runit(r, count, argc - 1, argv + 1); + + ret = rapl_read(r[0].fd, after, count); + if (ret < 0) { + fprintf(stderr, "Unable to read perf event\n"); + return 1; + } + + printf("time:%.2fms", power_s(before[1], after[1]) * 1e3); + for (i = 0; i < count; i++) + printf(", %s:%.2fms", + r[i].name, power_W(before, after, i, r[i].scale) * 1e3); + printf("\n"); + + return ret; +} diff --git a/tools/meson.build b/tools/meson.build index eecb122bc..5b462c131 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -100,6 +100,11 @@ executable('intel_gpu_top', 'intel_gpu_top.c', install_rpath : bindir_rpathdir, dependencies : lib_igt_perf) +executable('igt_rapl', 'igt_rapl.c', + install : true, + install_rpath : bindir_rpathdir, + dependencies : lib_igt_perf) + executable('amd_hdmi_compliance', 'amd_hdmi_compliance.c', dependencies : [tool_deps], install_rpath : bindir_rpathdir, -- 2.24.0 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx