blob: 7092b75b3a16886e33c45dae615f6291b10bc5fd [file] [log] [blame]
#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);
}