1 /*
2 * Copyright © 2010 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 * Eric Anholt <[email protected]>
25 * Chris Wilson <[email protected]>
26 *
27 */
28
29 #include "igt.h"
30 #include "igt_x86.h"
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <fcntl.h>
37 #include <inttypes.h>
38 #include <errno.h>
39 #include <sys/stat.h>
40 #include <sys/ioctl.h>
41 #include <sys/time.h>
42 #include "drm.h"
43
44 #define OBJECT_SIZE 16384
45
elapsed(const struct timeval * start,const struct timeval * end,int loop)46 static double elapsed(const struct timeval *start,
47 const struct timeval *end,
48 int loop)
49 {
50 return (1e6*(end->tv_sec - start->tv_sec) + (end->tv_usec - start->tv_usec))/loop;
51 }
52
53 #if defined(__x86_64__) && !defined(__clang__)
54 #pragma GCC push_options
55 #pragma GCC target("sse4.1")
56 #include <smmintrin.h>
57 __attribute__((noinline))
streaming_load(void * src,int len)58 static void streaming_load(void *src, int len)
59 {
60 __m128i tmp, *s = src;
61
62 igt_assert((len & 15) == 0);
63 igt_assert((((uintptr_t)src) & 15) == 0);
64
65 while (len >= 16) {
66 tmp += _mm_stream_load_si128(s++);
67 len -= 16;
68
69 }
70
71 *(volatile __m128i *)src = tmp;
72 }
x86_64_features(void)73 static inline unsigned x86_64_features(void)
74 {
75 return igt_x86_features();
76 }
77 #pragma GCC pop_options
78 #else
x86_64_features(void)79 static inline unsigned x86_64_features(void)
80 {
81 return 0;
82 }
streaming_load(void * src,int len)83 static void streaming_load(void *src, int len)
84 {
85 igt_assert(!"reached");
86 }
87 #endif
88
89 int size = OBJECT_SIZE;
90
opt_handler(int opt,int opt_index,void * data)91 static int opt_handler(int opt, int opt_index, void *data)
92 {
93 switch (opt) {
94 case 's':
95 size = atoi(optarg);
96 break;
97 default:
98 return IGT_OPT_HANDLER_ERROR;
99 }
100
101 return IGT_OPT_HANDLER_SUCCESS;
102 }
103
104 const char *help_str = " -s\tObject size in bytes\n";
105
106 igt_simple_main_args("s:", NULL, help_str, opt_handler, NULL)
107 {
108 struct timeval start, end;
109 uint8_t *buf;
110 uint32_t handle;
111 unsigned cpu = x86_64_features();
112 int loop, i, tiling;
113 int fd;
114
115 igt_skip_on_simulation();
116
117 igt_assert_f(size != 0, "Invalid object size specified\n");
118
119 if (cpu) {
120 char str[1024];
121 igt_info("Detected cpu faatures: %s\n",
122 igt_x86_features_to_string(cpu, str));
123 }
124
125 buf = malloc(size);
126 memset(buf, 0, size);
127 fd = drm_open_driver(DRIVER_INTEL);
128
129 handle = gem_create(fd, size);
130 igt_assert(handle);
131
132 for (tiling = I915_TILING_NONE; tiling <= I915_TILING_Y; tiling++) {
133 if (tiling != I915_TILING_NONE) {
134 igt_info("\nSetting tiling mode to %s\n",
135 tiling == I915_TILING_X ? "X" : "Y");
136 gem_set_tiling(fd, handle, tiling, 512);
137 }
138
139 if (tiling == I915_TILING_NONE) {
140 gem_set_domain(fd, handle,
141 I915_GEM_DOMAIN_CPU,
142 I915_GEM_DOMAIN_CPU);
143
144 {
145 uint32_t *base = gem_mmap__cpu(fd, handle, 0, size, PROT_READ | PROT_WRITE);
146 volatile uint32_t *ptr = base;
147 int x = 0;
148
149 for (i = 0; i < size/sizeof(*ptr); i++)
150 x += ptr[i];
151
152 /* force overly clever gcc to actually compute x */
153 ptr[0] = x;
154
155 munmap(base, size);
156
157 /* mmap read */
158 gettimeofday(&start, NULL);
159 for (loop = 0; loop < 1000; loop++) {
160 base = gem_mmap__cpu(fd, handle, 0,
161 size,
162 PROT_READ | PROT_WRITE);
163 ptr = base;
164 x = 0;
165
166 for (i = 0; i < size/sizeof(*ptr); i++)
167 x += ptr[i];
168
169 /* force overly clever gcc to actually compute x */
170 ptr[0] = x;
171
172 munmap(base, size);
173 }
174 gettimeofday(&end, NULL);
175 igt_info("Time to read %dk through a CPU map: %7.3fµs\n",
176 size/1024, elapsed(&start, &end, loop));
177 {
178 base = gem_mmap__cpu(fd, handle, 0,
179 size,
180 PROT_READ | PROT_WRITE);
181 gettimeofday(&start, NULL);
182 for (loop = 0; loop < 1000; loop++) {
183 ptr = base;
184 x = 0;
185
186 for (i = 0; i < size/sizeof(*ptr); i++)
187 x += ptr[i];
188
189 /* force overly clever gcc to actually compute x */
190 ptr[0] = x;
191
192 }
193 gettimeofday(&end, NULL);
194 munmap(base, size);
195 igt_info("Time to read %dk through a cached CPU map: %7.3fµs\n",
196 size/1024, elapsed(&start, &end, loop));
197 }
198
199 /* mmap write */
200 gettimeofday(&start, NULL);
201 for (loop = 0; loop < 1000; loop++) {
202 base = gem_mmap__cpu(fd, handle, 0,
203 size,
204 PROT_READ | PROT_WRITE);
205 ptr = base;
206
207 for (i = 0; i < size/sizeof(*ptr); i++)
208 ptr[i] = i;
209
210 munmap(base, size);
211 }
212 gettimeofday(&end, NULL);
213 igt_info("Time to write %dk through a CPU map: %7.3fµs\n",
214 size/1024, elapsed(&start, &end, loop));
215
216 gettimeofday(&start, NULL);
217 for (loop = 0; loop < 1000; loop++) {
218 base = gem_mmap__cpu(fd, handle, 0,
219 size,
220 PROT_READ | PROT_WRITE);
221 memset(base, 0, size);
222 munmap(base, size);
223 }
224 gettimeofday(&end, NULL);
225 igt_info("Time to clear %dk through a CPU map: %7.3fµs\n",
226 size/1024, elapsed(&start, &end, loop));
227
228 gettimeofday(&start, NULL);
229 base = gem_mmap__cpu(fd, handle, 0, size,
230 PROT_READ | PROT_WRITE);
231 for (loop = 0; loop < 1000; loop++)
232 memset(base, 0, size);
233 munmap(base, size);
234 gettimeofday(&end, NULL);
235 igt_info("Time to clear %dk through a cached CPU map: %7.3fµs\n",
236 size/1024, elapsed(&start, &end, loop));
237 }
238
239 /* CPU pwrite */
240 gettimeofday(&start, NULL);
241 for (loop = 0; loop < 1000; loop++)
242 gem_write(fd, handle, 0, buf, size);
243 gettimeofday(&end, NULL);
244 igt_info("Time to pwrite %dk through the CPU: %7.3fµs\n",
245 size/1024, elapsed(&start, &end, loop));
246
247 /* CPU pread */
248 gettimeofday(&start, NULL);
249 for (loop = 0; loop < 1000; loop++)
250 gem_read(fd, handle, 0, buf, size);
251 gettimeofday(&end, NULL);
252 igt_info("Time to pread %dk through the CPU: %7.3fµs\n",
253 size/1024, elapsed(&start, &end, loop));
254 }
255
256 /* prefault into gtt */
257 {
258 uint32_t *base = gem_mmap__gtt(fd, handle, size, PROT_READ | PROT_WRITE);
259 volatile uint32_t *ptr = base;
260 int x = 0;
261
262 for (i = 0; i < size/sizeof(*ptr); i++)
263 x += ptr[i];
264
265 /* force overly clever gcc to actually compute x */
266 ptr[0] = x;
267
268 munmap(base, size);
269 }
270 /* mmap read */
271 gettimeofday(&start, NULL);
272 for (loop = 0; loop < 1000; loop++) {
273 uint32_t *base = gem_mmap__gtt(fd, handle, size, PROT_READ | PROT_WRITE);
274 volatile uint32_t *ptr = base;
275 int x = 0;
276
277 for (i = 0; i < size/sizeof(*ptr); i++)
278 x += ptr[i];
279
280 /* force overly clever gcc to actually compute x */
281 ptr[0] = x;
282
283 munmap(base, size);
284 }
285 gettimeofday(&end, NULL);
286 igt_info("Time to read %dk through a GTT map: %7.3fµs\n",
287 size/1024, elapsed(&start, &end, loop));
288
289 if (gem_mmap__has_wc(fd)) {
290 gettimeofday(&start, NULL);
291 for (loop = 0; loop < 1000; loop++) {
292 uint32_t *base = gem_mmap__wc(fd, handle, 0, size, PROT_READ | PROT_WRITE);
293 volatile uint32_t *ptr = base;
294 int x = 0;
295
296 for (i = 0; i < size/sizeof(*ptr); i++)
297 x += ptr[i];
298
299 /* force overly clever gcc to actually compute x */
300 ptr[0] = x;
301
302 munmap(base, size);
303 }
304 gettimeofday(&end, NULL);
305 igt_info("Time to read %dk through a WC map: %7.3fµs\n",
306 size/1024, elapsed(&start, &end, loop));
307
308 {
309 uint32_t *base = gem_mmap__wc(fd, handle, 0, size, PROT_READ | PROT_WRITE);
310 gettimeofday(&start, NULL);
311 for (loop = 0; loop < 1000; loop++) {
312 volatile uint32_t *ptr = base;
313 int x = 0;
314
315 for (i = 0; i < size/sizeof(*ptr); i++)
316 x += ptr[i];
317
318 /* force overly clever gcc to actually compute x */
319 ptr[0] = x;
320
321 }
322 gettimeofday(&end, NULL);
323 munmap(base, size);
324 }
325 igt_info("Time to read %dk through a cached WC map: %7.3fµs\n",
326 size/1024, elapsed(&start, &end, loop));
327
328 /* Check streaming loads from WC */
329 if (cpu & SSE4_1) {
330 gettimeofday(&start, NULL);
331 for (loop = 0; loop < 1000; loop++) {
332 uint32_t *base = gem_mmap__wc(fd, handle, 0, size, PROT_READ | PROT_WRITE);
333 streaming_load(base, size);
334
335 munmap(base, size);
336 }
337 gettimeofday(&end, NULL);
338 igt_info("Time to stream %dk from a WC map: %7.3fµs\n",
339 size/1024, elapsed(&start, &end, loop));
340
341 {
342 uint32_t *base = gem_mmap__wc(fd, handle, 0, size, PROT_READ | PROT_WRITE);
343 gettimeofday(&start, NULL);
344 for (loop = 0; loop < 1000; loop++)
345 streaming_load(base, size);
346 gettimeofday(&end, NULL);
347 munmap(base, size);
348 }
349 igt_info("Time to stream %dk from a cached WC map: %7.3fµs\n",
350 size/1024, elapsed(&start, &end, loop));
351 }
352 }
353
354
355 /* mmap write */
356 gettimeofday(&start, NULL);
357 for (loop = 0; loop < 1000; loop++) {
358 uint32_t *base = gem_mmap__gtt(fd, handle, size, PROT_READ | PROT_WRITE);
359 volatile uint32_t *ptr = base;
360
361 for (i = 0; i < size/sizeof(*ptr); i++)
362 ptr[i] = i;
363
364 munmap(base, size);
365 }
366 gettimeofday(&end, NULL);
367 igt_info("Time to write %dk through a GTT map: %7.3fµs\n",
368 size/1024, elapsed(&start, &end, loop));
369
370 if (gem_mmap__has_wc(fd)) {
371 /* mmap write */
372 gettimeofday(&start, NULL);
373 for (loop = 0; loop < 1000; loop++) {
374 uint32_t *base = gem_mmap__wc(fd, handle, 0, size, PROT_READ | PROT_WRITE);
375 volatile uint32_t *ptr = base;
376
377 for (i = 0; i < size/sizeof(*ptr); i++)
378 ptr[i] = i;
379
380 munmap(base, size);
381 }
382 gettimeofday(&end, NULL);
383 igt_info("Time to write %dk through a WC map: %7.3fµs\n",
384 size/1024, elapsed(&start, &end, loop));
385 }
386
387 /* mmap clear */
388 gettimeofday(&start, NULL);
389 for (loop = 0; loop < 1000; loop++) {
390 uint32_t *base = gem_mmap__gtt(fd, handle, size, PROT_READ | PROT_WRITE);
391 memset(base, 0, size);
392 munmap(base, size);
393 }
394 gettimeofday(&end, NULL);
395 igt_info("Time to clear %dk through a GTT map: %7.3fµs\n",
396 size/1024, elapsed(&start, &end, loop));
397
398 if (gem_mmap__has_wc(fd)) {
399 /* mmap clear */
400 gettimeofday(&start, NULL);
401 for (loop = 0; loop < 1000; loop++) {
402 uint32_t *base = gem_mmap__wc(fd, handle, 0, size, PROT_READ | PROT_WRITE);
403 memset(base, 0, size);
404 munmap(base, size);
405 }
406 gettimeofday(&end, NULL);
407 igt_info("Time to clear %dk through a WC map: %7.3fµs\n",
408 size/1024, elapsed(&start, &end, loop));
409 }
410
411 gettimeofday(&start, NULL);{
412 uint32_t *base = gem_mmap__gtt(fd, handle, size, PROT_READ | PROT_WRITE);
413 for (loop = 0; loop < 1000; loop++)
414 memset(base, 0, size);
415 munmap(base, size);
416 } gettimeofday(&end, NULL);
417 igt_info("Time to clear %dk through a cached GTT map: %7.3fµs\n",
418 size/1024, elapsed(&start, &end, loop));
419
420 if (gem_mmap__has_wc(fd)) {
421 gettimeofday(&start, NULL);{
422 uint32_t *base = gem_mmap__wc(fd, handle, 0, size, PROT_READ | PROT_WRITE);
423 for (loop = 0; loop < 1000; loop++)
424 memset(base, 0, size);
425 munmap(base, size);
426 } gettimeofday(&end, NULL);
427 igt_info("Time to clear %dk through a cached WC map: %7.3fµs\n",
428 size/1024, elapsed(&start, &end, loop));
429 }
430
431 /* mmap read */
432 gettimeofday(&start, NULL);
433 for (loop = 0; loop < 1000; loop++) {
434 uint32_t *base = gem_mmap__gtt(fd, handle, size, PROT_READ | PROT_WRITE);
435 volatile uint32_t *ptr = base;
436 int x = 0;
437
438 for (i = 0; i < size/sizeof(*ptr); i++)
439 x += ptr[i];
440
441 /* force overly clever gcc to actually compute x */
442 ptr[0] = x;
443
444 munmap(base, size);
445 }
446 gettimeofday(&end, NULL);
447 igt_info("Time to read %dk (again) through a GTT map: %7.3fµs\n",
448 size/1024, elapsed(&start, &end, loop));
449
450 if (tiling == I915_TILING_NONE) {
451 /* GTT pwrite */
452 gettimeofday(&start, NULL);
453 for (loop = 0; loop < 1000; loop++)
454 gem_write(fd, handle, 0, buf, size);
455 gettimeofday(&end, NULL);
456 igt_info("Time to pwrite %dk through the GTT: %7.3fµs\n",
457 size/1024, elapsed(&start, &end, loop));
458
459 /* GTT pread */
460 gettimeofday(&start, NULL);
461 for (loop = 0; loop < 1000; loop++)
462 gem_read(fd, handle, 0, buf, size);
463 gettimeofday(&end, NULL);
464 igt_info("Time to pread %dk through the GTT: %7.3fµs\n",
465 size/1024, elapsed(&start, &end, loop));
466
467 /* GTT pwrite, including clflush */
468 gettimeofday(&start, NULL);
469 for (loop = 0; loop < 1000; loop++) {
470 gem_write(fd, handle, 0, buf, size);
471 gem_sync(fd, handle);
472 }
473 gettimeofday(&end, NULL);
474 igt_info("Time to pwrite %dk through the GTT (clflush): %7.3fµs\n",
475 size/1024, elapsed(&start, &end, loop));
476
477 /* GTT pread, including clflush */
478 gettimeofday(&start, NULL);
479 for (loop = 0; loop < 1000; loop++) {
480 gem_sync(fd, handle);
481 gem_read(fd, handle, 0, buf, size);
482 }
483 gettimeofday(&end, NULL);
484 igt_info("Time to pread %dk through the GTT (clflush): %7.3fµs\n",
485 size/1024, elapsed(&start, &end, loop));
486
487 /* partial writes */
488 igt_info("Now partial writes.\n");
489 size /= 4;
490
491 /* partial GTT pwrite, including clflush */
492 gettimeofday(&start, NULL);
493 for (loop = 0; loop < 1000; loop++) {
494 gem_write(fd, handle, 0, buf, size);
495 gem_sync(fd, handle);
496 }
497 gettimeofday(&end, NULL);
498 igt_info("Time to pwrite %dk through the GTT (clflush): %7.3fµs\n",
499 size/1024, elapsed(&start, &end, loop));
500
501 /* partial GTT pread, including clflush */
502 gettimeofday(&start, NULL);
503 for (loop = 0; loop < 1000; loop++) {
504 gem_sync(fd, handle);
505 gem_read(fd, handle, 0, buf, size);
506 }
507 gettimeofday(&end, NULL);
508 igt_info("Time to pread %dk through the GTT (clflush): %7.3fµs\n",
509 size/1024, elapsed(&start, &end, loop));
510
511 size *= 4;
512 }
513 }
514
515 gem_close(fd, handle);
516 close(fd);
517 }
518