overlay: Read power from perf_events
authorChris Wilson <chris@chris-wilson.co.uk>
Tue, 27 Aug 2013 10:20:43 +0000 (11:20 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Tue, 27 Aug 2013 11:31:13 +0000 (12:31 +0100)
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
overlay/Makefile.am
overlay/gpu-perf.c
overlay/gpu-top.c
overlay/overlay.c
overlay/perf.c [new file with mode: 0644]
overlay/perf.h [new file with mode: 0644]
overlay/power.c
overlay/power.h

index 41f42cc..8f829fe 100644 (file)
@@ -29,6 +29,8 @@ intel_gpu_overlay_SOURCES = \
        igfx.c \
        overlay.h \
        overlay.c \
+       perf.h \
+       perf.c \
        power.h \
        power.c \
        rc6.h \
index 142357c..fc21563 100644 (file)
@@ -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];
index 751d5fc..1efbbfd 100644 (file)
@@ -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"
 
 #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;
index 27281fd..0c013cf 100644 (file)
@@ -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 (file)
index 0000000..b8fdc67
--- /dev/null
@@ -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 (file)
index 0000000..e2be0f7
--- /dev/null
@@ -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 */
index 520a109..6c5c374 100644 (file)
@@ -22,6 +22,7 @@
  *
  */
 
+#include <stdint.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #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;
index a046bd5..bf8346c 100644 (file)
@@ -33,6 +33,7 @@ struct power {
                uint64_t timestamp;
        } stat[2];
 
+       int fd;
        int error;
        int count;
        int new_sample;