• 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 "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 
pread_self(int i915)53 static void pread_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_WRITE);
64 
65 		gem_read(i915, handle, 0, ptr + MiB(3), MiB(1));
66 		gem_read(i915, handle, MiB(3), ptr, MiB(1));
67 		gem_read(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 #define LARGE_OBJECT_SIZE 1024 * 1024
76 #define KGRN "\x1B[32m"
77 #define KRED "\x1B[31m"
78 #define KNRM "\x1B[0m"
79 
do_gem_read(int fd,uint32_t handle,void * buf,int len,int loops)80 static void do_gem_read(int fd, uint32_t handle, void *buf, int len, int loops)
81 {
82 	while (loops--)
83 		gem_read(fd, handle, 0, buf, len);
84 }
85 
elapsed(const struct timeval * start,const struct timeval * end,int loop)86 static double elapsed(const struct timeval *start,
87 		      const struct timeval *end,
88 		      int loop)
89 {
90 	return (1e6*(end->tv_sec - start->tv_sec) + (end->tv_usec - start->tv_usec))/loop;
91 }
92 
bytes_per_sec(char * buf,double v)93 static const char *bytes_per_sec(char *buf, double v)
94 {
95 	const char *order[] = {
96 		"",
97 		"KiB",
98 		"MiB",
99 		"GiB",
100 		"TiB",
101 		NULL,
102 	}, **o = order;
103 
104 	while (v > 1000 && o[1]) {
105 		v /= 1000;
106 		o++;
107 	}
108 	sprintf(buf, "%.1f%s/s", v, *o);
109 	return buf;
110 }
111 
112 
113 uint32_t *src, dst;
114 uint32_t *dst_user, src_stolen, large_stolen;
115 uint32_t *stolen_pf_user, *stolen_nopf_user;
116 int fd, count;
117 int object_size = 0;
118 
opt_handler(int opt,int opt_index,void * data)119 static int opt_handler(int opt, int opt_index, void *data)
120 {
121 	switch (opt) {
122 	case 's':
123 		object_size = atoi(optarg);
124 		break;
125 	default:
126 		return IGT_OPT_HANDLER_ERROR;
127 	}
128 
129 	return IGT_OPT_HANDLER_SUCCESS;
130 }
131 
132 const char *help_str = "  -s\tObject size in bytes\n";
133 
134 igt_main_args("s:", NULL, help_str, opt_handler, NULL)
135 {
136 	double usecs;
137 	char buf[100];
138 	const char* bps;
139 	const struct {
140 		int level;
141 		const char *name;
142 	} cache[] = {
143 		{ 0, "uncached" },
144 		{ 1, "snoop" },
145 		{ 2, "display" },
146 		{ -1 },
147 	}, *c;
148 
149 	if (object_size == 0)
150 		object_size = OBJECT_SIZE;
151 	object_size = (object_size + 3) & -4;
152 
153 	igt_fixture {
154 		fd = drm_open_driver(DRIVER_INTEL);
155 
156 		dst = gem_create(fd, object_size);
157 		src = malloc(object_size);
158 		src_stolen = gem_create_stolen(fd, object_size);
159 		dst_user = malloc(object_size);
160 	}
161 
162 	igt_subtest("bench") {
163 		for (count = 1; count <= 1<<17; count <<= 1) {
164 			struct timeval start, end;
165 
166 			gettimeofday(&start, NULL);
167 			do_gem_read(fd, dst, src, object_size, count);
168 			gettimeofday(&end, NULL);
169 			usecs = elapsed(&start, &end, count);
170 			bps = bytes_per_sec(buf, object_size/usecs*1e6);
171 			igt_info("Time to pread %d bytes x %6d:	%7.3fµs, %s\n",
172 				 object_size, count, usecs, bps);
173 			fflush(stdout);
174 		}
175 	}
176 
177 	igt_subtest("self")
178 		pread_self(fd);
179 
180 	for (c = cache; c->level != -1; c++) {
181 		igt_subtest(c->name) {
182 			gem_set_caching(fd, dst, c->level);
183 
184 			for (count = 1; count <= 1<<17; count <<= 1) {
185 				struct timeval start, end;
186 
187 				gettimeofday(&start, NULL);
188 				do_gem_read(fd, dst, src, object_size, count);
189 				gettimeofday(&end, NULL);
190 				usecs = elapsed(&start, &end, count);
191 				bps = bytes_per_sec(buf, object_size/usecs*1e6);
192 				igt_info("Time to %s pread %d bytes x %6d:	%7.3fµs, %s\n",
193 					 c->name, object_size, count, usecs, bps);
194 				fflush(stdout);
195 			}
196 		}
197 	}
198 
199 	igt_subtest("stolen-normal") {
200 		gem_require_stolen_support(fd);
201 		for (count = 1; count <= 1<<17; count <<= 1) {
202 			struct timeval start, end;
203 
204 			gettimeofday(&start, NULL);
205 			do_gem_read(fd, src_stolen, dst_user, object_size, count);
206 			gettimeofday(&end, NULL);
207 			usecs = elapsed(&start, &end, count);
208 			bps = bytes_per_sec(buf, object_size/usecs*1e6);
209 			igt_info("Time to pread %d bytes x %6d:	%7.3fµs, %s\n",
210 				 object_size, count, usecs, bps);
211 			fflush(stdout);
212 		}
213 	}
214 	for (c = cache; c->level != -1; c++) {
215 		igt_subtest_f("stolen-%s", c->name) {
216 			gem_require_stolen_support(fd);
217 			gem_set_caching(fd, src_stolen, c->level);
218 
219 			for (count = 1; count <= 1<<17; count <<= 1) {
220 				struct timeval start, end;
221 
222 				gettimeofday(&start, NULL);
223 				do_gem_read(fd, src_stolen, dst_user,
224 					    object_size, count);
225 				gettimeofday(&end, NULL);
226 				usecs = elapsed(&start, &end, count);
227 				bps = bytes_per_sec(buf, object_size/usecs*1e6);
228 				igt_info("Time to stolen-%s pread %d bytes x %6d:      %7.3fµs, %s\n",
229 					 c->name, object_size, count, usecs, bps);
230 				fflush(stdout);
231 			}
232 		}
233 	}
234 
235 	/* List the time taken in pread operation for stolen objects, with
236 	 * and without the overhead of page fault handling on accessing the
237 	 * user space buffer
238 	 */
239 	igt_subtest("pagefault-pread") {
240 		gem_require_stolen_support(fd);
241 		large_stolen = gem_create_stolen(fd, LARGE_OBJECT_SIZE);
242 		stolen_nopf_user = (uint32_t *) mmap(NULL, LARGE_OBJECT_SIZE,
243 						PROT_WRITE,
244 						MAP_ANONYMOUS|MAP_PRIVATE,
245 						-1, 0);
246 		igt_assert(stolen_nopf_user);
247 
248 		for (count = 1; count <= 10; count ++) {
249 			struct timeval start, end;
250 			double t_elapsed = 0;
251 
252 			gettimeofday(&start, NULL);
253 			do_gem_read(fd, large_stolen, stolen_nopf_user,
254 				    LARGE_OBJECT_SIZE, 1);
255 			gettimeofday(&end, NULL);
256 			t_elapsed = elapsed(&start, &end, count);
257 			bps = bytes_per_sec(buf, object_size/t_elapsed*1e6);
258 			igt_info("Pagefault-N - Time to pread %d bytes: %7.3fµs, %s\n",
259 				 LARGE_OBJECT_SIZE, t_elapsed, bps);
260 
261 			stolen_pf_user = (uint32_t *) mmap(NULL, LARGE_OBJECT_SIZE,
262 						      PROT_WRITE,
263 						      MAP_ANONYMOUS|MAP_PRIVATE,
264 						      -1, 0);
265 			igt_assert(stolen_pf_user);
266 
267 			gettimeofday(&start, NULL);
268 			do_gem_read(fd, large_stolen, stolen_pf_user,
269 				    LARGE_OBJECT_SIZE, 1);
270 			gettimeofday(&end, NULL);
271 			usecs = elapsed(&start, &end, count);
272 			bps = bytes_per_sec(buf, object_size/usecs*1e6);
273 			igt_info("Pagefault-Y - Time to pread %d bytes: %7.3fµs, %s%s%s\n",
274 				 LARGE_OBJECT_SIZE, usecs,
275 				 t_elapsed < usecs ? KGRN : KRED, bps, KNRM);
276 			fflush(stdout);
277 			munmap(stolen_pf_user, LARGE_OBJECT_SIZE);
278 		}
279 		munmap(stolen_nopf_user, LARGE_OBJECT_SIZE);
280 		gem_close(fd, large_stolen);
281 	}
282 
283 
284 	igt_fixture {
285 		free(src);
286 		gem_close(fd, dst);
287 		free(dst_user);
288 		gem_close(fd, src_stolen);
289 
290 		close(fd);
291 	}
292 }
293