diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2013-08-27 11:20:43 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2013-08-27 12:31:13 +0100 |
commit | 1c3fd70357a57f823846010f59ba75f19e5d4af9 (patch) | |
tree | e3ef96d481a5c1d59782dab6c1b38c7e712adcd1 | |
parent | 6ec1d2c0ae631a3c0af445d4baa53561228be9a5 (diff) |
overlay: Read power from perf_events
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | overlay/Makefile.am | 2 | ||||
-rw-r--r-- | overlay/gpu-perf.c | 23 | ||||
-rw-r--r-- | overlay/gpu-top.c | 47 | ||||
-rw-r--r-- | overlay/overlay.c | 2 | ||||
-rw-r--r-- | overlay/perf.c | 26 | ||||
-rw-r--r-- | overlay/perf.h | 60 | ||||
-rw-r--r-- | overlay/power.c | 43 | ||||
-rw-r--r-- | overlay/power.h | 1 |
8 files changed, 131 insertions, 73 deletions
diff --git a/overlay/Makefile.am b/overlay/Makefile.am index 41f42cc8..8f829fe4 100644 --- a/overlay/Makefile.am +++ b/overlay/Makefile.am @@ -29,6 +29,8 @@ intel_gpu_overlay_SOURCES = \ igfx.c \ overlay.h \ overlay.c \ + perf.h \ + perf.c \ power.h \ power.c \ rc6.h \ diff --git a/overlay/gpu-perf.c b/overlay/gpu-perf.c index 142357cb..fc215634 100644 --- a/overlay/gpu-perf.c +++ b/overlay/gpu-perf.c @@ -24,7 +24,6 @@ #include <stdint.h> #include <stdbool.h> -#include <linux/perf_event.h> #include <sys/types.h> #include <sys/mman.h> #include <sys/ioctl.h> @@ -35,6 +34,7 @@ #include <fcntl.h> #include <errno.h> +#include "perf.h" #include "gpu-perf.h" #include "debugfs.h" @@ -59,27 +59,6 @@ struct sample_event { uint32_t raw[0]; }; -static int -perf_event_open(struct perf_event_attr *attr, - pid_t pid, - int cpu, - int group_fd, - unsigned long flags) -{ -#ifndef __NR_perf_event_open -#if defined(__i386__) -#define __NR_perf_event_open 336 -#elif defined(__x86_64__) -#define __NR_perf_event_open 298 -#else -#define __NR_perf_event_open 0 -#endif -#endif - - attr->size = sizeof(*attr); - return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); -} - static uint64_t tracepoint_id(const char *sys, const char *name) { char buf[1024]; diff --git a/overlay/gpu-top.c b/overlay/gpu-top.c index 751d5fcb..1efbbfd3 100644 --- a/overlay/gpu-top.c +++ b/overlay/gpu-top.c @@ -22,7 +22,6 @@ * */ -#include <linux/perf_event.h> #include <stdint.h> #include <stdlib.h> #include <stdio.h> @@ -31,6 +30,7 @@ #include <fcntl.h> #include <errno.h> +#include "perf.h" #include "igfx.h" #include "gpu-top.h" @@ -46,45 +46,6 @@ #define I915_PERF_RING_WAIT(n) (__I915_PERF_RING(n) + 1) #define I915_PERF_RING_SEMA(n) (__I915_PERF_RING(n) + 2) -static int -perf_event_open(struct perf_event_attr *attr, - pid_t pid, - int cpu, - int group_fd, - unsigned long flags) -{ -#ifndef __NR_perf_event_open -#if defined(__i386__) -#define __NR_perf_event_open 336 -#elif defined(__x86_64__) -#define __NR_perf_event_open 298 -#else -#define __NR_perf_event_open 0 -#endif -#endif - attr->size = sizeof(*attr); - return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); -} - -static uint64_t i915_type_id(void) -{ - char buf[1024]; - int fd, n; - - fd = open("/sys/bus/event_source/devices/i915/type", 0); - if (fd < 0) { - n = -1; - } else { - n = read(fd, buf, sizeof(buf)-1); - close(fd); - } - if (n < 0) - return 0; - - buf[n] = '\0'; - return strtoull(buf, 0, 0); -} - static int perf_i915_open(int config, int group) { struct perf_event_attr attr; @@ -106,9 +67,9 @@ static int perf_i915_open(int config, int group) static int perf_init(struct gpu_top *gt) { const char *names[] = { - "render", - "bitstream", - "bliter", + "RCS", + "VCS", + "BCS", NULL, }; int n; diff --git a/overlay/overlay.c b/overlay/overlay.c index 27281fd6..0c013cff 100644 --- a/overlay/overlay.c +++ b/overlay/overlay.c @@ -742,7 +742,7 @@ int main(int argc, char **argv) config_init(&config); opterr = 0; - while ((i = getopt_long(argc, argv, "c:f:", long_options, &index)) != -1) { + while ((i = getopt_long(argc, argv, "c:f", long_options, &index)) != -1) { switch (i) { case 'c': config_parse_string(&config, optarg); diff --git a/overlay/perf.c b/overlay/perf.c new file mode 100644 index 00000000..b8fdc675 --- /dev/null +++ b/overlay/perf.c @@ -0,0 +1,26 @@ +#include <stdint.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> + +#include "perf.h" + +uint64_t i915_type_id(void) +{ + char buf[1024]; + int fd, n; + + fd = open("/sys/bus/event_source/devices/i915/type", 0); + if (fd < 0) { + n = -1; + } else { + n = read(fd, buf, sizeof(buf)-1); + close(fd); + } + if (n < 0) + return 0; + + buf[n] = '\0'; + return strtoull(buf, 0, 0); +} + diff --git a/overlay/perf.h b/overlay/perf.h new file mode 100644 index 00000000..e2be0f7e --- /dev/null +++ b/overlay/perf.h @@ -0,0 +1,60 @@ +#ifndef I915_PERF_H +#define I915_PERF_H + +#include <linux/perf_event.h> + +#define I915_SAMPLE_BUSY 0 +#define I915_SAMPLE_WAIT 1 +#define I915_SAMPLE_SEMA 2 + +#define I915_SAMPLE_RCS 0 +#define I915_SAMPLE_VCS 1 +#define I915_SAMPLE_BCS 2 +#define I915_SAMPLE_VECS 3 + +#define __I915_PERF_COUNT(ring, id) ((ring) << 4 | (id)) + +#define I915_PERF_COUNT_RCS_BUSY __I915_PERF_COUNT(I915_SAMPLE_RCS, I915_SAMPLE_BUSY) +#define I915_PERF_COUNT_RCS_WAIT __I915_PERF_COUNT(I915_SAMPLE_RCS, I915_SAMPLE_WAIT) +#define I915_PERF_COUNT_RCS_SEMA __I915_PERF_COUNT(I915_SAMPLE_RCS, I915_SAMPLE_SEMA) + +#define I915_PERF_COUNT_VCS_BUSY __I915_PERF_COUNT(I915_SAMPLE_VCS, I915_SAMPLE_BUSY) +#define I915_PERF_COUNT_VCS_WAIT __I915_PERF_COUNT(I915_SAMPLE_VCS, I915_SAMPLE_WAIT) +#define I915_PERF_COUNT_VCS_SEMA __I915_PERF_COUNT(I915_SAMPLE_VCS, I915_SAMPLE_SEMA) + +#define I915_PERF_COUNT_BCS_BUSY __I915_PERF_COUNT(I915_SAMPLE_BCS, I915_SAMPLE_BUSY) +#define I915_PERF_COUNT_BCS_WAIT __I915_PERF_COUNT(I915_SAMPLE_BCS, I915_SAMPLE_WAIT) +#define I915_PERF_COUNT_BCS_SEMA __I915_PERF_COUNT(I915_SAMPLE_BCS, I915_SAMPLE_SEMA) + +#define I915_PERF_COUNT_VECS_BUSY __I915_PERF_COUNT(I915_SAMPLE_VECS, I915_SAMPLE_BUSY) +#define I915_PERF_COUNT_VECS_WAIT __I915_PERF_COUNT(I915_SAMPLE_VECS, I915_SAMPLE_WAIT) +#define I915_PERF_COUNT_VECS_SEMA __I915_PERF_COUNT(I915_SAMPLE_VECS, I915_SAMPLE_SEMA) + +#define I915_PERF_ACTUAL_FREQUENCY 32 +#define I915_PERF_REQUESTED_FREQUENCY 33 +#define I915_PERF_ENERGY 34 +#define I915_PERF_INTERRUPTS 35 + +static inline int +perf_event_open(struct perf_event_attr *attr, + pid_t pid, + int cpu, + int group_fd, + unsigned long flags) +{ +#ifndef __NR_perf_event_open +#if defined(__i386__) +#define __NR_perf_event_open 336 +#elif defined(__x86_64__) +#define __NR_perf_event_open 298 +#else +#define __NR_perf_event_open 0 +#endif +#endif + attr->size = sizeof(*attr); + return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); +} + +uint64_t i915_type_id(void); + +#endif /* I915_PERF_H */ diff --git a/overlay/power.c b/overlay/power.c index 520a1099..6c5c3749 100644 --- a/overlay/power.c +++ b/overlay/power.c @@ -22,6 +22,7 @@ * */ +#include <stdint.h> #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -30,11 +31,27 @@ #include <time.h> #include <errno.h> +#include "perf.h" #include "power.h" #include "debugfs.h" /* XXX Is this exposed through RAPL? */ +static int perf_open(void) +{ + struct perf_event_attr attr; + + memset(&attr, 0, sizeof (attr)); + + attr.type = i915_type_id(); + if (attr.type == 0) + return -ENOENT; + attr.config = I915_PERF_ENERGY; + + attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED; + return perf_event_open(&attr, -1, 0, -1, 0); +} + int power_init(struct power *power) { char buf[4096]; @@ -42,6 +59,10 @@ int power_init(struct power *power) memset(power, 0, sizeof(*power)); + power->fd = perf_open(); + if (power->fd != -1) + return 0; + sprintf(buf, "%s/i915_energy_uJ", debugfs_dri_path); fd = open(buf, 0); if (fd < 0) @@ -100,17 +121,25 @@ int power_update(struct power *power) if (power->error) return power->error; - s->energy = file_to_u64("i915_energy_uJ"); - s->timestamp = clock_ms_to_u64(); + if (power->fd != -1) { + uint64_t data[2]; + int len; + + len = read(power->fd, data, sizeof(data)); + if (len < 0) + return power->error = errno; + + s->energy = data[0]; + s->timestamp = data[1] / (1000*1000); + } else { + s->energy = file_to_u64("i915_energy_uJ"); + s->timestamp = clock_ms_to_u64(); + } + if (power->count == 1) return EAGAIN; d_time = s->timestamp - d->timestamp; - if (d_time < 900) { /* HW sample rate seems to be stable ~1Hz */ - power->count--; - return power->count <= 1 ? EAGAIN : 0; - } - power->power_mW = (s->energy - d->energy) / d_time; power->new_sample = 1; return 0; diff --git a/overlay/power.h b/overlay/power.h index a046bd5a..bf8346ce 100644 --- a/overlay/power.h +++ b/overlay/power.h @@ -33,6 +33,7 @@ struct power { uint64_t timestamp; } stat[2]; + int fd; int error; int count; int new_sample; |