blob: 751d5fcbfb9cc19af3ec5d319937c64f48376139 [file] [log] [blame]
Chris Wilsonb98bade2013-08-20 21:39:27 +01001/*
2 * Copyright © 2013 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 */
24
Chris Wilson2e482a32013-08-20 19:11:44 +010025#include <linux/perf_event.h>
Chris Wilsonf9a50de2013-08-17 11:12:07 +010026#include <stdint.h>
Chris Wilson2e482a32013-08-20 19:11:44 +010027#include <stdlib.h>
Chris Wilsonf9a50de2013-08-17 11:12:07 +010028#include <stdio.h>
29#include <string.h>
Chris Wilson2e482a32013-08-20 19:11:44 +010030#include <unistd.h>
31#include <fcntl.h>
32#include <errno.h>
Chris Wilsonf9a50de2013-08-17 11:12:07 +010033
34#include "igfx.h"
35#include "gpu-top.h"
36
37#define RING_TAIL 0x00
38#define RING_HEAD 0x04
39#define ADDR_MASK 0x001FFFFC
40#define RING_CTL 0x0C
41#define RING_WAIT (1<<11)
42#define RING_WAIT_SEMAPHORE (1<<10)
43
Chris Wilson2e482a32013-08-20 19:11:44 +010044#define __I915_PERF_RING(n) (4*n)
45#define I915_PERF_RING_BUSY(n) (__I915_PERF_RING(n) + 0)
46#define I915_PERF_RING_WAIT(n) (__I915_PERF_RING(n) + 1)
47#define I915_PERF_RING_SEMA(n) (__I915_PERF_RING(n) + 2)
48
49static int
50perf_event_open(struct perf_event_attr *attr,
51 pid_t pid,
52 int cpu,
53 int group_fd,
54 unsigned long flags)
55{
56#ifndef __NR_perf_event_open
57#if defined(__i386__)
58#define __NR_perf_event_open 336
59#elif defined(__x86_64__)
60#define __NR_perf_event_open 298
61#else
62#define __NR_perf_event_open 0
63#endif
64#endif
65 attr->size = sizeof(*attr);
66 return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
67}
68
69static uint64_t i915_type_id(void)
70{
71 char buf[1024];
72 int fd, n;
73
74 fd = open("/sys/bus/event_source/devices/i915/type", 0);
Chris Wilsona7b74202013-08-20 23:19:45 +010075 if (fd < 0) {
76 n = -1;
77 } else {
78 n = read(fd, buf, sizeof(buf)-1);
79 close(fd);
80 }
Chris Wilson2e482a32013-08-20 19:11:44 +010081 if (n < 0)
82 return 0;
83
84 buf[n] = '\0';
85 return strtoull(buf, 0, 0);
86}
87
88static int perf_i915_open(int config, int group)
89{
90 struct perf_event_attr attr;
91
92 memset(&attr, 0, sizeof (attr));
93
94 attr.type = i915_type_id();
95 if (attr.type == 0)
96 return -ENOENT;
97 attr.config = config;
98
Chris Wilson2e482a32013-08-20 19:11:44 +010099 attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED;
100 if (group == -1)
101 attr.read_format |= PERF_FORMAT_GROUP;
102
103 return perf_event_open(&attr, -1, 0, group, 0);
104}
105
106static int perf_init(struct gpu_top *gt)
107{
108 const char *names[] = {
109 "render",
110 "bitstream",
111 "bliter",
112 NULL,
113 };
114 int n;
115
116 gt->fd = perf_i915_open(I915_PERF_RING_BUSY(0), -1);
117 if (gt->fd < 0)
118 return -1;
119
120 if (perf_i915_open(I915_PERF_RING_WAIT(0), gt->fd) >= 0)
121 gt->have_wait = 1;
122
123 if (perf_i915_open(I915_PERF_RING_SEMA(0), gt->fd) >= 0)
124 gt->have_sema = 1;
125
126 gt->ring[0].name = names[0];
127 gt->num_rings = 1;
128
129 for (n = 1; names[n]; n++) {
130 if (perf_i915_open(I915_PERF_RING_BUSY(n), gt->fd) >= 0) {
131 if (gt->have_wait &&
132 perf_i915_open(I915_PERF_RING_WAIT(n), gt->fd) < 0)
133 return -1;
134
135 if (gt->have_sema &&
136 perf_i915_open(I915_PERF_RING_SEMA(n), gt->fd) < 0)
137 return -1;
138
139 gt->ring[gt->num_rings++].name = names[n];
140 }
141 }
142
143 return 0;
144}
145
146struct mmio_ring {
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100147 int id;
Chris Wilson2e482a32013-08-20 19:11:44 +0100148 uint32_t base;
149 void *mmio;
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100150 int idle, wait, sema;
151};
152
Chris Wilson2e482a32013-08-20 19:11:44 +0100153static uint32_t mmio_ring_read(struct mmio_ring *ring, uint32_t reg)
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100154{
Chris Wilson3e7dddc2013-08-21 09:16:25 +0100155 return igfx_read(ring->mmio, ring->base + reg);
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100156}
157
Chris Wilson2e482a32013-08-20 19:11:44 +0100158static void mmio_ring_init(struct mmio_ring *ring, void *mmio)
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100159{
160 uint32_t ctl;
161
Chris Wilson3e7dddc2013-08-21 09:16:25 +0100162 ring->mmio = mmio;
Chris Wilson2e482a32013-08-20 19:11:44 +0100163
164 ctl = mmio_ring_read(ring, RING_CTL);
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100165 if ((ctl & 1) == 0)
166 ring->id = -1;
167}
168
Chris Wilson2e482a32013-08-20 19:11:44 +0100169static void mmio_ring_reset(struct mmio_ring *ring)
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100170{
171 ring->idle = 0;
172 ring->wait = 0;
173 ring->sema = 0;
174}
175
Chris Wilson2e482a32013-08-20 19:11:44 +0100176static void mmio_ring_sample(struct mmio_ring *ring)
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100177{
178 uint32_t head, tail, ctl;
179
180 if (ring->id == -1)
181 return;
182
Chris Wilson2e482a32013-08-20 19:11:44 +0100183 head = mmio_ring_read(ring, RING_HEAD) & ADDR_MASK;
184 tail = mmio_ring_read(ring, RING_TAIL) & ADDR_MASK;
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100185 ring->idle += head == tail;
186
Chris Wilson2e482a32013-08-20 19:11:44 +0100187 ctl = mmio_ring_read(ring, RING_CTL);
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100188 ring->wait += !!(ctl & RING_WAIT);
189 ring->sema += !!(ctl & RING_WAIT_SEMAPHORE);
190}
191
Chris Wilson2e482a32013-08-20 19:11:44 +0100192static void mmio_ring_emit(struct mmio_ring *ring, int samples, union gpu_top_payload *payload)
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100193{
194 if (ring->id == -1)
195 return;
196
197 payload[ring->id].u.busy = 100 - 100 * ring->idle / samples;
198 payload[ring->id].u.wait = 100 * ring->wait / samples;
199 payload[ring->id].u.sema = 100 * ring->sema / samples;
200}
201
Chris Wilson2e482a32013-08-20 19:11:44 +0100202static void mmio_init(struct gpu_top *gt)
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100203{
Chris Wilson2e482a32013-08-20 19:11:44 +0100204 struct mmio_ring render_ring = {
205 .base = 0x2030,
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100206 .id = 0,
207 }, bsd_ring = {
Chris Wilson2e482a32013-08-20 19:11:44 +0100208 .base = 0x4030,
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100209 .id = 1,
210 }, bsd6_ring = {
Chris Wilson2e482a32013-08-20 19:11:44 +0100211 .base = 0x12030,
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100212 .id = 1,
213 }, blt_ring = {
Chris Wilson2e482a32013-08-20 19:11:44 +0100214 .base = 0x22030,
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100215 .id = 2,
216 };
217 const struct igfx_info *info;
218 struct pci_device *igfx;
Chris Wilson2e482a32013-08-20 19:11:44 +0100219 void *mmio;
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100220 int fd[2], i;
221
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100222 igfx = igfx_get();
223 if (!igfx)
224 return;
225
226 if (pipe(fd) < 0)
227 return;
228
229 info = igfx_get_info(igfx);
230
231 switch (fork()) {
232 case -1: return;
233 default:
234 fcntl(fd[0], F_SETFL, fcntl(fd[0], F_GETFL) | O_NONBLOCK);
235 gt->fd = fd[0];
Chris Wilson2e482a32013-08-20 19:11:44 +0100236 gt->type = MMIO;
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100237 gt->ring[0].name = "render";
238 gt->num_rings = 1;
239 if (info->gen >= 040) {
240 gt->ring[1].name = "bitstream";
241 gt->num_rings++;
242 }
243 if (info->gen >= 060) {
244 gt->ring[2].name = "blt";
245 gt->num_rings++;
246 }
247 close(fd[1]);
248 return;
249 case 0:
250 close(fd[0]);
251 break;
252 }
253
254 mmio = igfx_get_mmio(igfx);
Chris Wilson3e7dddc2013-08-21 09:16:25 +0100255 if (mmio == NULL)
256 exit(127);
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100257
Chris Wilson2e482a32013-08-20 19:11:44 +0100258 mmio_ring_init(&render_ring, mmio);
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100259 if (info->gen >= 060) {
Chris Wilson3e7dddc2013-08-21 09:16:25 +0100260 bsd_ring = bsd6_ring;
Chris Wilson2e482a32013-08-20 19:11:44 +0100261 mmio_ring_init(&blt_ring, mmio);
Chris Wilson3e7dddc2013-08-21 09:16:25 +0100262 }
263 if (info->gen >= 040) {
Chris Wilson2e482a32013-08-20 19:11:44 +0100264 mmio_ring_init(&bsd_ring, mmio);
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100265 }
266
267 for (;;) {
268 union gpu_top_payload payload[MAX_RINGS];
269
Chris Wilson2e482a32013-08-20 19:11:44 +0100270 mmio_ring_reset(&render_ring);
271 mmio_ring_reset(&bsd_ring);
Chris Wilson2e482a32013-08-20 19:11:44 +0100272 mmio_ring_reset(&blt_ring);
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100273
274 for (i = 0; i < 1000; i++) {
Chris Wilson2e482a32013-08-20 19:11:44 +0100275 mmio_ring_sample(&render_ring);
276 mmio_ring_sample(&bsd_ring);
Chris Wilson2e482a32013-08-20 19:11:44 +0100277 mmio_ring_sample(&blt_ring);
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100278 usleep(1000);
279 }
280
Chris Wilson2e482a32013-08-20 19:11:44 +0100281 mmio_ring_emit(&render_ring, 1000, payload);
282 mmio_ring_emit(&bsd_ring, 1000, payload);
Chris Wilson2e482a32013-08-20 19:11:44 +0100283 mmio_ring_emit(&blt_ring, 1000, payload);
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100284
285 write(fd[1], payload, sizeof(payload));
286 }
287}
288
Chris Wilson2e482a32013-08-20 19:11:44 +0100289void gpu_top_init(struct gpu_top *gt)
290{
291 memset(gt, 0, sizeof(*gt));
292 gt->fd = -1;
293
294 if (perf_init(gt) == 0)
295 return;
296
297 mmio_init(gt);
298}
299
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100300int gpu_top_update(struct gpu_top *gt)
301{
302 uint32_t data[1024];
Chris Wilson2e482a32013-08-20 19:11:44 +0100303 int update, len;
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100304
305 if (gt->fd < 0)
Chris Wilson2e482a32013-08-20 19:11:44 +0100306 return 0;
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100307
Chris Wilson2e482a32013-08-20 19:11:44 +0100308 if (gt->type == PERF) {
309 struct gpu_top_stat *s = &gt->stat[gt->count++&1];
310 struct gpu_top_stat *d = &gt->stat[gt->count&1];
311 uint64_t *sample, d_time;
Chris Wilsona7b74202013-08-20 23:19:45 +0100312 int n, m;
Chris Wilson2e482a32013-08-20 19:11:44 +0100313
314 len = read(gt->fd, data, sizeof(data));
315 if (len < 0)
316 return 0;
317
318 sample = (uint64_t *)data + 1;
319
320 s->time = *sample++;
Chris Wilsona7b74202013-08-20 23:19:45 +0100321 for (n = m = 0; n < gt->num_rings; n++) {
322 s->busy[n] = sample[m++];
Chris Wilson2e482a32013-08-20 19:11:44 +0100323 if (gt->have_wait)
Chris Wilsona7b74202013-08-20 23:19:45 +0100324 s->wait[n] = sample[m++];
Chris Wilson2e482a32013-08-20 19:11:44 +0100325 if (gt->have_sema)
Chris Wilsona7b74202013-08-20 23:19:45 +0100326 s->sema[n] = sample[m++];
Chris Wilson2e482a32013-08-20 19:11:44 +0100327 }
328
329 if (gt->count == 1)
330 return 0;
331
332 d_time = s->time - d->time;
333 for (n = 0; n < gt->num_rings; n++) {
334 gt->ring[n].u.u.busy = 100 * (s->busy[n] - d->busy[n]) / d_time;
335 if (gt->have_wait)
336 gt->ring[n].u.u.wait = 100 * (s->wait[n] - d->wait[n]) / d_time;
337 if (gt->have_sema)
338 gt->ring[n].u.u.sema = 100 * (s->sema[n] - d->sema[n]) / d_time;
339 }
340
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100341 update = 1;
Chris Wilson2e482a32013-08-20 19:11:44 +0100342 } else {
343 while ((len = read(gt->fd, data, sizeof(data))) > 0) {
344 uint32_t *ptr = &data[len/sizeof(uint32_t) - MAX_RINGS];
345 gt->ring[0].u.payload = ptr[0];
346 gt->ring[1].u.payload = ptr[1];
347 gt->ring[2].u.payload = ptr[2];
348 gt->ring[3].u.payload = ptr[3];
349 update = 1;
350 }
Chris Wilsonf9a50de2013-08-17 11:12:07 +0100351 }
352
353 return update;
354}