summaryrefslogtreecommitdiff
path: root/lib/igt_gpu_power.c
blob: 7092b75b3a16886e33c45dae615f6291b10bc5fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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);
}