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