tests: remove unused getopt header includes
[platform/upstream/intel-gpu-tools.git] / tests / eviction_common.c
1 /*
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
30 #include <stdlib.h>
31
32 #include "drmtest.h"
33 #include "igt_aux.h"
34
35 struct igt_eviction_test_ops
36 {
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);
43 };
44
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)
53
54 static void exchange_uint32_t(void *array, unsigned i, unsigned j)
55 {
56         uint32_t *i_arr = array;
57         uint32_t i_tmp;
58
59         i_tmp = i_arr[i];
60         i_arr[i] = i_arr[j];
61         i_arr[j] = i_tmp;
62 }
63
64 static int minor_evictions(int fd, struct igt_eviction_test_ops *ops,
65                            int surface_size, int nr_surfaces)
66 {
67         uint32_t *bo, *sel;
68         int n, m, pass, fail;
69         int total_surfaces;
70
71         /* Make sure nr_surfaces is not divisible by seven
72          * to avoid duplicates in the selection loop below.
73          */
74         nr_surfaces /= 7;
75         nr_surfaces *= 7;
76         nr_surfaces += 3;
77
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));
81
82         bo = malloc((nr_surfaces + total_surfaces)*sizeof(*bo));
83         igt_assert(bo);
84
85         for (n = 0; n < total_surfaces; n++)
86                 bo[n] = ops->create(fd, surface_size);
87
88         sel = bo + n;
89         for (fail = 0, m = 0; fail < 10; fail++) {
90                 int ret;
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);
95                         igt_assert(ret == 0);
96                 }
97                 ret = ops->copy(fd, bo[0], bo[0], bo, total_surfaces);
98                 igt_assert(ret == ENOSPC);
99         }
100
101         for (n = 0; n < total_surfaces; n++)
102                 ops->close(fd, bo[n]);
103         free(bo);
104
105         return 0;
106 }
107
108 static int major_evictions(int fd, struct igt_eviction_test_ops *ops,
109                            int surface_size, int nr_surfaces)
110 {
111         int n, m, loop;
112         uint32_t *bo;
113         int ret;
114
115         igt_require(intel_check_memory(nr_surfaces, surface_size, CHECK_RAM));
116
117         bo = malloc(nr_surfaces*sizeof(*bo));
118         igt_assert(bo);
119
120         for (n = 0; n < nr_surfaces; n++)
121                 bo[n] = ops->create(fd, surface_size);
122
123         for (loop = 0, m = 0; loop < 100; loop++, m += 17) {
124                 n = m % nr_surfaces;
125                 ret = ops->copy(fd, bo[n], bo[n], &bo[n], 1);
126                 igt_assert(ret == 0);
127         }
128
129         for (n = 0; n < nr_surfaces; n++)
130                 ops->close(fd, bo[n]);
131         free(bo);
132
133         return 0;
134 }
135
136 static int swapping_evictions(int fd, struct igt_eviction_test_ops *ops,
137                               int surface_size,
138                               int working_surfaces,
139                               int trash_surfaces)
140 {
141         uint32_t *bo;
142         int i, n, pass, ret;
143
144         igt_require(intel_check_memory(working_surfaces, surface_size, CHECK_RAM));
145
146         if (trash_surfaces < working_surfaces)
147                 trash_surfaces = working_surfaces;
148
149         igt_require(intel_check_memory(trash_surfaces, surface_size, CHECK_RAM | CHECK_SWAP));
150
151         bo = malloc(trash_surfaces*sizeof(*bo));
152         igt_assert(bo);
153
154         for (n = 0; n < trash_surfaces; n++)
155                 bo[n] = ops->create(fd, surface_size);
156
157         for (i = 0; i < trash_surfaces/32; i++) {
158                 igt_permute_array(bo, trash_surfaces, exchange_uint32_t);
159
160                 for (pass = 0; pass < 100; pass++) {
161                         ret = ops->copy(fd, bo[0], bo[1], bo, working_surfaces);
162                         igt_assert(ret == 0);
163                 }
164         }
165
166         for (n = 0; n < trash_surfaces; n++)
167                 ops->close(fd, bo[n]);
168         free(bo);
169
170         return 0;
171 }
172
173 #define min(a, b) ((a) < (b) ? (a) : (b))
174
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)
178 {
179         uint32_t *bo;
180         int n, pass, l, ret;
181         int num_threads = sysconf(_SC_NPROCESSORS_ONLN);
182         int bo_count;
183
184         igt_require(intel_check_memory(working_surfaces, surface_size, CHECK_RAM));
185
186         if (flags & FORKING_EVICTIONS_SWAPPING) {
187                 bo_count = trash_surfaces;
188                 if (bo_count < working_surfaces)
189                         bo_count = working_surfaces;
190
191         } else
192                 bo_count = working_surfaces;
193
194         igt_assert(working_surfaces <= bo_count);
195         igt_require(intel_check_memory(bo_count, surface_size, CHECK_RAM | CHECK_SWAP));
196
197         bo = malloc(bo_count*sizeof(*bo));
198         igt_assert(bo);
199
200         for (n = 0; n < bo_count; n++)
201                 bo[n] = ops->create(fd, surface_size);
202
203         igt_fork(i, min(num_threads * 4, 12)) {
204                 int realfd = fd;
205                 int num_passes = flags & FORKING_EVICTIONS_SWAPPING ? 10 : 100;
206
207                 /* Every fork should have a different permutation! */
208                 srand(i * 63);
209
210                 if (flags & FORKING_EVICTIONS_INTERRUPTIBLE)
211                         igt_fork_signal_helper();
212
213                 igt_permute_array(bo, bo_count, exchange_uint32_t);
214
215                 if (flags & FORKING_EVICTIONS_DUP_DRMFD) {
216                         realfd = drm_open_any();
217
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]);
222
223                                 bo[l] = gem_open(realfd, flink);
224                                 if (ops->flink)
225                                         ops->flink(handle, bo[l]);
226                         }
227                 }
228
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);
232
233                         for (l = 0; l < working_surfaces &&
234                           (flags & FORKING_EVICTIONS_MEMORY_PRESSURE);
235                             l++) {
236                                 ops->clear(realfd, bo[l], surface_size);
237                         }
238                 }
239
240                 if (flags & FORKING_EVICTIONS_INTERRUPTIBLE)
241                         igt_stop_signal_helper();
242
243                 /* drmfd closing will take care of additional bo refs */
244                 if (flags & FORKING_EVICTIONS_DUP_DRMFD)
245                         close(realfd);
246         }
247
248         igt_waitchildren();
249
250         for (n = 0; n < bo_count; n++)
251                 ops->close(fd, bo[n]);
252         free(bo);
253
254         return 0;
255 }