blob: 300eb03d28b4a6960ebf0982092ede510061525b [file] [log] [blame]
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +00001/*
2 * Copyright © 2007, 2011, 2013, 2014 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 * Daniel Vetter <daniel.vetter@ffwll.ch>
26 * Tvrtko Ursulin <tvrtko.ursulin@intel.com>
27 *
28 */
29
Thomas Wood804e11f2015-08-17 17:57:43 +010030#include "igt.h"
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +000031#include <stdlib.h>
32
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +000033
Chris Wilson0e207142016-01-25 13:51:00 +000034struct igt_eviction_test_ops {
Thomas Wood7a5e1c62015-05-14 16:38:01 +010035 uint32_t (*create)(int fd, uint64_t size);
Chris Wilson784b7722014-07-21 09:12:43 +010036 void (*flink)(uint32_t old_handle, uint32_t new_handle);
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +000037 void (*close)(int fd, uint32_t bo);
Chris Wilsona384e552014-06-03 07:31:49 +010038 int (*copy)(int fd, uint32_t dst, uint32_t src,
39 uint32_t *all_bo, int nr_bos);
Chris Wilson0e207142016-01-25 13:51:00 +000040 void (*clear)(int fd, uint32_t bo, uint64_t size);
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +000041};
42
43#define FORKING_EVICTIONS_INTERRUPTIBLE (1 << 0)
44#define FORKING_EVICTIONS_SWAPPING (1 << 1)
45#define FORKING_EVICTIONS_DUP_DRMFD (1 << 2)
46#define FORKING_EVICTIONS_MEMORY_PRESSURE (1 << 3)
47#define ALL_FORKING_EVICTIONS (FORKING_EVICTIONS_INTERRUPTIBLE | \
48 FORKING_EVICTIONS_SWAPPING | \
49 FORKING_EVICTIONS_DUP_DRMFD | \
50 FORKING_EVICTIONS_MEMORY_PRESSURE)
51
52static void exchange_uint32_t(void *array, unsigned i, unsigned j)
53{
54 uint32_t *i_arr = array;
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +000055
Daniel Vetter2eca38e2015-02-07 12:37:48 +010056 igt_swap(i_arr[i], i_arr[j]);
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +000057}
58
59static int minor_evictions(int fd, struct igt_eviction_test_ops *ops,
Chris Wilson0e207142016-01-25 13:51:00 +000060 uint64_t surface_size,
61 uint64_t nr_surfaces)
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +000062{
63 uint32_t *bo, *sel;
Chris Wilson0e207142016-01-25 13:51:00 +000064 uint64_t n, m, total_surfaces;
65 int pass, fail;
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +000066
Tvrtko Ursulin42bcd052014-02-03 10:59:41 +000067 /* Make sure nr_surfaces is not divisible by seven
68 * to avoid duplicates in the selection loop below.
69 */
70 nr_surfaces /= 7;
71 nr_surfaces *= 7;
72 nr_surfaces += 3;
73
Chris Wilsona1a8aa12014-06-05 13:19:39 +010074 total_surfaces = gem_aperture_size(fd) / surface_size + 1;
Chris Wilson8c475e02014-02-26 12:01:47 +000075 igt_require(nr_surfaces < total_surfaces);
Daniel Vettera535cde2014-11-17 14:43:33 +010076 intel_require_memory(total_surfaces, surface_size, CHECK_RAM);
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +000077
Chris Wilson8c475e02014-02-26 12:01:47 +000078 bo = malloc((nr_surfaces + total_surfaces)*sizeof(*bo));
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +000079 igt_assert(bo);
80
Chris Wilson8c475e02014-02-26 12:01:47 +000081 for (n = 0; n < total_surfaces; n++)
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +000082 bo[n] = ops->create(fd, surface_size);
83
84 sel = bo + n;
85 for (fail = 0, m = 0; fail < 10; fail++) {
Chris Wilsona384e552014-06-03 07:31:49 +010086 int ret;
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +000087 for (pass = 0; pass < 100; pass++) {
88 for (n = 0; n < nr_surfaces; n++, m += 7)
Chris Wilson8c475e02014-02-26 12:01:47 +000089 sel[n] = bo[m%total_surfaces];
Chris Wilsona384e552014-06-03 07:31:49 +010090 ret = ops->copy(fd, sel[0], sel[1], sel, nr_surfaces);
Matt Roper07be8fe2015-03-05 15:01:00 -080091 igt_assert_eq(ret, 0);
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +000092 }
Chris Wilsona384e552014-06-03 07:31:49 +010093 ret = ops->copy(fd, bo[0], bo[0], bo, total_surfaces);
Chris Wilson91d37802016-09-30 17:41:01 +010094 igt_assert_eq(ret, -ENOSPC);
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +000095 }
96
Chris Wilson8c475e02014-02-26 12:01:47 +000097 for (n = 0; n < total_surfaces; n++)
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +000098 ops->close(fd, bo[n]);
99 free(bo);
100
101 return 0;
102}
103
104static int major_evictions(int fd, struct igt_eviction_test_ops *ops,
Chris Wilson0e207142016-01-25 13:51:00 +0000105 uint64_t surface_size, uint64_t nr_surfaces)
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000106{
Chris Wilson0e207142016-01-25 13:51:00 +0000107 uint64_t n, m;
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000108 uint32_t *bo;
Chris Wilson0e207142016-01-25 13:51:00 +0000109 int ret, loop;
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000110
Daniel Vettera535cde2014-11-17 14:43:33 +0100111 intel_require_memory(nr_surfaces, surface_size, CHECK_RAM);
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000112
113 bo = malloc(nr_surfaces*sizeof(*bo));
114 igt_assert(bo);
115
116 for (n = 0; n < nr_surfaces; n++)
117 bo[n] = ops->create(fd, surface_size);
118
119 for (loop = 0, m = 0; loop < 100; loop++, m += 17) {
120 n = m % nr_surfaces;
Chris Wilsona384e552014-06-03 07:31:49 +0100121 ret = ops->copy(fd, bo[n], bo[n], &bo[n], 1);
Matt Roper07be8fe2015-03-05 15:01:00 -0800122 igt_assert_eq(ret, 0);
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000123 }
124
125 for (n = 0; n < nr_surfaces; n++)
126 ops->close(fd, bo[n]);
127 free(bo);
128
129 return 0;
130}
131
Chris Wilson068f9ce2014-12-03 09:05:54 +0000132static void mlocked_evictions(int fd, struct igt_eviction_test_ops *ops,
Chris Wilson0e207142016-01-25 13:51:00 +0000133 uint64_t surface_size,
134 uint64_t surface_count)
Chris Wilson068f9ce2014-12-03 09:05:54 +0000135{
Chris Wilsond592fb92017-03-09 12:27:32 +0000136 unsigned int *can_mlock;
Chris Wilson0e962382016-02-04 17:41:05 +0000137 uint64_t sz, pin;
Chris Wilson068f9ce2014-12-03 09:05:54 +0000138
139 intel_require_memory(surface_count, surface_size, CHECK_RAM);
Chris Wilson068f9ce2014-12-03 09:05:54 +0000140
141 sz = surface_size*surface_count;
142 pin = intel_get_avail_ram_mb();
143 pin *= 1024 * 1024;
144 igt_require(pin > sz);
Chris Wilson0e962382016-02-04 17:41:05 +0000145 pin -= sz;
Chris Wilson068f9ce2014-12-03 09:05:54 +0000146
Chris Wilson0e962382016-02-04 17:41:05 +0000147 igt_debug("Pinning [%'lld, %'lld] MiB\n",
148 (long long)pin/(1024*1024),
149 (long long)(pin + sz)/(1024*1024));
Chris Wilson068f9ce2014-12-03 09:05:54 +0000150
Chris Wilsond592fb92017-03-09 12:27:32 +0000151 can_mlock = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
152 igt_assert(can_mlock != MAP_FAILED);
Chris Wilson068f9ce2014-12-03 09:05:54 +0000153
154 igt_fork(child, 1) {
Chris Wilsond592fb92017-03-09 12:27:32 +0000155 void *locked;
156
157 locked = malloc(pin + sz);
158 if (locked != NULL && !mlock(locked, pin + sz))
159 *can_mlock = 1;
160 }
161 igt_waitchildren();
162 igt_require(*can_mlock);
163 munmap(can_mlock, 4096);
164
165 igt_fork(child, 1) {
166 void *locked;
Chris Wilson068f9ce2014-12-03 09:05:54 +0000167 uint32_t *bo;
Chris Wilson0e207142016-01-25 13:51:00 +0000168 uint64_t n;
169 int ret;
Chris Wilson068f9ce2014-12-03 09:05:54 +0000170
171 bo = malloc(surface_count*sizeof(*bo));
172 igt_assert(bo);
173
174 locked = malloc(pin);
Chris Wilsonaf3e32c2015-03-30 17:01:51 +0100175 if (locked == NULL || mlock(locked, pin))
176 exit(ENOSPC);
Chris Wilson068f9ce2014-12-03 09:05:54 +0000177
178 for (n = 0; n < surface_count; n++)
179 bo[n] = ops->create(fd, surface_size);
180
Chris Wilson068f9ce2014-12-03 09:05:54 +0000181 for (n = 0; n < surface_count - 2; n++) {
182 igt_permute_array(bo, surface_count, exchange_uint32_t);
183 ret = ops->copy(fd, bo[0], bo[1], bo, surface_count-n);
184 if (ret)
Chris Wilsonaf3e32c2015-03-30 17:01:51 +0100185 exit(ret);
Chris Wilson068f9ce2014-12-03 09:05:54 +0000186
187 /* Having used the surfaces (and so pulled out of
188 * our pages into memory), start a memory hog to
189 * force evictions.
190 */
191
192 locked = malloc(surface_size);
Chris Wilsonaf3e32c2015-03-30 17:01:51 +0100193 if (locked == NULL || mlock(locked, surface_size))
Chris Wilson0e962382016-02-04 17:41:05 +0000194 free(locked);
Chris Wilson068f9ce2014-12-03 09:05:54 +0000195 }
196
197 for (n = 0; n < surface_count; n++)
198 ops->close(fd, bo[n]);
Chris Wilson068f9ce2014-12-03 09:05:54 +0000199 }
200
201 igt_waitchildren();
Chris Wilson068f9ce2014-12-03 09:05:54 +0000202}
203
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000204static int swapping_evictions(int fd, struct igt_eviction_test_ops *ops,
Chris Wilson0e207142016-01-25 13:51:00 +0000205 uint64_t surface_size,
206 uint64_t working_surfaces,
207 uint64_t trash_surfaces)
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000208{
209 uint32_t *bo;
Chris Wilson0e207142016-01-25 13:51:00 +0000210 uint64_t i, n;
211 int pass, ret;
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000212
Daniel Vettera535cde2014-11-17 14:43:33 +0100213 intel_require_memory(working_surfaces, surface_size, CHECK_RAM);
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000214
215 if (trash_surfaces < working_surfaces)
216 trash_surfaces = working_surfaces;
217
Daniel Vettera535cde2014-11-17 14:43:33 +0100218 intel_require_memory(trash_surfaces, surface_size, CHECK_RAM | CHECK_SWAP);
Chris Wilson321273f2014-05-28 09:01:56 +0100219
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000220 bo = malloc(trash_surfaces*sizeof(*bo));
221 igt_assert(bo);
222
223 for (n = 0; n < trash_surfaces; n++)
224 bo[n] = ops->create(fd, surface_size);
225
226 for (i = 0; i < trash_surfaces/32; i++) {
227 igt_permute_array(bo, trash_surfaces, exchange_uint32_t);
228
229 for (pass = 0; pass < 100; pass++) {
Chris Wilsona384e552014-06-03 07:31:49 +0100230 ret = ops->copy(fd, bo[0], bo[1], bo, working_surfaces);
Matt Roper07be8fe2015-03-05 15:01:00 -0800231 igt_assert_eq(ret, 0);
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000232 }
233 }
234
235 for (n = 0; n < trash_surfaces; n++)
236 ops->close(fd, bo[n]);
237 free(bo);
238
239 return 0;
240}
241
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000242static int forking_evictions(int fd, struct igt_eviction_test_ops *ops,
Chris Wilson0e207142016-01-25 13:51:00 +0000243 uint64_t surface_size,
244 uint64_t working_surfaces,
245 uint64_t trash_surfaces,
246 unsigned flags)
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000247{
Chris Wilson0e207142016-01-25 13:51:00 +0000248 const int num_threads = sysconf(_SC_NPROCESSORS_ONLN);
249 uint64_t bo_count, n, l;
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000250 uint32_t *bo;
Chris Wilson0e207142016-01-25 13:51:00 +0000251 int pass, ret;
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000252
Daniel Vettera535cde2014-11-17 14:43:33 +0100253 intel_require_memory(working_surfaces, surface_size, CHECK_RAM);
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000254
255 if (flags & FORKING_EVICTIONS_SWAPPING) {
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000256 bo_count = trash_surfaces;
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000257 if (bo_count < working_surfaces)
258 bo_count = working_surfaces;
Chris Wilson321273f2014-05-28 09:01:56 +0100259
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000260 } else
261 bo_count = working_surfaces;
262
Matt Roper07be8fe2015-03-05 15:01:00 -0800263 igt_assert_lte(working_surfaces, bo_count);
Daniel Vettera535cde2014-11-17 14:43:33 +0100264 intel_require_memory(bo_count, surface_size, CHECK_RAM | CHECK_SWAP);
Chris Wilson321273f2014-05-28 09:01:56 +0100265
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000266 bo = malloc(bo_count*sizeof(*bo));
267 igt_assert(bo);
268
269 for (n = 0; n < bo_count; n++)
270 bo[n] = ops->create(fd, surface_size);
271
272 igt_fork(i, min(num_threads * 4, 12)) {
273 int realfd = fd;
274 int num_passes = flags & FORKING_EVICTIONS_SWAPPING ? 10 : 100;
275
276 /* Every fork should have a different permutation! */
277 srand(i * 63);
278
279 if (flags & FORKING_EVICTIONS_INTERRUPTIBLE)
280 igt_fork_signal_helper();
281
282 igt_permute_array(bo, bo_count, exchange_uint32_t);
283
284 if (flags & FORKING_EVICTIONS_DUP_DRMFD) {
Micah Fedkec81d2932015-07-22 21:54:02 +0000285 realfd = drm_open_driver(DRIVER_INTEL);
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000286
287 /* We can overwrite the bo array since we're forked. */
288 for (l = 0; l < bo_count; l++) {
Chris Wilson784b7722014-07-21 09:12:43 +0100289 uint32_t handle = bo[l];
290 uint32_t flink = gem_flink(fd, bo[l]);
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000291
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000292 bo[l] = gem_open(realfd, flink);
Chris Wilson784b7722014-07-21 09:12:43 +0100293 if (ops->flink)
294 ops->flink(handle, bo[l]);
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000295 }
296 }
297
298 for (pass = 0; pass < num_passes; pass++) {
Chris Wilsona384e552014-06-03 07:31:49 +0100299 ret = ops->copy(realfd, bo[0], bo[1], bo, working_surfaces);
Matt Roper07be8fe2015-03-05 15:01:00 -0800300 igt_assert_eq(ret, 0);
Tvrtko Ursuline1dea7e2014-02-03 10:59:40 +0000301
302 for (l = 0; l < working_surfaces &&
303 (flags & FORKING_EVICTIONS_MEMORY_PRESSURE);
304 l++) {
305 ops->clear(realfd, bo[l], surface_size);
306 }
307 }
308
309 if (flags & FORKING_EVICTIONS_INTERRUPTIBLE)
310 igt_stop_signal_helper();
311
312 /* drmfd closing will take care of additional bo refs */
313 if (flags & FORKING_EVICTIONS_DUP_DRMFD)
314 close(realfd);
315 }
316
317 igt_waitchildren();
318
319 for (n = 0; n < bo_count; n++)
320 ops->close(fd, bo[n]);
321 free(bo);
322
323 return 0;
324}