1 #include <ctype.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <locale.h>
5 #include <math.h>
6 #include <unistd.h>
7 #include <inttypes.h>
8
9 #include "igt_gpu_power.h"
10 #include "igt_perf.h"
11 #include "igt_sysfs.h"
12
13 struct rapl {
14 uint64_t power, type;
15 double scale;
16 };
17
rapl_parse(struct rapl * r)18 static int rapl_parse(struct rapl *r)
19 {
20 locale_t locale, oldlocale;
21 bool result;
22 int dir;
23
24 memset(r, 0, sizeof(*r));
25
26 dir = open("/sys/devices/power", O_RDONLY);
27 if (dir < 0)
28 return -errno;
29
30 /* Replace user environment with plain C to match kernel format */
31 locale = newlocale(LC_ALL, "C", 0);
32 oldlocale = uselocale(locale);
33
34 result = true;
35 result &= igt_sysfs_scanf(dir, "type",
36 "%"PRIu64, &r->type) == 1;
37 result &= igt_sysfs_scanf(dir, "events/energy-gpu",
38 "event=%"PRIx64, &r->power) == 1;
39 result &= igt_sysfs_scanf(dir, "events/energy-gpu.scale",
40 "%lf", &r->scale) == 1;
41
42 uselocale(oldlocale);
43 freelocale(locale);
44
45 close(dir);
46
47 if (!result)
48 return -EINVAL;
49
50 if (isnan(r->scale) || !r->scale)
51 return -ERANGE;
52
53 return 0;
54 }
55
gpu_power_open(struct gpu_power * power)56 int gpu_power_open(struct gpu_power *power)
57 {
58 struct rapl r;
59
60 power->fd = rapl_parse(&r);
61 if (power->fd < 0)
62 goto err;
63
64 power->fd = igt_perf_open(r.type, r.power);
65 if (power->fd < 0) {
66 power->fd = -errno;
67 goto err;
68 }
69
70 power->scale = r.scale;
71
72 return 0;
73
74 err:
75 errno = 0;
76 return power->fd;
77 }
78
gpu_power_read(struct gpu_power * power,struct gpu_power_sample * s)79 bool gpu_power_read(struct gpu_power *power, struct gpu_power_sample *s)
80 {
81 return read(power->fd, s, sizeof(*s)) == sizeof(*s);
82 }
83
gpu_power_close(struct gpu_power * power)84 void gpu_power_close(struct gpu_power *power)
85 {
86 close(power->fd);
87 }
88