xref: /aosp_15_r20/external/igt-gpu-tools/tests/i915/gem_pwrite.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
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 <[email protected]>
25  *
26  */
27 
28 #include "igt.h"
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <fcntl.h>
35 #include <inttypes.h>
36 #include <errno.h>
37 #include <sys/stat.h>
38 #include <sys/ioctl.h>
39 #include <sys/time.h>
40 #include "drm.h"
41 
42 #define MiB(x) ((x) * 1024 * 1024)
43 
44 typedef void *(*mmap_fn_t)(int, uint32_t, uint64_t, uint64_t, unsigned int);
45 
wrap_gem_mmap__gtt(int i915,uint32_t handle,uint64_t offset,uint64_t length,unsigned int prot)46 static void *wrap_gem_mmap__gtt(int i915, uint32_t handle,
47 				uint64_t offset, uint64_t length,
48 				unsigned int prot)
49 {
50 	return gem_mmap__gtt(i915, handle, length, prot);
51 }
52 
pwrite_self(int i915)53 static void pwrite_self(int i915)
54 {
55 	static const mmap_fn_t mmap_fn[] = {
56 		wrap_gem_mmap__gtt,
57 		gem_mmap__cpu,
58 		gem_mmap__wc,
59 		NULL
60 	};
61 	for (const mmap_fn_t *fn = mmap_fn; *fn; fn++) {
62 		uint32_t handle = gem_create(i915, MiB(4));
63 		void *ptr = (*fn)(i915, handle, 0, MiB(4), PROT_READ);
64 
65 		gem_write(i915, handle, 0, ptr + MiB(3), MiB(1));
66 		gem_write(i915, handle, MiB(3), ptr, MiB(1));
67 		gem_write(i915, handle, MiB(1), ptr + MiB(1), MiB(2));
68 
69 		munmap(ptr, MiB(4));
70 		gem_close(i915, handle);
71 	}
72 }
73 
74 #define OBJECT_SIZE 16384
75 
76 #define COPY_BLT_CMD		(2<<29|0x53<<22|0x6)
77 #define BLT_WRITE_ALPHA		(1<<21)
78 #define BLT_WRITE_RGB		(1<<20)
79 #define BLT_SRC_TILED		(1<<15)
80 #define BLT_DST_TILED		(1<<11)
81 
do_gem_write(int fd,uint32_t handle,void * buf,int len,int loops)82 static void do_gem_write(int fd, uint32_t handle, void *buf, int len, int loops)
83 {
84 	while (loops--)
85 		gem_write(fd, handle, 0, buf, len);
86 }
87 
elapsed(const struct timeval * start,const struct timeval * end,int loop)88 static double elapsed(const struct timeval *start,
89 		      const struct timeval *end,
90 		      int loop)
91 {
92 	return (1e6*(end->tv_sec - start->tv_sec) + (end->tv_usec - start->tv_usec))/loop;
93 }
94 
bytes_per_sec(char * buf,double v)95 static const char *bytes_per_sec(char *buf, double v)
96 {
97 	const char *order[] = {
98 		"",
99 		"KiB",
100 		"MiB",
101 		"GiB",
102 		"TiB",
103 		NULL,
104 	}, **o = order;
105 
106 	while (v > 1000 && o[1]) {
107 		v /= 1000;
108 		o++;
109 	}
110 	sprintf(buf, "%.1f%s/s", v, *o);
111 	return buf;
112 }
113 
114 #define FORWARD 0x1
115 #define BACKWARD 0x2
116 #define RANDOM 0x4
test_big_cpu(int fd,int scale,unsigned flags)117 static void test_big_cpu(int fd, int scale, unsigned flags)
118 {
119 	uint64_t offset, size;
120 	uint32_t handle;
121 
122 	switch (scale) {
123 	case 0:
124 		size = gem_mappable_aperture_size() + 4096;
125 		break;
126 	case 1:
127 		size = gem_global_aperture_size(fd) + 4096;
128 		break;
129 	case 2:
130 		size = gem_aperture_size(fd) + 4096;
131 		break;
132 	}
133 	intel_require_memory(1, size, CHECK_RAM);
134 
135 	handle = gem_create(fd, size);
136 	gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
137 
138 	if (flags & FORWARD) {
139 		igt_debug("Forwards\n");
140 		for (offset = 0; offset < size; offset += 4096) {
141 			int suboffset = (offset >> 12) % (4096 - sizeof(offset));
142 			uint64_t tmp;
143 
144 			gem_write(fd, handle, offset + suboffset, &offset, sizeof(offset));
145 			gem_read(fd, handle, offset + suboffset, &tmp, sizeof(tmp));
146 			igt_assert_eq_u64(offset, tmp);
147 		}
148 	}
149 
150 	if (flags & BACKWARD) {
151 		igt_debug("Backwards\n");
152 		for (offset = size >> 12; offset--; ) {
153 			int suboffset = 4096 - (offset % (4096 - sizeof(offset)));
154 			uint64_t tmp;
155 
156 			gem_write(fd, handle, (offset<<12) + suboffset, &offset, sizeof(offset));
157 			gem_read(fd, handle, (offset<<12) + suboffset, &tmp, sizeof(tmp));
158 			igt_assert_eq_u64(offset, tmp);
159 		}
160 	}
161 
162 	if (flags & RANDOM) {
163 		igt_debug("Random\n");
164 		for (offset = 0; offset < size >> 12; offset++) {
165 			uint64_t tmp = rand() % (size >> 12);
166 			int suboffset = tmp % (4096 - sizeof(offset));
167 
168 			gem_write(fd, handle, (tmp << 12) + suboffset, &offset, sizeof(offset));
169 			gem_read(fd, handle, (tmp << 12) + suboffset, &tmp, sizeof(tmp));
170 			igt_assert_eq_u64(offset, tmp);
171 		}
172 	}
173 
174 	gem_close(fd, handle);
175 }
176 
test_big_gtt(int fd,int scale,unsigned flags)177 static void test_big_gtt(int fd, int scale, unsigned flags)
178 {
179 	uint64_t offset, size;
180 	uint64_t *ptr;
181 	uint32_t handle;
182 
183 	igt_require(gem_mmap__has_wc(fd));
184 	switch (scale) {
185 	case 0:
186 		size = gem_mappable_aperture_size() + 4096;
187 		break;
188 	case 1:
189 		size = gem_global_aperture_size(fd) + 4096;
190 		break;
191 	case 2:
192 		size = gem_aperture_size(fd) + 4096;
193 		break;
194 	}
195 	intel_require_memory(1, size, CHECK_RAM);
196 
197 	handle = gem_create(fd, size);
198 	gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
199 
200 	ptr = gem_mmap__wc(fd, handle, 0, size, PROT_READ);
201 
202 	if (flags & FORWARD) {
203 		igt_debug("Forwards\n");
204 		for (offset = 0; offset < size; offset += 4096) {
205 			int suboffset = (offset >> 12) % (4096 / sizeof(offset) - 1) * sizeof(offset);
206 
207 			gem_write(fd, handle, offset + suboffset, &offset, sizeof(offset));
208 			gem_set_domain(fd, handle, I915_GEM_DOMAIN_WC, 0);
209 			igt_assert_eq_u64(ptr[(offset + suboffset)/sizeof(offset)], offset);
210 		}
211 	}
212 
213 	if (flags & BACKWARD) {
214 		igt_debug("Backwards\n");
215 		for (offset = size >> 12; offset--; ) {
216 			int suboffset = (4096 - (offset % (4096 - sizeof(offset)))) & -sizeof(offset);
217 			gem_write(fd, handle, (offset<<12) + suboffset, &offset, sizeof(offset));
218 			gem_set_domain(fd, handle, I915_GEM_DOMAIN_WC, 0);
219 			igt_assert_eq_u64(ptr[((offset<<12) + suboffset)/sizeof(offset)], offset);
220 		}
221 	}
222 
223 	if (flags & RANDOM) {
224 		igt_debug("Random\n");
225 		for (offset = 0; offset < size >> 12; offset++) {
226 			uint64_t tmp = rand() % (size >> 12);
227 			int suboffset = (tmp % 4096) & -sizeof(offset);
228 
229 			tmp = (tmp << 12) + suboffset;
230 			gem_write(fd, handle, tmp, &offset, sizeof(offset));
231 			gem_set_domain(fd, handle, I915_GEM_DOMAIN_WC, 0);
232 			igt_assert_eq_u64(ptr[tmp/sizeof(offset)], offset);
233 		}
234 	}
235 
236 	munmap(ptr, size);
237 	gem_close(fd, handle);
238 }
239 
240 uint32_t *src, dst;
241 uint32_t *src_user, dst_stolen;
242 int fd;
243 int object_size = 0;
244 
opt_handler(int opt,int opt_index,void * data)245 static int opt_handler(int opt, int opt_index, void *data)
246 {
247 	switch (opt) {
248 	case 's':
249 		object_size = atoi(optarg);
250 		break;
251 	default:
252 		return IGT_OPT_HANDLER_ERROR;
253 	}
254 
255 	return IGT_OPT_HANDLER_SUCCESS;
256 }
257 
258 const char *help_str = "  -s\tObject size in bytes\n";
259 
260 igt_main_args("s:", NULL, help_str, opt_handler, NULL)
261 {
262 	double usecs;
263 	const char* bps;
264 	char buf[100];
265 	int count;
266 	const struct {
267 		int level;
268 		const char *name;
269 	} cache[] = {
270 		{ 0, "uncached" },
271 		{ 1, "snoop" },
272 		{ 2, "display" },
273 		{ -1 },
274 	}, *c;
275 
276 	if (object_size == 0)
277 		object_size = OBJECT_SIZE;
278 	object_size = (object_size + 3) & -4;
279 
280 	igt_fixture {
281 		fd = drm_open_driver(DRIVER_INTEL);
282 
283 		dst = gem_create(fd, object_size);
284 		src = malloc(object_size);
285 		dst_stolen = gem_create_stolen(fd, object_size);
286 		src_user = malloc(object_size);
287 	}
288 
289 	igt_subtest("bench") {
290 		for (count = 1; count <= 1<<17; count <<= 1) {
291 			struct timeval start, end;
292 
293 			gettimeofday(&start, NULL);
294 			do_gem_write(fd, dst, src, object_size, count);
295 			gettimeofday(&end, NULL);
296 			usecs = elapsed(&start, &end, count);
297 			bps = bytes_per_sec(buf, object_size/usecs*1e6);
298 			igt_info("Time to pwrite %d bytes x %6d:	%7.3fµs, %s\n",
299 				 object_size, count, usecs, bps);
300 			fflush(stdout);
301 		}
302 	}
303 
304 	igt_subtest("self")
305 		pwrite_self(fd);
306 
307 	for (c = cache; c->level != -1; c++) {
308 		igt_subtest(c->name) {
309 			gem_set_caching(fd, dst, c->level);
310 
311 			for (count = 1; count <= 1<<17; count <<= 1) {
312 				struct timeval start, end;
313 
314 				gettimeofday(&start, NULL);
315 				do_gem_write(fd, dst, src, object_size, count);
316 				gettimeofday(&end, NULL);
317 				usecs = elapsed(&start, &end, count);
318 				bps = bytes_per_sec(buf, object_size/usecs*1e6);
319 				igt_info("Time to %s pwrite %d bytes x %6d:	%7.3fµs, %s\n",
320 					 c->name, object_size, count, usecs, bps);
321 				fflush(stdout);
322 			}
323 		}
324 	}
325 
326 	igt_subtest("stolen-normal") {
327 		gem_require_stolen_support(fd);
328 		for (count = 1; count <= 1<<17; count <<= 1) {
329 			struct timeval start, end;
330 
331 			gettimeofday(&start, NULL);
332 			do_gem_write(fd, dst_stolen, src_user,
333 				     object_size, count);
334 			gettimeofday(&end, NULL);
335 			usecs = elapsed(&start, &end, count);
336 			bps = bytes_per_sec(buf, object_size/usecs*1e6);
337 			igt_info("Time to pwrite %d bytes x %6d:        %7.3fµs, %s\n",
338 				 object_size, count, usecs, bps);
339 			fflush(stdout);
340 		}
341 	}
342 
343 	for (c = cache; c->level != -1; c++) {
344 		igt_subtest_f("stolen-%s", c->name) {
345 			gem_require_stolen_support(fd);
346 			gem_set_caching(fd, dst, c->level);
347 			for (count = 1; count <= 1<<17; count <<= 1) {
348 				struct timeval start, end;
349 
350 				gettimeofday(&start, NULL);
351 				do_gem_write(fd, dst_stolen, src_user,
352 					     object_size, count);
353 				gettimeofday(&end, NULL);
354 				bps = bytes_per_sec(buf,
355 						    object_size/usecs*1e6);
356 				igt_info("Time to stolen-%s pwrite %d bytes x %6d:     %7.3fµs, %s\n",
357 					 c->name, object_size, count,
358 					 usecs, bps);
359 				fflush(stdout);
360 			}
361 		}
362 	}
363 
364 	igt_fixture {
365 		free(src);
366 		gem_close(fd, dst);
367 		free(src_user);
368 		gem_close(fd, dst_stolen);
369 	}
370 
371 	{
372 		const struct mode {
373 			const char *name;
374 			unsigned flags;
375 		} modes[] = {
376 			{ "forwards", FORWARD },
377 			{ "backwards", BACKWARD },
378 			{ "random", RANDOM },
379 			{ "fbr", FORWARD | BACKWARD | RANDOM },
380 			{ NULL },
381 		}, *m;
382 		for (m = modes; m->name; m++) {
383 			igt_subtest_f("small-cpu-%s", m->name)
384 				test_big_cpu(fd, 0, m->flags);
385 			igt_subtest_f("small-gtt-%s", m->name)
386 				test_big_gtt(fd, 0, m->flags);
387 
388 			igt_subtest_f("big-cpu-%s", m->name)
389 				test_big_cpu(fd, 1, m->flags);
390 			igt_subtest_f("big-gtt-%s", m->name)
391 				test_big_gtt(fd, 1, m->flags);
392 
393 			igt_subtest_f("huge-cpu-%s", m->name)
394 				test_big_cpu(fd, 2, m->flags);
395 			igt_subtest_f("huge-gtt-%s", m->name)
396 				test_big_gtt(fd, 2, m->flags);
397 		}
398 	}
399 
400 	igt_fixture
401 		close(fd);
402 }
403