diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2013-08-17 11:12:07 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2013-08-17 11:21:51 +0100 |
commit | f9a50de3dcc501e930de6c60983a4feb57121e7e (patch) | |
tree | e2a65ef9a1ce5c15faf8e95e0337e821e2579ac7 /overlay/gpu-top.c | |
parent | 7df9caeea1606b4f0272de35f0d7f70eedd5ec30 (diff) |
Introduce intel-gpu-overlay
A realtime display of GPU activity. Note, this is just at the point of
minimum usability...
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'overlay/gpu-top.c')
-rw-r--r-- | overlay/gpu-top.c | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/overlay/gpu-top.c b/overlay/gpu-top.c new file mode 100644 index 00000000..400cbc58 --- /dev/null +++ b/overlay/gpu-top.c @@ -0,0 +1,178 @@ +#include <stdint.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> + +#include "igfx.h" +#include "gpu-top.h" + +#define RING_TAIL 0x00 +#define RING_HEAD 0x04 +#define ADDR_MASK 0x001FFFFC +#define RING_CTL 0x0C +#define RING_WAIT (1<<11) +#define RING_WAIT_SEMAPHORE (1<<10) + +struct ring { + int id; + uint32_t mmio; + int idle, wait, sema; +}; + +static void *mmio; + +static uint32_t ring_read(struct ring *ring, uint32_t reg) +{ + return igfx_read(mmio, ring->mmio + reg); +} + +static void ring_init(struct ring *ring) +{ + uint32_t ctl; + + ctl = ring_read(ring, RING_CTL); + if ((ctl & 1) == 0) + ring->id = -1; +} + +static void ring_reset(struct ring *ring) +{ + ring->idle = 0; + ring->wait = 0; + ring->sema = 0; +} + +static void ring_sample(struct ring *ring) +{ + uint32_t head, tail, ctl; + + if (ring->id == -1) + return; + + head = ring_read(ring, RING_HEAD) & ADDR_MASK; + tail = ring_read(ring, RING_TAIL) & ADDR_MASK; + ring->idle += head == tail; + + ctl = ring_read(ring, RING_CTL); + ring->wait += !!(ctl & RING_WAIT); + ring->sema += !!(ctl & RING_WAIT_SEMAPHORE); +} + +static void ring_emit(struct ring *ring, int samples, union gpu_top_payload *payload) +{ + if (ring->id == -1) + return; + + payload[ring->id].u.busy = 100 - 100 * ring->idle / samples; + payload[ring->id].u.wait = 100 * ring->wait / samples; + payload[ring->id].u.sema = 100 * ring->sema / samples; +} + +void gpu_top_init(struct gpu_top *gt) +{ + struct ring render_ring = { + .mmio = 0x2030, + .id = 0, + }, bsd_ring = { + .mmio = 0x4030, + .id = 1, + }, bsd6_ring = { + .mmio = 0x12030, + .id = 1, + }, blt_ring = { + .mmio = 0x22030, + .id = 2, + }; + const struct igfx_info *info; + struct pci_device *igfx; + int fd[2], i; + + memset(gt, 0, sizeof(*gt)); + gt->fd = -1; + + igfx = igfx_get(); + if (!igfx) + return; + + if (pipe(fd) < 0) + return; + + info = igfx_get_info(igfx); + + switch (fork()) { + case -1: return; + default: + fcntl(fd[0], F_SETFL, fcntl(fd[0], F_GETFL) | O_NONBLOCK); + gt->fd = fd[0]; + gt->ring[0].name = "render"; + gt->num_rings = 1; + if (info->gen >= 040) { + gt->ring[1].name = "bitstream"; + gt->num_rings++; + } + if (info->gen >= 060) { + gt->ring[2].name = "blt"; + gt->num_rings++; + } + close(fd[1]); + return; + case 0: + close(fd[0]); + break; + } + + mmio = igfx_get_mmio(igfx); + + ring_init(&render_ring); + if (info->gen >= 060) { + ring_init(&bsd6_ring); + ring_init(&blt_ring); + } else if (info->gen >= 040) { + ring_init(&bsd_ring); + } + + for (;;) { + union gpu_top_payload payload[MAX_RINGS]; + + ring_reset(&render_ring); + ring_reset(&bsd_ring); + ring_reset(&bsd6_ring); + ring_reset(&blt_ring); + + for (i = 0; i < 1000; i++) { + ring_sample(&render_ring); + ring_sample(&bsd_ring); + ring_sample(&bsd6_ring); + ring_sample(&blt_ring); + usleep(1000); + } + + ring_emit(&render_ring, 1000, payload); + ring_emit(&bsd_ring, 1000, payload); + ring_emit(&bsd6_ring, 1000, payload); + ring_emit(&blt_ring, 1000, payload); + + write(fd[1], payload, sizeof(payload)); + } +} + +int gpu_top_update(struct gpu_top *gt) +{ + uint32_t data[1024]; + int len, update = 0; + + if (gt->fd < 0) + return update; + + while ((len = read(gt->fd, data, sizeof(data))) > 0) { + uint32_t *ptr = &data[len/sizeof(uint32_t) - MAX_RINGS]; + gt->ring[0].u.payload = ptr[0]; + gt->ring[1].u.payload = ptr[1]; + gt->ring[2].u.payload = ptr[2]; + gt->ring[3].u.payload = ptr[3]; + update = 1; + } + + return update; +} |