e1cfc4e1de62f1e34dfa1699d29af09b374e4e4c
[platform/upstream/intel-gpu-tools.git] / tests / gem_fence_thrash.c
1 /*
2  * Copyright © 2008-9 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 <eric@anholt.net>
25  *    Chris Wilson <chris@chris-wilson.co.uk>
26  *
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <assert.h>
38 #include <fcntl.h>
39 #include <inttypes.h>
40 #include <errno.h>
41 #include <sys/stat.h>
42 #include <sys/ioctl.h>
43 #include <sys/mman.h>
44 #include <pthread.h>
45 #include "drm.h"
46 #include "i915_drm.h"
47 #include "drmtest.h"
48
49 #define OBJECT_SIZE (128*1024) /* restricted to 1MiB alignment on i915 fences */
50
51 /* Before introduction of the LRU list for fences, allocation of a fence for a page
52  * fault would use the first inactive fence (i.e. in preference one with no outstanding
53  * GPU activity, or it would wait on the first to finish). Given the choice, it would simply
54  * reuse the fence that had just been allocated for the previous page-fault - the worst choice
55  * when copying between two buffers and thus constantly swapping fences.
56  */
57
58 struct test {
59         int fd;
60         int tiling;
61         int num_surfaces;
62 };
63
64 static void *
65 bo_create (int fd, int tiling)
66 {
67         void *ptr;
68         int handle;
69
70         handle = gem_create(fd, OBJECT_SIZE);
71
72         /* dirty cpu caches a bit ... */
73         ptr = gem_mmap__cpu(fd, handle, OBJECT_SIZE, PROT_READ | PROT_WRITE);
74         assert(ptr);
75         memset(ptr, 0, OBJECT_SIZE);
76         munmap(ptr, OBJECT_SIZE);
77
78         gem_set_tiling(fd, handle, tiling, 1024);
79
80         ptr = gem_mmap(fd, handle, OBJECT_SIZE, PROT_READ | PROT_WRITE);
81         assert(ptr);
82
83         /* XXX: mmap_gtt pulls the bo into the GTT read domain. */
84         gem_sync(fd, handle);
85
86         return ptr;
87 }
88
89 static void *
90 bo_copy (void *_arg)
91 {
92         struct test *t = (struct test *)_arg;
93         int fd = t->fd;
94         int n;
95         char *a, *b;
96
97         a = bo_create (fd, t->tiling);
98         b = bo_create (fd, t->tiling);
99
100         for (n = 0; n < 1000; n++) {
101                 memcpy (a, b, OBJECT_SIZE);
102                 sched_yield ();
103         }
104
105         return NULL;
106 }
107
108 static void
109 _bo_write_verify(struct test *t)
110 {
111         int fd = t->fd;
112         int i, k;
113         uint32_t **s;
114         uint32_t v;
115         unsigned int dwords = OBJECT_SIZE >> 2;
116         const char *tile_str[] = { "none", "x", "y" };
117
118         assert (t->tiling >= 0 && t->tiling <= I915_TILING_Y);
119         assert (t->num_surfaces > 0);
120
121         s = calloc(sizeof(*s), t->num_surfaces);
122         assert(s);
123
124         for (k = 0; k < t->num_surfaces; k++)
125                 s[k] = bo_create(fd, t->tiling);
126
127         for (k = 0; k < t->num_surfaces; k++) {
128                 volatile uint32_t *a = s[k];
129
130                 for (i = 0; i < dwords; i++) {
131                         a[i] = i;
132                         v = a[i];
133                         if (v != i) {
134                                 printf("tiling %s: write failed at %d (%x)\n",
135                                        tile_str[t->tiling], i, v);
136                                 _exit(-1);
137                         }
138                 }
139
140                 for (i = 0; i < dwords; i++) {
141                         v = a[i];
142                         if (v != i) {
143                                 printf("tiling %s: verify failed at %d (%x)\n",
144                                        tile_str[t->tiling], i, v);
145                                 exit(-2);
146                         }
147                 }
148         }
149
150         for (k = 0; k < t->num_surfaces; k++)
151                 munmap(s[k], OBJECT_SIZE);
152
153         free(s);
154 }
155
156 static void *
157 bo_write_verify(void *_arg)
158 {
159         struct test *t = (struct test *)_arg;
160         int i;
161
162         for (i = 0; i < 10; i++)
163                 _bo_write_verify(t);
164
165         return 0;
166 }
167
168 static int run_test(int threads_per_fence, void *f, int tiling,
169                     int surfaces_per_thread)
170 {
171         struct test t;
172         pthread_t *threads;
173         int n, num_fences, num_threads;
174
175         t.fd = drm_open_any();
176         t.tiling = tiling;
177         t.num_surfaces = surfaces_per_thread;
178
179         num_fences = gem_available_fences(t.fd);
180         assert (num_fences > 0);
181
182         num_threads = threads_per_fence * num_fences;
183
184         printf("%s: threads %d, fences %d, tiling %d, surfaces per thread %d\n",
185                f == bo_copy ? "copy" : "write-verify", num_threads,
186                num_fences, tiling, surfaces_per_thread);
187
188         if (threads_per_fence) {
189                 threads = calloc(sizeof(*threads), num_threads);
190                 assert  (threads != NULL);
191
192                 for (n = 0; n < num_threads; n++)
193                         pthread_create (&threads[n], NULL, f, &t);
194
195                 for (n = 0; n < num_threads; n++)
196                         pthread_join (threads[n], NULL);
197         } else {
198                 void *(*func)(void *) = f;
199                 assert(func(&t) == (void *)0);
200         }
201
202         close(t.fd);
203
204         return 0;
205 }
206
207 int
208 main(int argc, char **argv)
209 {
210         drmtest_subtest_init(argc, argv);
211
212         if (drmtest_run_subtest("bo-write-verify-none"))
213                 assert (run_test(0, bo_write_verify, I915_TILING_NONE, 80) == 0);
214
215         if (drmtest_run_subtest("bo-write-verify-x"))
216                 assert (run_test(0, bo_write_verify, I915_TILING_X, 80) == 0);
217
218         if (drmtest_run_subtest("bo-write-verify-y"))
219                 assert (run_test(0, bo_write_verify, I915_TILING_Y, 80) == 0);
220
221         if (drmtest_run_subtest("bo-write-verify-threaded-none"))
222                 assert (run_test(5, bo_write_verify, I915_TILING_NONE, 2) == 0);
223
224         if (drmtest_run_subtest("bo-write-verify-threaded-x")) {
225                 assert (run_test(2, bo_write_verify, I915_TILING_X, 2) == 0);
226                 assert (run_test(5, bo_write_verify, I915_TILING_X, 2) == 0);
227                 assert (run_test(10, bo_write_verify, I915_TILING_X, 2) == 0);
228                 assert (run_test(20, bo_write_verify, I915_TILING_X, 2) == 0);
229         }
230
231         if (drmtest_run_subtest("bo-write-verify-threaded-y")) {
232                 assert (run_test(2, bo_write_verify, I915_TILING_Y, 2) == 0);
233                 assert (run_test(5, bo_write_verify, I915_TILING_Y, 2) == 0);
234                 assert (run_test(10, bo_write_verify, I915_TILING_Y, 2) == 0);
235                 assert (run_test(20, bo_write_verify, I915_TILING_Y, 2) == 0);
236         }
237
238         if (drmtest_run_subtest("bo-copy"))
239                 assert(run_test(1, bo_copy, I915_TILING_X, 1) == 0);
240
241         return 0;
242 }