diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2019-01-31 14:21:35 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2019-03-26 10:12:55 +0000 |
commit | 25fcb1c23dc5318b103d6c096b2dcfaea98dad3d (patch) | |
tree | 3909344687b76641d9ce7e9fc84d774b70f9c0a8 /lib/igt_gpu_power.c | |
parent | a4dc3d0f9ac6abf2a0ca6a4771255cb5dcb3b07b (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.c | 87 |
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); +} |