1 /*
2 * Copyright © 2011 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 * Authors:
24 * Chris Wilson <chris@chris-wilson.co.uk>
25 *
26 */
27
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <stdint.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <fcntl.h>
34 #include <inttypes.h>
35 #include <errno.h>
36 #include <sys/stat.h>
37 #include <sys/ioctl.h>
38 #include <sys/time.h>
39 #include <time.h>
40
41 #include "drm.h"
42 #include "ioctl_wrappers.h"
43 #include "drmtest.h"
44 #include "intel_io.h"
45 #include "intel_reg.h"
46 #include "igt_stats.h"
47
48 #define LOCAL_I915_EXEC_NO_RELOC (1<<11)
49 #define LOCAL_I915_EXEC_HANDLE_LUT (1<<12)
50
51 #define LOCAL_I915_EXEC_BSD_SHIFT (13)
52 #define LOCAL_I915_EXEC_BSD_MASK (3 << LOCAL_I915_EXEC_BSD_SHIFT)
53
54 #define ENGINE_FLAGS (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK)
55
56 #define SYNC 0x1
57 #define WRITE 0x2
58 #define READ_ALL 0x4
59
elapsed(const struct timespec * start,const struct timespec * end)60 static double elapsed(const struct timespec *start,
61 const struct timespec *end)
62 {
63 return (end->tv_sec - start->tv_sec) + 1e-9*(end->tv_nsec - start->tv_nsec);
64 }
65
batch(int fd)66 static uint32_t batch(int fd)
67 {
68 const uint32_t bbe = MI_BATCH_BUFFER_END;
69 uint32_t handle = gem_create(fd, 4096);
70 gem_write(fd, handle, 0, &bbe, sizeof(bbe));
71 return handle;
72 }
73
loop(unsigned ring,int reps,int ncpus,unsigned flags)74 static int loop(unsigned ring, int reps, int ncpus, unsigned flags)
75 {
76 struct drm_i915_gem_execbuffer2 execbuf;
77 struct drm_i915_gem_exec_object2 obj[2];
78 unsigned all_engines[16];
79 unsigned all_nengine;
80 unsigned engines[16];
81 unsigned nengine;
82 double *shared;
83 int fd;
84
85 shared = mmap(0, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
86
87 fd = drm_open_driver(DRIVER_INTEL);
88
89 memset(obj, 0, sizeof(obj));
90 obj[0].handle = gem_create(fd, 4096);
91 if (flags & WRITE)
92 obj[0].flags = EXEC_OBJECT_WRITE;
93 obj[1].handle = batch(fd);
94
95 memset(&execbuf, 0, sizeof(execbuf));
96 execbuf.buffers_ptr = (uintptr_t)obj;
97 execbuf.buffer_count = 2;
98 execbuf.flags |= LOCAL_I915_EXEC_HANDLE_LUT;
99 execbuf.flags |= LOCAL_I915_EXEC_NO_RELOC;
100 if (__gem_execbuf(fd, &execbuf)) {
101 execbuf.flags = 0;
102 if (__gem_execbuf(fd, &execbuf))
103 return 77;
104 }
105
106 if (flags & WRITE && !(execbuf.flags & LOCAL_I915_EXEC_HANDLE_LUT))
107 return 77;
108
109 all_nengine = 0;
110 for (unsigned r = 1; r < 16; r++) {
111 execbuf.flags &= ~ENGINE_FLAGS;
112 execbuf.flags |= r;
113 if (__gem_execbuf(fd, &execbuf) == 0)
114 all_engines[all_nengine++] = r;
115 }
116
117 if (ring == -1) {
118 nengine = all_nengine;
119 memcpy(engines, all_engines, all_nengine*sizeof(engines[0]));
120 } else {
121 nengine = 1;
122 engines[0] = ring;
123 }
124
125 while (reps--) {
126 memset(shared, 0, 4096);
127
128 gem_set_domain(fd, obj[1].handle, I915_GEM_DOMAIN_GTT, 0);
129 sleep(1); /* wait for the hw to go back to sleep */
130
131 igt_fork(child, ncpus) {
132 struct timespec start, end;
133 unsigned count = 0;
134
135 obj[0].handle = gem_create(fd, 4096);
136 obj[1].handle = batch(fd);
137
138 clock_gettime(CLOCK_MONOTONIC, &start);
139 do {
140 for (int inner = 0; inner < 1024; inner++) {
141 if (flags & READ_ALL) {
142 obj[0].flags = 0;
143 for (int n = 0; n < all_nengine; n++) {
144 execbuf.flags &= ~ENGINE_FLAGS;
145 execbuf.flags |= all_engines[n];
146 gem_execbuf(fd, &execbuf);
147 }
148 if (flags & WRITE)
149 obj[0].flags = EXEC_OBJECT_WRITE;
150 }
151 execbuf.flags &= ~ENGINE_FLAGS;
152 execbuf.flags |= engines[count++ % nengine];
153 gem_execbuf(fd, &execbuf);
154 if (flags & SYNC)
155 gem_sync(fd, obj[1].handle);
156 }
157
158 clock_gettime(CLOCK_MONOTONIC, &end);
159 } while (elapsed(&start, &end) < 2.);
160
161 gem_sync(fd, obj[1].handle);
162 clock_gettime(CLOCK_MONOTONIC, &end);
163 shared[child] = 1e6*elapsed(&start, &end) / count;
164
165 gem_close(fd, obj[1].handle);
166 gem_close(fd, obj[0].handle);
167 }
168 igt_waitchildren();
169
170 for (int child = 0; child < ncpus; child++)
171 shared[ncpus] += shared[child];
172 printf("%7.3f\n", shared[ncpus] / ncpus);
173
174 obj[0].flags = 0;
175 for (int n = 0; n < nengine; n++) {
176 execbuf.flags &= ~ENGINE_FLAGS;
177 execbuf.flags |= engines[n];
178 gem_execbuf(fd, &execbuf);
179 }
180 if (flags & WRITE)
181 obj[0].flags = EXEC_OBJECT_WRITE;
182 }
183 return 0;
184 }
185
main(int argc,char ** argv)186 int main(int argc, char **argv)
187 {
188 unsigned ring = I915_EXEC_RENDER;
189 unsigned flags = 0;
190 int reps = 1;
191 int ncpus = 1;
192 int c;
193
194 while ((c = getopt (argc, argv, "e:r:sf")) != -1) {
195 switch (c) {
196 case 'e':
197 if (strcmp(optarg, "rcs") == 0)
198 ring = I915_EXEC_RENDER;
199 else if (strcmp(optarg, "vcs") == 0)
200 ring = I915_EXEC_BSD;
201 else if (strcmp(optarg, "bcs") == 0)
202 ring = I915_EXEC_BLT;
203 else if (strcmp(optarg, "vecs") == 0)
204 ring = I915_EXEC_VEBOX;
205 else if (strcmp(optarg, "all") == 0)
206 ring = -1;
207 else
208 ring = atoi(optarg);
209 break;
210
211 case 'r':
212 reps = atoi(optarg);
213 if (reps < 1)
214 reps = 1;
215 break;
216
217 case 'f':
218 ncpus = sysconf(_SC_NPROCESSORS_ONLN);
219 break;
220
221 case 's':
222 flags |= SYNC;
223 break;
224
225 case 'W':
226 flags |= WRITE;
227 break;
228
229 case 'A':
230 flags |= READ_ALL;
231 break;
232
233 default:
234 break;
235 }
236 }
237
238 return loop(ring, reps, ncpus, flags);
239 }
240