[Intel-gfx] [PATCH i-g-t] tools: Add a simple rapl wrapper
Chris Wilson
chris at chris-wilson.co.uk
Fri Nov 8 16:50:46 UTC 2019
Run a command; print how much power rapl reported the system using.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Andi Shyti <andi.shyti at intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
---
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
More information about the Intel-gfx
mailing list