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 enum mode { NOP, CREATE, SWITCH, DEFAULT };
49 #define SYNC 0x1
50
51 #define LOCAL_I915_EXEC_NO_RELOC (1<<11)
52 #define LOCAL_I915_EXEC_HANDLE_LUT (1<<12)
53
elapsed(const struct timespec * start,const struct timespec * end)54 static double elapsed(const struct timespec *start,
55 const struct timespec *end)
56 {
57 return (end->tv_sec - start->tv_sec) + 1e-9*(end->tv_nsec - start->tv_nsec);
58 }
59
batch(int fd)60 static uint32_t batch(int fd)
61 {
62 const uint32_t buf[] = {MI_BATCH_BUFFER_END};
63 uint32_t handle = gem_create(fd, 4096);
64 gem_write(fd, handle, 0, buf, sizeof(buf));
65 return handle;
66 }
67
__gem_context_create_local(int fd)68 static uint32_t __gem_context_create_local(int fd)
69 {
70 struct drm_i915_gem_context_create create;
71
72 memset(&create, 0, sizeof(create));
73 drmIoctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE, &create);
74
75 return create.ctx_id;
76 }
77
loop(unsigned ring,int reps,enum mode mode,int ncpus,unsigned flags)78 static int loop(unsigned ring,
79 int reps,
80 enum mode mode,
81 int ncpus,
82 unsigned flags)
83 {
84 struct drm_i915_gem_execbuffer2 execbuf;
85 struct drm_i915_gem_exec_object2 obj;
86 double *shared;
87 int fds[2], fd;
88
89 shared = mmap(0, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
90
91 fd = fds[0] = drm_open_driver(DRIVER_INTEL);
92 fds[1] = drm_open_driver(DRIVER_INTEL);
93
94 memset(&obj, 0, sizeof(obj));
95 obj.handle = batch(fd);
96 igt_assert(gem_open(fds[1], gem_flink(fds[0], obj.handle)) == obj.handle);
97
98 memset(&execbuf, 0, sizeof(execbuf));
99 execbuf.buffers_ptr = (uintptr_t)&obj;
100 execbuf.buffer_count = 1;
101 execbuf.flags = ring;
102 execbuf.flags |= LOCAL_I915_EXEC_HANDLE_LUT;
103 execbuf.flags |= LOCAL_I915_EXEC_NO_RELOC;
104 if (mode != DEFAULT) {
105 execbuf.rsvd1 = __gem_context_create_local(fd);
106 if (execbuf.rsvd1 == 0)
107 return 77;
108 }
109
110 if (__gem_execbuf(fd, &execbuf)) {
111 execbuf.flags = ring;
112 if (__gem_execbuf(fd, &execbuf))
113 return 77;
114 }
115 if (mode != DEFAULT && mode != NOP)
116 gem_context_destroy(fd, execbuf.rsvd1);
117
118 while (reps--) {
119 sleep(1); /* wait for the hw to go back to sleep */
120
121 memset(shared, 0, 4096);
122
123 igt_fork(child, ncpus) {
124 struct timespec start, end;
125 unsigned count = 0;
126 uint32_t ctx = 0;
127
128 if (mode != DEFAULT && mode != NOP) {
129 execbuf.rsvd1 = __gem_context_create_local(fd);
130 ctx = gem_context_create(fd);
131 }
132
133 clock_gettime(CLOCK_MONOTONIC, &start);
134 do {
135 uint32_t tmp;
136 switch (mode) {
137 case CREATE:
138 ctx = execbuf.rsvd1;
139 execbuf.rsvd1 = gem_context_create(fd);
140 break;
141
142 case SWITCH:
143 tmp = execbuf.rsvd1;
144 execbuf.rsvd1 = ctx;
145 ctx = tmp;
146 break;
147
148 case DEFAULT:
149 fd = fds[count & 1];
150 break;
151
152 case NOP:
153 break;
154 }
155 gem_execbuf(fd, &execbuf);
156 count++;
157 if (mode == CREATE)
158 gem_context_destroy(fd, ctx);
159
160 if (flags & SYNC)
161 gem_sync(fd, obj.handle);
162
163 clock_gettime(CLOCK_MONOTONIC, &end);
164 } while (elapsed(&start, &end) < 2.);
165
166 gem_sync(fd, obj.handle);
167
168 clock_gettime(CLOCK_MONOTONIC, &end);
169 shared[child] = 1e6*elapsed(&start, &end) / count;
170
171 if (mode != DEFAULT && mode != NOP) {
172 if (mode != CREATE)
173 gem_context_destroy(fd, ctx);
174 gem_context_destroy(fd, execbuf.rsvd1);
175 }
176 }
177 igt_waitchildren();
178
179 for (int child = 0; child < ncpus; child++)
180 shared[ncpus] += shared[child];
181 printf("%7.3f\n", shared[ncpus] / ncpus);
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 enum mode mode = NOP;
191 int reps = 1;
192 int ncpus = 1;
193 int c;
194
195 while ((c = getopt (argc, argv, "e:r:b:sf")) != -1) {
196 switch (c) {
197 case 'e':
198 if (strcmp(optarg, "rcs") == 0)
199 ring = I915_EXEC_RENDER;
200 else if (strcmp(optarg, "vcs") == 0)
201 ring = I915_EXEC_BSD;
202 else if (strcmp(optarg, "bcs") == 0)
203 ring = I915_EXEC_BLT;
204 else if (strcmp(optarg, "vecs") == 0)
205 ring = I915_EXEC_VEBOX;
206 else
207 ring = atoi(optarg);
208 break;
209
210 case 'b':
211 if (strcmp(optarg, "create") == 0)
212 mode = CREATE;
213 else if (strcmp(optarg, "switch") == 0)
214 mode = SWITCH;
215 else if (strcmp(optarg, "default") == 0)
216 mode = DEFAULT;
217 else if (strcmp(optarg, "nop") == 0)
218 mode = NOP;
219 else
220 abort();
221 break;
222
223 case 'f':
224 ncpus = sysconf(_SC_NPROCESSORS_ONLN);
225 break;
226
227 case 'r':
228 reps = atoi(optarg);
229 if (reps < 1)
230 reps = 1;
231 break;
232
233 case 's':
234 flags |= SYNC;
235 break;
236
237 default:
238 break;
239 }
240 }
241
242 return loop(ring, reps, mode, ncpus, flags);
243 }
244