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 (*close)(int fd, uint32_t bo);
39 int (*copy)(int fd, uint32_t dst, uint32_t src,
40 uint32_t *all_bo, int nr_bos);
41 void (*clear)(int fd, uint32_t bo, int size);
44 #define FORKING_EVICTIONS_INTERRUPTIBLE (1 << 0)
45 #define FORKING_EVICTIONS_SWAPPING (1 << 1)
46 #define FORKING_EVICTIONS_DUP_DRMFD (1 << 2)
47 #define FORKING_EVICTIONS_MEMORY_PRESSURE (1 << 3)
48 #define ALL_FORKING_EVICTIONS (FORKING_EVICTIONS_INTERRUPTIBLE | \
49 FORKING_EVICTIONS_SWAPPING | \
50 FORKING_EVICTIONS_DUP_DRMFD | \
51 FORKING_EVICTIONS_MEMORY_PRESSURE)
53 static void exchange_uint32_t(void *array, unsigned i, unsigned j)
55 uint32_t *i_arr = array;
63 static int minor_evictions(int fd, struct igt_eviction_test_ops *ops,
64 int surface_size, int nr_surfaces)
70 /* Make sure nr_surfaces is not divisible by seven
71 * to avoid duplicates in the selection loop below.
77 total_surfaces = gem_aperture_size(fd) / surface_size + 1;
78 igt_require(nr_surfaces < total_surfaces);
79 igt_require(intel_check_memory(total_surfaces, surface_size, CHECK_RAM));
81 bo = malloc((nr_surfaces + total_surfaces)*sizeof(*bo));
84 for (n = 0; n < total_surfaces; n++)
85 bo[n] = ops->create(fd, surface_size);
88 for (fail = 0, m = 0; fail < 10; fail++) {
90 for (pass = 0; pass < 100; pass++) {
91 for (n = 0; n < nr_surfaces; n++, m += 7)
92 sel[n] = bo[m%total_surfaces];
93 ret = ops->copy(fd, sel[0], sel[1], sel, nr_surfaces);
96 ret = ops->copy(fd, bo[0], bo[0], bo, total_surfaces);
97 igt_assert(ret == ENOSPC);
100 for (n = 0; n < total_surfaces; n++)
101 ops->close(fd, bo[n]);
107 static int major_evictions(int fd, struct igt_eviction_test_ops *ops,
108 int surface_size, int nr_surfaces)
114 igt_require(intel_check_memory(nr_surfaces, surface_size, CHECK_RAM));
116 bo = malloc(nr_surfaces*sizeof(*bo));
119 for (n = 0; n < nr_surfaces; n++)
120 bo[n] = ops->create(fd, surface_size);
122 for (loop = 0, m = 0; loop < 100; loop++, m += 17) {
124 ret = ops->copy(fd, bo[n], bo[n], &bo[n], 1);
125 igt_assert(ret == 0);
128 for (n = 0; n < nr_surfaces; n++)
129 ops->close(fd, bo[n]);
135 static int swapping_evictions(int fd, struct igt_eviction_test_ops *ops,
137 int working_surfaces,
143 igt_require(intel_check_memory(working_surfaces, surface_size, CHECK_RAM));
145 if (trash_surfaces < working_surfaces)
146 trash_surfaces = working_surfaces;
148 igt_require(intel_check_memory(trash_surfaces, surface_size, CHECK_RAM | CHECK_SWAP));
150 bo = malloc(trash_surfaces*sizeof(*bo));
153 for (n = 0; n < trash_surfaces; n++)
154 bo[n] = ops->create(fd, surface_size);
156 for (i = 0; i < trash_surfaces/32; i++) {
157 igt_permute_array(bo, trash_surfaces, exchange_uint32_t);
159 for (pass = 0; pass < 100; pass++) {
160 ret = ops->copy(fd, bo[0], bo[1], bo, working_surfaces);
161 igt_assert(ret == 0);
165 for (n = 0; n < trash_surfaces; n++)
166 ops->close(fd, bo[n]);
172 #define min(a, b) ((a) < (b) ? (a) : (b))
174 static int forking_evictions(int fd, struct igt_eviction_test_ops *ops,
175 int surface_size, int working_surfaces,
176 int trash_surfaces, unsigned flags)
180 int num_threads = sysconf(_SC_NPROCESSORS_ONLN);
183 igt_require(intel_check_memory(working_surfaces, surface_size, CHECK_RAM));
185 if (flags & FORKING_EVICTIONS_SWAPPING) {
186 bo_count = trash_surfaces;
187 if (bo_count < working_surfaces)
188 bo_count = working_surfaces;
191 bo_count = working_surfaces;
193 igt_require(intel_check_memory(bo_count, surface_size, CHECK_RAM | CHECK_SWAP));
195 bo = malloc(bo_count*sizeof(*bo));
198 for (n = 0; n < bo_count; n++)
199 bo[n] = ops->create(fd, surface_size);
201 igt_fork(i, min(num_threads * 4, 12)) {
203 int num_passes = flags & FORKING_EVICTIONS_SWAPPING ? 10 : 100;
205 /* Every fork should have a different permutation! */
208 if (flags & FORKING_EVICTIONS_INTERRUPTIBLE)
209 igt_fork_signal_helper();
211 igt_permute_array(bo, bo_count, exchange_uint32_t);
213 if (flags & FORKING_EVICTIONS_DUP_DRMFD) {
214 realfd = drm_open_any();
216 /* We can overwrite the bo array since we're forked. */
217 for (l = 0; l < bo_count; l++) {
220 flink = gem_flink(fd, bo[l]);
221 bo[l] = gem_open(realfd, flink);
225 for (pass = 0; pass < num_passes; pass++) {
226 ret = ops->copy(realfd, bo[0], bo[1], bo, working_surfaces);
227 igt_assert(ret == 0);
229 for (l = 0; l < working_surfaces &&
230 (flags & FORKING_EVICTIONS_MEMORY_PRESSURE);
232 ops->clear(realfd, bo[l], surface_size);
236 if (flags & FORKING_EVICTIONS_INTERRUPTIBLE)
237 igt_stop_signal_helper();
239 /* drmfd closing will take care of additional bo refs */
240 if (flags & FORKING_EVICTIONS_DUP_DRMFD)
246 for (n = 0; n < bo_count; n++)
247 ops->close(fd, bo[n]);