summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2013-08-27 11:20:43 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2013-08-27 12:31:13 +0100
commit1c3fd70357a57f823846010f59ba75f19e5d4af9 (patch)
treee3ef96d481a5c1d59782dab6c1b38c7e712adcd1
parent6ec1d2c0ae631a3c0af445d4baa53561228be9a5 (diff)
overlay: Read power from perf_events
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--overlay/Makefile.am2
-rw-r--r--overlay/gpu-perf.c23
-rw-r--r--overlay/gpu-top.c47
-rw-r--r--overlay/overlay.c2
-rw-r--r--overlay/perf.c26
-rw-r--r--overlay/perf.h60
-rw-r--r--overlay/power.c43
-rw-r--r--overlay/power.h1
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;