summaryrefslogtreecommitdiff
path: root/lib/igt_gpu_power.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2019-01-31 14:21:35 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2019-03-26 10:12:55 +0000
commit25fcb1c23dc5318b103d6c096b2dcfaea98dad3d (patch)
tree3909344687b76641d9ce7e9fc84d774b70f9c0a8 /lib/igt_gpu_power.c
parenta4dc3d0f9ac6abf2a0ca6a4771255cb5dcb3b07b (diff)
lib: Add GPU power measurement
Read the RAPL power metrics courtesy of perf. Or your local HW equivalent? v2: uselocale() v3: Use gpu_power_s(), gpu_power_J(), gpu_power_W() to try and make the scale factors self-consistent. v4: Use igt_sysfs v5: s/tN/sampleN/ Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Diffstat (limited to 'lib/igt_gpu_power.c')
-rw-r--r--lib/igt_gpu_power.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/lib/igt_gpu_power.c b/lib/igt_gpu_power.c
new file mode 100644
index 00000000..7092b75b
--- /dev/null
+++ b/lib/igt_gpu_power.c
@@ -0,0 +1,87 @@
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <math.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "igt_gpu_power.h"
+#include "igt_perf.h"
+#include "igt_sysfs.h"
+
+struct rapl {
+ uint64_t power, type;
+ double scale;
+};
+
+static int rapl_parse(struct rapl *r)
+{
+ locale_t locale, oldlocale;
+ bool result;
+ 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 = true;
+ result &= igt_sysfs_scanf(dir, "type",
+ "%"PRIu64, &r->type) == 1;
+ result &= igt_sysfs_scanf(dir, "events/energy-gpu",
+ "event=%"PRIx64, &r->power) == 1;
+ result &= igt_sysfs_scanf(dir, "events/energy-gpu.scale",
+ "%lf", &r->scale) == 1;
+
+ uselocale(oldlocale);
+ freelocale(locale);
+
+ close(dir);
+
+ if (!result)
+ return -EINVAL;
+
+ if (isnan(r->scale) || !r->scale)
+ return -ERANGE;
+
+ return 0;
+}
+
+int gpu_power_open(struct gpu_power *power)
+{
+ struct rapl r;
+
+ power->fd = rapl_parse(&r);
+ if (power->fd < 0)
+ goto err;
+
+ power->fd = igt_perf_open(r.type, r.power);
+ if (power->fd < 0) {
+ power->fd = -errno;
+ goto err;
+ }
+
+ power->scale = r.scale;
+
+ return 0;
+
+err:
+ errno = 0;
+ return power->fd;
+}
+
+bool gpu_power_read(struct gpu_power *power, struct gpu_power_sample *s)
+{
+ return read(power->fd, s, sizeof(*s)) == sizeof(*s);
+}
+
+void gpu_power_close(struct gpu_power *power)
+{
+ close(power->fd);
+}