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