2 * Copyright © 2007, 2011, 2013, 2014 Intel Corporation
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:
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
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
24 * Eric Anholt <eric@anholt.net>
25 * Daniel Vetter <daniel.vetter@ffwll.ch>
26 * Tvrtko Ursulin <tvrtko.ursulin@intel.com>
35 struct igt_eviction_test_ops
37 uint32_t (*create)(int fd, int size);
38 void (*flink)(uint32_t old_handle, uint32_t new_handle);
39 void (*close)(int fd, uint32_t bo);
40 int (*copy)(int fd, uint32_t dst, uint32_t src,
41 uint32_t *all_bo, int nr_bos);
42 void (*clear)(int fd, uint32_t bo, int size);
45 #define FORKING_EVICTIONS_INTERRUPTIBLE (1 << 0)
46 #define FORKING_EVICTIONS_SWAPPING (1 << 1)
47 #define FORKING_EVICTIONS_DUP_DRMFD (1 << 2)
48 #define FORKING_EVICTIONS_MEMORY_PRESSURE (1 << 3)
49 #define ALL_FORKING_EVICTIONS (FORKING_EVICTIONS_INTERRUPTIBLE | \
50 FORKING_EVICTIONS_SWAPPING | \
51 FORKING_EVICTIONS_DUP_DRMFD | \
52 FORKING_EVICTIONS_MEMORY_PRESSURE)
54 static void exchange_uint32_t(void *array, unsigned i, unsigned j)
56 uint32_t *i_arr = array;
64 static int minor_evictions(int fd, struct igt_eviction_test_ops *ops,
65 int surface_size, int nr_surfaces)
71 /* Make sure nr_surfaces is not divisible by seven
72 * to avoid duplicates in the selection loop below.
78 total_surfaces = gem_aperture_size(fd) / surface_size + 1;
79 igt_require(nr_surfaces < total_surfaces);
80 igt_require(intel_check_memory(total_surfaces, surface_size, CHECK_RAM));
82 bo = malloc((nr_surfaces + total_surfaces)*sizeof(*bo));
85 for (n = 0; n < total_surfaces; n++)
86 bo[n] = ops->create(fd, surface_size);
89 for (fail = 0, m = 0; fail < 10; fail++) {
91 for (pass = 0; pass < 100; pass++) {
92 for (n = 0; n < nr_surfaces; n++, m += 7)
93 sel[n] = bo[m%total_surfaces];
94 ret = ops->copy(fd, sel[0], sel[1], sel, nr_surfaces);
97 ret = ops->copy(fd, bo[0], bo[0], bo, total_surfaces);
98 igt_assert(ret == ENOSPC);
101 for (n = 0; n < total_surfaces; n++)
102 ops->close(fd, bo[n]);
108 static int major_evictions(int fd, struct igt_eviction_test_ops *ops,
109 int surface_size, int nr_surfaces)
115 igt_require(intel_check_memory(nr_surfaces, surface_size, CHECK_RAM));
117 bo = malloc(nr_surfaces*sizeof(*bo));
120 for (n = 0; n < nr_surfaces; n++)
121 bo[n] = ops->create(fd, surface_size);
123 for (loop = 0, m = 0; loop < 100; loop++, m += 17) {
125 ret = ops->copy(fd, bo[n], bo[n], &bo[n], 1);
126 igt_assert(ret == 0);
129 for (n = 0; n < nr_surfaces; n++)
130 ops->close(fd, bo[n]);
136 static int swapping_evictions(int fd, struct igt_eviction_test_ops *ops,
138 int working_surfaces,
144 igt_require(intel_check_memory(working_surfaces, surface_size, CHECK_RAM));
146 if (trash_surfaces < working_surfaces)
147 trash_surfaces = working_surfaces;
149 igt_require(intel_check_memory(trash_surfaces, surface_size, CHECK_RAM | CHECK_SWAP));
151 bo = malloc(trash_surfaces*sizeof(*bo));
154 for (n = 0; n < trash_surfaces; n++)
155 bo[n] = ops->create(fd, surface_size);
157 for (i = 0; i < trash_surfaces/32; i++) {
158 igt_permute_array(bo, trash_surfaces, exchange_uint32_t);
160 for (pass = 0; pass < 100; pass++) {
161 ret = ops->copy(fd, bo[0], bo[1], bo, working_surfaces);
162 igt_assert(ret == 0);
166 for (n = 0; n < trash_surfaces; n++)
167 ops->close(fd, bo[n]);
173 #define min(a, b) ((a) < (b) ? (a) : (b))
175 static int forking_evictions(int fd, struct igt_eviction_test_ops *ops,
176 int surface_size, int working_surfaces,
177 int trash_surfaces, unsigned flags)
181 int num_threads = sysconf(_SC_NPROCESSORS_ONLN);
184 igt_require(intel_check_memory(working_surfaces, surface_size, CHECK_RAM));
186 if (flags & FORKING_EVICTIONS_SWAPPING) {
187 bo_count = trash_surfaces;
188 if (bo_count < working_surfaces)
189 bo_count = working_surfaces;
192 bo_count = working_surfaces;
194 igt_assert(working_surfaces <= bo_count);
195 igt_require(intel_check_memory(bo_count, surface_size, CHECK_RAM | CHECK_SWAP));
197 bo = malloc(bo_count*sizeof(*bo));
200 for (n = 0; n < bo_count; n++)
201 bo[n] = ops->create(fd, surface_size);
203 igt_fork(i, min(num_threads * 4, 12)) {
205 int num_passes = flags & FORKING_EVICTIONS_SWAPPING ? 10 : 100;
207 /* Every fork should have a different permutation! */
210 if (flags & FORKING_EVICTIONS_INTERRUPTIBLE)
211 igt_fork_signal_helper();
213 igt_permute_array(bo, bo_count, exchange_uint32_t);
215 if (flags & FORKING_EVICTIONS_DUP_DRMFD) {
216 realfd = drm_open_any();
218 /* We can overwrite the bo array since we're forked. */
219 for (l = 0; l < bo_count; l++) {
220 uint32_t handle = bo[l];
221 uint32_t flink = gem_flink(fd, bo[l]);
223 bo[l] = gem_open(realfd, flink);
225 ops->flink(handle, bo[l]);
229 for (pass = 0; pass < num_passes; pass++) {
230 ret = ops->copy(realfd, bo[0], bo[1], bo, working_surfaces);
231 igt_assert(ret == 0);
233 for (l = 0; l < working_surfaces &&
234 (flags & FORKING_EVICTIONS_MEMORY_PRESSURE);
236 ops->clear(realfd, bo[l], surface_size);
240 if (flags & FORKING_EVICTIONS_INTERRUPTIBLE)
241 igt_stop_signal_helper();
243 /* drmfd closing will take care of additional bo refs */
244 if (flags & FORKING_EVICTIONS_DUP_DRMFD)
250 for (n = 0; n < bo_count; n++)
251 ops->close(fd, bo[n]);