• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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