xref: /aosp_15_r20/external/igt-gpu-tools/tests/i915/gem_gtt_speed.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
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