xref: /aosp_15_r20/external/igt-gpu-tools/tests/i915/gem_shrink.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1*d83cc019SAndroid Build Coastguard Worker /*
2*d83cc019SAndroid Build Coastguard Worker  * Copyright © 2016 Intel Corporation
3*d83cc019SAndroid Build Coastguard Worker  *
4*d83cc019SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
5*d83cc019SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
6*d83cc019SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
7*d83cc019SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*d83cc019SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
9*d83cc019SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
10*d83cc019SAndroid Build Coastguard Worker  *
11*d83cc019SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice (including the next
12*d83cc019SAndroid Build Coastguard Worker  * paragraph) shall be included in all copies or substantial portions of the
13*d83cc019SAndroid Build Coastguard Worker  * Software.
14*d83cc019SAndroid Build Coastguard Worker  *
15*d83cc019SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*d83cc019SAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*d83cc019SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18*d83cc019SAndroid Build Coastguard Worker  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*d83cc019SAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*d83cc019SAndroid Build Coastguard Worker  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21*d83cc019SAndroid Build Coastguard Worker  * IN THE SOFTWARE.
22*d83cc019SAndroid Build Coastguard Worker  *
23*d83cc019SAndroid Build Coastguard Worker  */
24*d83cc019SAndroid Build Coastguard Worker 
25*d83cc019SAndroid Build Coastguard Worker /** @file gem_shrink.c
26*d83cc019SAndroid Build Coastguard Worker  *
27*d83cc019SAndroid Build Coastguard Worker  * Exercise the shrinker by overallocating GEM objects
28*d83cc019SAndroid Build Coastguard Worker  */
29*d83cc019SAndroid Build Coastguard Worker 
30*d83cc019SAndroid Build Coastguard Worker #include "igt.h"
31*d83cc019SAndroid Build Coastguard Worker #include "igt_gt.h"
32*d83cc019SAndroid Build Coastguard Worker #include "igt_debugfs.h"
33*d83cc019SAndroid Build Coastguard Worker #include "igt_sysfs.h"
34*d83cc019SAndroid Build Coastguard Worker 
35*d83cc019SAndroid Build Coastguard Worker #ifndef MADV_FREE
36*d83cc019SAndroid Build Coastguard Worker #define MADV_FREE 8
37*d83cc019SAndroid Build Coastguard Worker #endif
38*d83cc019SAndroid Build Coastguard Worker 
39*d83cc019SAndroid Build Coastguard Worker static unsigned int engines[16], nengine;
40*d83cc019SAndroid Build Coastguard Worker 
get_pages(int fd,uint64_t alloc)41*d83cc019SAndroid Build Coastguard Worker static void get_pages(int fd, uint64_t alloc)
42*d83cc019SAndroid Build Coastguard Worker {
43*d83cc019SAndroid Build Coastguard Worker 	uint32_t handle = gem_create(fd, alloc);
44*d83cc019SAndroid Build Coastguard Worker 	gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, 0);
45*d83cc019SAndroid Build Coastguard Worker 	gem_madvise(fd, handle, I915_MADV_DONTNEED);
46*d83cc019SAndroid Build Coastguard Worker }
47*d83cc019SAndroid Build Coastguard Worker 
get_pages_dirty(int fd,uint64_t alloc)48*d83cc019SAndroid Build Coastguard Worker static void get_pages_dirty(int fd, uint64_t alloc)
49*d83cc019SAndroid Build Coastguard Worker {
50*d83cc019SAndroid Build Coastguard Worker 	uint32_t handle = gem_create(fd, alloc);
51*d83cc019SAndroid Build Coastguard Worker 	gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
52*d83cc019SAndroid Build Coastguard Worker 	gem_madvise(fd, handle, I915_MADV_DONTNEED);
53*d83cc019SAndroid Build Coastguard Worker }
54*d83cc019SAndroid Build Coastguard Worker 
pwrite_(int fd,uint64_t alloc)55*d83cc019SAndroid Build Coastguard Worker static void pwrite_(int fd, uint64_t alloc)
56*d83cc019SAndroid Build Coastguard Worker {
57*d83cc019SAndroid Build Coastguard Worker 	uint32_t tmp;
58*d83cc019SAndroid Build Coastguard Worker 	uint32_t handle = gem_create(fd, alloc);
59*d83cc019SAndroid Build Coastguard Worker 	for (int page = 0; page < alloc>>12; page++)
60*d83cc019SAndroid Build Coastguard Worker 		gem_write(fd, handle, (page + page % 4095) & ~3, &tmp, 4);
61*d83cc019SAndroid Build Coastguard Worker 	gem_madvise(fd, handle, I915_MADV_DONTNEED);
62*d83cc019SAndroid Build Coastguard Worker }
63*d83cc019SAndroid Build Coastguard Worker 
pread_(int fd,uint64_t alloc)64*d83cc019SAndroid Build Coastguard Worker static void pread_(int fd, uint64_t alloc)
65*d83cc019SAndroid Build Coastguard Worker {
66*d83cc019SAndroid Build Coastguard Worker 	uint32_t tmp;
67*d83cc019SAndroid Build Coastguard Worker 	uint32_t handle = gem_create(fd, alloc);
68*d83cc019SAndroid Build Coastguard Worker 	for (int page = 0; page < alloc>>12; page++)
69*d83cc019SAndroid Build Coastguard Worker 		gem_read(fd, handle, (page + page % 4095) & ~3, &tmp, 4);
70*d83cc019SAndroid Build Coastguard Worker 	gem_madvise(fd, handle, I915_MADV_DONTNEED);
71*d83cc019SAndroid Build Coastguard Worker }
72*d83cc019SAndroid Build Coastguard Worker 
mmap_gtt(int fd,uint64_t alloc)73*d83cc019SAndroid Build Coastguard Worker static void mmap_gtt(int fd, uint64_t alloc)
74*d83cc019SAndroid Build Coastguard Worker {
75*d83cc019SAndroid Build Coastguard Worker 	uint32_t handle = gem_create(fd, alloc);
76*d83cc019SAndroid Build Coastguard Worker 	uint32_t *ptr = gem_mmap__gtt(fd, handle, alloc, PROT_WRITE);
77*d83cc019SAndroid Build Coastguard Worker 	for (int page = 0; page < alloc>>12; page++)
78*d83cc019SAndroid Build Coastguard Worker 		ptr[page<<10] = 0;
79*d83cc019SAndroid Build Coastguard Worker 	munmap(ptr, alloc);
80*d83cc019SAndroid Build Coastguard Worker 	gem_madvise(fd, handle, I915_MADV_DONTNEED);
81*d83cc019SAndroid Build Coastguard Worker }
82*d83cc019SAndroid Build Coastguard Worker 
mmap_cpu(int fd,uint64_t alloc)83*d83cc019SAndroid Build Coastguard Worker static void mmap_cpu(int fd, uint64_t alloc)
84*d83cc019SAndroid Build Coastguard Worker {
85*d83cc019SAndroid Build Coastguard Worker 	uint32_t handle = gem_create(fd, alloc);
86*d83cc019SAndroid Build Coastguard Worker 	uint32_t *ptr = gem_mmap__cpu(fd, handle, 0, alloc, PROT_WRITE);
87*d83cc019SAndroid Build Coastguard Worker 	for (int page = 0; page < alloc>>12; page++)
88*d83cc019SAndroid Build Coastguard Worker 		ptr[page<<10] = 0;
89*d83cc019SAndroid Build Coastguard Worker 	munmap(ptr, alloc);
90*d83cc019SAndroid Build Coastguard Worker 	gem_madvise(fd, handle, I915_MADV_DONTNEED);
91*d83cc019SAndroid Build Coastguard Worker }
92*d83cc019SAndroid Build Coastguard Worker 
execbuf1(int fd,uint64_t alloc)93*d83cc019SAndroid Build Coastguard Worker static void execbuf1(int fd, uint64_t alloc)
94*d83cc019SAndroid Build Coastguard Worker {
95*d83cc019SAndroid Build Coastguard Worker 	const uint32_t bbe = MI_BATCH_BUFFER_END;
96*d83cc019SAndroid Build Coastguard Worker 	struct drm_i915_gem_exec_object2 obj;
97*d83cc019SAndroid Build Coastguard Worker 	struct drm_i915_gem_execbuffer2 execbuf;
98*d83cc019SAndroid Build Coastguard Worker 
99*d83cc019SAndroid Build Coastguard Worker 	memset(&obj, 0, sizeof(obj));
100*d83cc019SAndroid Build Coastguard Worker 	memset(&execbuf, 0, sizeof(execbuf));
101*d83cc019SAndroid Build Coastguard Worker 	execbuf.buffers_ptr = to_user_pointer(&obj);
102*d83cc019SAndroid Build Coastguard Worker 	execbuf.buffer_count = 1;
103*d83cc019SAndroid Build Coastguard Worker 
104*d83cc019SAndroid Build Coastguard Worker 	obj.handle = gem_create(fd, alloc);
105*d83cc019SAndroid Build Coastguard Worker 	gem_write(fd, obj.handle, 0, &bbe, sizeof(bbe));
106*d83cc019SAndroid Build Coastguard Worker 	gem_execbuf(fd, &execbuf);
107*d83cc019SAndroid Build Coastguard Worker 	gem_madvise(fd, obj.handle, I915_MADV_DONTNEED);
108*d83cc019SAndroid Build Coastguard Worker }
109*d83cc019SAndroid Build Coastguard Worker 
110*d83cc019SAndroid Build Coastguard Worker /* Since we want to trigger oom (SIGKILL), we don't want small allocations
111*d83cc019SAndroid Build Coastguard Worker  * to fail and generate a false error (SIGSEGV)! So we redirect allocations
112*d83cc019SAndroid Build Coastguard Worker  * though GEM objects, which should be much more likely to trigger oom. There
113*d83cc019SAndroid Build Coastguard Worker  * are still small allocations within the kernel, so still a small chance of
114*d83cc019SAndroid Build Coastguard Worker  * ENOMEM instead of a full oom.
115*d83cc019SAndroid Build Coastguard Worker  */
__gem_calloc(int fd,size_t count,size_t size,uint64_t * out_size)116*d83cc019SAndroid Build Coastguard Worker static void *__gem_calloc(int fd, size_t count, size_t size, uint64_t *out_size)
117*d83cc019SAndroid Build Coastguard Worker {
118*d83cc019SAndroid Build Coastguard Worker 	uint32_t handle;
119*d83cc019SAndroid Build Coastguard Worker 	uint64_t total;
120*d83cc019SAndroid Build Coastguard Worker 	void *ptr;
121*d83cc019SAndroid Build Coastguard Worker 
122*d83cc019SAndroid Build Coastguard Worker 	total = count * size;
123*d83cc019SAndroid Build Coastguard Worker 	total = (total + 4095) & -4096;
124*d83cc019SAndroid Build Coastguard Worker 
125*d83cc019SAndroid Build Coastguard Worker 	handle = gem_create(fd, total);
126*d83cc019SAndroid Build Coastguard Worker 	ptr = gem_mmap__cpu(fd, handle, 0, total, PROT_WRITE);
127*d83cc019SAndroid Build Coastguard Worker 	gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
128*d83cc019SAndroid Build Coastguard Worker 	gem_close(fd, handle);
129*d83cc019SAndroid Build Coastguard Worker 
130*d83cc019SAndroid Build Coastguard Worker 	*out_size = total;
131*d83cc019SAndroid Build Coastguard Worker 	return ptr;
132*d83cc019SAndroid Build Coastguard Worker }
133*d83cc019SAndroid Build Coastguard Worker 
execbufN(int fd,uint64_t alloc)134*d83cc019SAndroid Build Coastguard Worker static void execbufN(int fd, uint64_t alloc)
135*d83cc019SAndroid Build Coastguard Worker {
136*d83cc019SAndroid Build Coastguard Worker 	const uint32_t bbe = MI_BATCH_BUFFER_END;
137*d83cc019SAndroid Build Coastguard Worker 	struct drm_i915_gem_exec_object2 *obj;
138*d83cc019SAndroid Build Coastguard Worker 	struct drm_i915_gem_execbuffer2 execbuf;
139*d83cc019SAndroid Build Coastguard Worker 	int count = alloc >> 20;
140*d83cc019SAndroid Build Coastguard Worker 	uint64_t obj_size;
141*d83cc019SAndroid Build Coastguard Worker 
142*d83cc019SAndroid Build Coastguard Worker 	obj = __gem_calloc(fd, alloc + 1, sizeof(*obj), &obj_size);
143*d83cc019SAndroid Build Coastguard Worker 	memset(&execbuf, 0, sizeof(execbuf));
144*d83cc019SAndroid Build Coastguard Worker 
145*d83cc019SAndroid Build Coastguard Worker 	obj[count].handle = gem_create(fd, 4096);
146*d83cc019SAndroid Build Coastguard Worker 	gem_write(fd, obj[count].handle, 0, &bbe, sizeof(bbe));
147*d83cc019SAndroid Build Coastguard Worker 
148*d83cc019SAndroid Build Coastguard Worker 	for (int i = 1; i <= count; i++) {
149*d83cc019SAndroid Build Coastguard Worker 		int j = count - i;
150*d83cc019SAndroid Build Coastguard Worker 
151*d83cc019SAndroid Build Coastguard Worker 		obj[j].handle = gem_create(fd, 1 << 20);
152*d83cc019SAndroid Build Coastguard Worker 		execbuf.buffers_ptr = to_user_pointer(&obj[j]);
153*d83cc019SAndroid Build Coastguard Worker 		execbuf.buffer_count = i + 1;
154*d83cc019SAndroid Build Coastguard Worker 		gem_execbuf(fd, &execbuf);
155*d83cc019SAndroid Build Coastguard Worker 	}
156*d83cc019SAndroid Build Coastguard Worker 
157*d83cc019SAndroid Build Coastguard Worker 	for (int i = 0; i <= count; i++)
158*d83cc019SAndroid Build Coastguard Worker 		gem_madvise(fd, obj[i].handle, I915_MADV_DONTNEED);
159*d83cc019SAndroid Build Coastguard Worker 	munmap(obj, obj_size);
160*d83cc019SAndroid Build Coastguard Worker }
161*d83cc019SAndroid Build Coastguard Worker 
execbufX(int fd,uint64_t alloc)162*d83cc019SAndroid Build Coastguard Worker static void execbufX(int fd, uint64_t alloc)
163*d83cc019SAndroid Build Coastguard Worker {
164*d83cc019SAndroid Build Coastguard Worker 	const uint32_t bbe = MI_BATCH_BUFFER_END;
165*d83cc019SAndroid Build Coastguard Worker 	struct drm_i915_gem_exec_object2 *obj;
166*d83cc019SAndroid Build Coastguard Worker 	struct drm_i915_gem_execbuffer2 execbuf;
167*d83cc019SAndroid Build Coastguard Worker 	int count = alloc >> 20;
168*d83cc019SAndroid Build Coastguard Worker 	uint64_t obj_size;
169*d83cc019SAndroid Build Coastguard Worker 
170*d83cc019SAndroid Build Coastguard Worker 	obj = __gem_calloc(fd, alloc + 1, sizeof(*obj), &obj_size);
171*d83cc019SAndroid Build Coastguard Worker 	memset(&execbuf, 0, sizeof(execbuf));
172*d83cc019SAndroid Build Coastguard Worker 
173*d83cc019SAndroid Build Coastguard Worker 	obj[count].handle = gem_create(fd, 4096);
174*d83cc019SAndroid Build Coastguard Worker 	gem_write(fd, obj[count].handle, 0, &bbe, sizeof(bbe));
175*d83cc019SAndroid Build Coastguard Worker 
176*d83cc019SAndroid Build Coastguard Worker 	for (int i = 1; i <= count; i++) {
177*d83cc019SAndroid Build Coastguard Worker 		int j = count - i;
178*d83cc019SAndroid Build Coastguard Worker 
179*d83cc019SAndroid Build Coastguard Worker 		obj[j+1].flags = 0;
180*d83cc019SAndroid Build Coastguard Worker 
181*d83cc019SAndroid Build Coastguard Worker 		obj[j].handle = gem_create(fd, 1 << 20);
182*d83cc019SAndroid Build Coastguard Worker 		obj[j].flags = EXEC_OBJECT_WRITE;
183*d83cc019SAndroid Build Coastguard Worker 
184*d83cc019SAndroid Build Coastguard Worker 		execbuf.buffers_ptr = to_user_pointer(&obj[j]);
185*d83cc019SAndroid Build Coastguard Worker 		execbuf.buffer_count = i + 1;
186*d83cc019SAndroid Build Coastguard Worker 		execbuf.flags = engines[j % nengine];
187*d83cc019SAndroid Build Coastguard Worker 		gem_execbuf(fd, &execbuf);
188*d83cc019SAndroid Build Coastguard Worker 	}
189*d83cc019SAndroid Build Coastguard Worker 
190*d83cc019SAndroid Build Coastguard Worker 	for (int i = 0; i <= count; i++)
191*d83cc019SAndroid Build Coastguard Worker 		gem_madvise(fd, obj[i].handle, I915_MADV_DONTNEED);
192*d83cc019SAndroid Build Coastguard Worker 	munmap(obj, obj_size);
193*d83cc019SAndroid Build Coastguard Worker }
194*d83cc019SAndroid Build Coastguard Worker 
hang(int fd,uint64_t alloc)195*d83cc019SAndroid Build Coastguard Worker static void hang(int fd, uint64_t alloc)
196*d83cc019SAndroid Build Coastguard Worker {
197*d83cc019SAndroid Build Coastguard Worker 	const uint32_t bbe = MI_BATCH_BUFFER_END;
198*d83cc019SAndroid Build Coastguard Worker 	struct drm_i915_gem_exec_object2 *obj;
199*d83cc019SAndroid Build Coastguard Worker 	struct drm_i915_gem_execbuffer2 execbuf;
200*d83cc019SAndroid Build Coastguard Worker 	int count = alloc >> 20;
201*d83cc019SAndroid Build Coastguard Worker 	uint64_t obj_size;
202*d83cc019SAndroid Build Coastguard Worker 
203*d83cc019SAndroid Build Coastguard Worker 	obj = __gem_calloc(fd, alloc + 1, sizeof(*obj), &obj_size);
204*d83cc019SAndroid Build Coastguard Worker 	memset(&execbuf, 0, sizeof(execbuf));
205*d83cc019SAndroid Build Coastguard Worker 
206*d83cc019SAndroid Build Coastguard Worker 	obj[count].handle = gem_create(fd, 4096);
207*d83cc019SAndroid Build Coastguard Worker 	gem_write(fd, obj[count].handle, 0, &bbe, sizeof(bbe));
208*d83cc019SAndroid Build Coastguard Worker 
209*d83cc019SAndroid Build Coastguard Worker 	for (int i = 1; i <= count; i++) {
210*d83cc019SAndroid Build Coastguard Worker 		int j = count - i;
211*d83cc019SAndroid Build Coastguard Worker 
212*d83cc019SAndroid Build Coastguard Worker 		obj[j].handle = gem_create(fd, 1 << 20);
213*d83cc019SAndroid Build Coastguard Worker 		execbuf.buffers_ptr = to_user_pointer(&obj[j]);
214*d83cc019SAndroid Build Coastguard Worker 		execbuf.buffer_count = i + 1;
215*d83cc019SAndroid Build Coastguard Worker 		gem_execbuf(fd, &execbuf);
216*d83cc019SAndroid Build Coastguard Worker 	}
217*d83cc019SAndroid Build Coastguard Worker 
218*d83cc019SAndroid Build Coastguard Worker 	gem_close(fd, igt_hang_ring(fd, 0).spin->handle);
219*d83cc019SAndroid Build Coastguard Worker 	for (int i = 0; i <= count; i++)
220*d83cc019SAndroid Build Coastguard Worker 		gem_madvise(fd, obj[i].handle, I915_MADV_DONTNEED);
221*d83cc019SAndroid Build Coastguard Worker 	munmap(obj, obj_size);
222*d83cc019SAndroid Build Coastguard Worker }
223*d83cc019SAndroid Build Coastguard Worker 
userptr(int fd,uint64_t alloc,unsigned int flags)224*d83cc019SAndroid Build Coastguard Worker static void userptr(int fd, uint64_t alloc, unsigned int flags)
225*d83cc019SAndroid Build Coastguard Worker #define UDIRTY (1 << 0)
226*d83cc019SAndroid Build Coastguard Worker {
227*d83cc019SAndroid Build Coastguard Worker 	struct local_i915_gem_userptr userptr;
228*d83cc019SAndroid Build Coastguard Worker 	void *ptr;
229*d83cc019SAndroid Build Coastguard Worker 
230*d83cc019SAndroid Build Coastguard Worker 	igt_assert((alloc & 4095) == 0);
231*d83cc019SAndroid Build Coastguard Worker 
232*d83cc019SAndroid Build Coastguard Worker 	ptr = mmap(NULL, alloc,
233*d83cc019SAndroid Build Coastguard Worker 		   PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
234*d83cc019SAndroid Build Coastguard Worker 		   -1, 0);
235*d83cc019SAndroid Build Coastguard Worker 	igt_assert(ptr != (void *)-1);
236*d83cc019SAndroid Build Coastguard Worker 
237*d83cc019SAndroid Build Coastguard Worker 	memset(&userptr, 0, sizeof(userptr));
238*d83cc019SAndroid Build Coastguard Worker 	userptr.user_size = alloc;
239*d83cc019SAndroid Build Coastguard Worker 	userptr.user_ptr = to_user_pointer(ptr);
240*d83cc019SAndroid Build Coastguard Worker 	do_ioctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
241*d83cc019SAndroid Build Coastguard Worker 
242*d83cc019SAndroid Build Coastguard Worker 	if (flags & UDIRTY)
243*d83cc019SAndroid Build Coastguard Worker 		gem_set_domain(fd, userptr.handle,
244*d83cc019SAndroid Build Coastguard Worker 			       I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
245*d83cc019SAndroid Build Coastguard Worker 	else
246*d83cc019SAndroid Build Coastguard Worker 		gem_set_domain(fd, userptr.handle, I915_GEM_DOMAIN_GTT, 0);
247*d83cc019SAndroid Build Coastguard Worker 
248*d83cc019SAndroid Build Coastguard Worker 	madvise(ptr, alloc, MADV_FREE);
249*d83cc019SAndroid Build Coastguard Worker }
250*d83cc019SAndroid Build Coastguard Worker 
has_userptr(void)251*d83cc019SAndroid Build Coastguard Worker static bool has_userptr(void)
252*d83cc019SAndroid Build Coastguard Worker {
253*d83cc019SAndroid Build Coastguard Worker 	struct local_i915_gem_userptr userptr;
254*d83cc019SAndroid Build Coastguard Worker 	int fd = drm_open_driver(DRIVER_INTEL);
255*d83cc019SAndroid Build Coastguard Worker 	int err;
256*d83cc019SAndroid Build Coastguard Worker 
257*d83cc019SAndroid Build Coastguard Worker 	memset(&userptr, 0, sizeof(userptr));
258*d83cc019SAndroid Build Coastguard Worker 	userptr.user_size = 8192;
259*d83cc019SAndroid Build Coastguard Worker 	userptr.user_ptr = -4096;
260*d83cc019SAndroid Build Coastguard Worker 
261*d83cc019SAndroid Build Coastguard Worker 	err = 0;
262*d83cc019SAndroid Build Coastguard Worker 	if (drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr))
263*d83cc019SAndroid Build Coastguard Worker 		err = errno;
264*d83cc019SAndroid Build Coastguard Worker 
265*d83cc019SAndroid Build Coastguard Worker 	close(fd);
266*d83cc019SAndroid Build Coastguard Worker 
267*d83cc019SAndroid Build Coastguard Worker 	return err == EFAULT;
268*d83cc019SAndroid Build Coastguard Worker }
269*d83cc019SAndroid Build Coastguard Worker 
leak(int fd,uint64_t alloc)270*d83cc019SAndroid Build Coastguard Worker static void leak(int fd, uint64_t alloc)
271*d83cc019SAndroid Build Coastguard Worker {
272*d83cc019SAndroid Build Coastguard Worker 	char *ptr;
273*d83cc019SAndroid Build Coastguard Worker 
274*d83cc019SAndroid Build Coastguard Worker 	ptr = mmap(NULL, alloc, PROT_READ | PROT_WRITE,
275*d83cc019SAndroid Build Coastguard Worker 		   MAP_ANON | MAP_PRIVATE | MAP_POPULATE,
276*d83cc019SAndroid Build Coastguard Worker 		   -1, 0);
277*d83cc019SAndroid Build Coastguard Worker 	if (ptr != (char *)-1)
278*d83cc019SAndroid Build Coastguard Worker 		return;
279*d83cc019SAndroid Build Coastguard Worker 
280*d83cc019SAndroid Build Coastguard Worker 	while (alloc) {
281*d83cc019SAndroid Build Coastguard Worker 		alloc -= 4096;
282*d83cc019SAndroid Build Coastguard Worker 		ptr[alloc] = 0;
283*d83cc019SAndroid Build Coastguard Worker 	}
284*d83cc019SAndroid Build Coastguard Worker }
285*d83cc019SAndroid Build Coastguard Worker 
286*d83cc019SAndroid Build Coastguard Worker #define SOLO 1
287*d83cc019SAndroid Build Coastguard Worker #define USERPTR 2
288*d83cc019SAndroid Build Coastguard Worker #define USERPTR_DIRTY 4
289*d83cc019SAndroid Build Coastguard Worker #define OOM 8
290*d83cc019SAndroid Build Coastguard Worker 
run_test(int nchildren,uint64_t alloc,void (* func)(int,uint64_t),unsigned flags)291*d83cc019SAndroid Build Coastguard Worker static void run_test(int nchildren, uint64_t alloc,
292*d83cc019SAndroid Build Coastguard Worker 		     void (*func)(int, uint64_t), unsigned flags)
293*d83cc019SAndroid Build Coastguard Worker {
294*d83cc019SAndroid Build Coastguard Worker 	const int timeout = flags & SOLO ? 1 : 20;
295*d83cc019SAndroid Build Coastguard Worker 
296*d83cc019SAndroid Build Coastguard Worker 	/* Each pass consumes alloc bytes and doesn't drop
297*d83cc019SAndroid Build Coastguard Worker 	 * its reference to object (i.e. calls
298*d83cc019SAndroid Build Coastguard Worker 	 * gem_madvise(DONTNEED) instead of gem_close()).
299*d83cc019SAndroid Build Coastguard Worker 	 * After nchildren passes we expect each process
300*d83cc019SAndroid Build Coastguard Worker 	 * to have enough objects to consume all of memory
301*d83cc019SAndroid Build Coastguard Worker 	 * if left unchecked.
302*d83cc019SAndroid Build Coastguard Worker 	 */
303*d83cc019SAndroid Build Coastguard Worker 
304*d83cc019SAndroid Build Coastguard Worker 	if (flags & SOLO)
305*d83cc019SAndroid Build Coastguard Worker 		nchildren = 1;
306*d83cc019SAndroid Build Coastguard Worker 
307*d83cc019SAndroid Build Coastguard Worker 	/* Background load */
308*d83cc019SAndroid Build Coastguard Worker 	if (flags & OOM) {
309*d83cc019SAndroid Build Coastguard Worker 		igt_fork(child, nchildren) {
310*d83cc019SAndroid Build Coastguard Worker 			igt_until_timeout(timeout) {
311*d83cc019SAndroid Build Coastguard Worker 				int fd = drm_open_driver(DRIVER_INTEL);
312*d83cc019SAndroid Build Coastguard Worker 				for (int pass = 0; pass < nchildren; pass++)
313*d83cc019SAndroid Build Coastguard Worker 					leak(fd, alloc);
314*d83cc019SAndroid Build Coastguard Worker 				close(fd);
315*d83cc019SAndroid Build Coastguard Worker 			}
316*d83cc019SAndroid Build Coastguard Worker 		}
317*d83cc019SAndroid Build Coastguard Worker 	}
318*d83cc019SAndroid Build Coastguard Worker 
319*d83cc019SAndroid Build Coastguard Worker 	if (flags & USERPTR) {
320*d83cc019SAndroid Build Coastguard Worker 		igt_require(has_userptr());
321*d83cc019SAndroid Build Coastguard Worker 		igt_fork(child, (nchildren + 1)/2) {
322*d83cc019SAndroid Build Coastguard Worker 			igt_until_timeout(timeout) {
323*d83cc019SAndroid Build Coastguard Worker 				int fd = drm_open_driver(DRIVER_INTEL);
324*d83cc019SAndroid Build Coastguard Worker 				for (int pass = 0; pass < nchildren; pass++)
325*d83cc019SAndroid Build Coastguard Worker 					userptr(fd, alloc, 0);
326*d83cc019SAndroid Build Coastguard Worker 				close(fd);
327*d83cc019SAndroid Build Coastguard Worker 			}
328*d83cc019SAndroid Build Coastguard Worker 		}
329*d83cc019SAndroid Build Coastguard Worker 		nchildren = (nchildren + 1)/2;
330*d83cc019SAndroid Build Coastguard Worker 	}
331*d83cc019SAndroid Build Coastguard Worker 
332*d83cc019SAndroid Build Coastguard Worker 	if (flags & USERPTR_DIRTY) {
333*d83cc019SAndroid Build Coastguard Worker 		igt_require(has_userptr());
334*d83cc019SAndroid Build Coastguard Worker 		igt_fork(child, (nchildren + 1)/2) {
335*d83cc019SAndroid Build Coastguard Worker 			igt_until_timeout(timeout) {
336*d83cc019SAndroid Build Coastguard Worker 				int fd = drm_open_driver(DRIVER_INTEL);
337*d83cc019SAndroid Build Coastguard Worker 				for (int pass = 0; pass < nchildren; pass++)
338*d83cc019SAndroid Build Coastguard Worker 					userptr(fd, alloc, UDIRTY);
339*d83cc019SAndroid Build Coastguard Worker 				close(fd);
340*d83cc019SAndroid Build Coastguard Worker 			}
341*d83cc019SAndroid Build Coastguard Worker 		}
342*d83cc019SAndroid Build Coastguard Worker 		nchildren = (nchildren + 1)/2;
343*d83cc019SAndroid Build Coastguard Worker 	}
344*d83cc019SAndroid Build Coastguard Worker 
345*d83cc019SAndroid Build Coastguard Worker 	/* Exercise major ioctls */
346*d83cc019SAndroid Build Coastguard Worker 	igt_fork(child, nchildren) {
347*d83cc019SAndroid Build Coastguard Worker 		igt_until_timeout(timeout) {
348*d83cc019SAndroid Build Coastguard Worker 			int fd = drm_open_driver(DRIVER_INTEL);
349*d83cc019SAndroid Build Coastguard Worker 			for (int pass = 0; pass < nchildren; pass++)
350*d83cc019SAndroid Build Coastguard Worker 				func(fd, alloc);
351*d83cc019SAndroid Build Coastguard Worker 			close(fd);
352*d83cc019SAndroid Build Coastguard Worker 		}
353*d83cc019SAndroid Build Coastguard Worker 	}
354*d83cc019SAndroid Build Coastguard Worker 	igt_waitchildren();
355*d83cc019SAndroid Build Coastguard Worker }
356*d83cc019SAndroid Build Coastguard Worker 
reclaim(unsigned engine,int timeout)357*d83cc019SAndroid Build Coastguard Worker static void reclaim(unsigned engine, int timeout)
358*d83cc019SAndroid Build Coastguard Worker {
359*d83cc019SAndroid Build Coastguard Worker 	const uint64_t timeout_100ms = 100000000LL;
360*d83cc019SAndroid Build Coastguard Worker 	int fd = drm_open_driver(DRIVER_INTEL);
361*d83cc019SAndroid Build Coastguard Worker 	int debugfs = igt_debugfs_dir(fd);
362*d83cc019SAndroid Build Coastguard Worker 	igt_spin_t *spin;
363*d83cc019SAndroid Build Coastguard Worker 	volatile uint32_t *shared;
364*d83cc019SAndroid Build Coastguard Worker 
365*d83cc019SAndroid Build Coastguard Worker 	shared = mmap(0, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
366*d83cc019SAndroid Build Coastguard Worker 	igt_assert(shared != MAP_FAILED);
367*d83cc019SAndroid Build Coastguard Worker 
368*d83cc019SAndroid Build Coastguard Worker 	igt_fork(child, sysconf(_SC_NPROCESSORS_ONLN)) {
369*d83cc019SAndroid Build Coastguard Worker 		do {
370*d83cc019SAndroid Build Coastguard Worker 			igt_sysfs_printf(debugfs, "i915_drop_caches",
371*d83cc019SAndroid Build Coastguard Worker 					"%d", DROP_BOUND | DROP_UNBOUND);
372*d83cc019SAndroid Build Coastguard Worker 		} while (!*shared);
373*d83cc019SAndroid Build Coastguard Worker 	}
374*d83cc019SAndroid Build Coastguard Worker 
375*d83cc019SAndroid Build Coastguard Worker 	spin = igt_spin_new(fd, .engine = engine);
376*d83cc019SAndroid Build Coastguard Worker 	igt_until_timeout(timeout) {
377*d83cc019SAndroid Build Coastguard Worker 		igt_spin_t *next = __igt_spin_new(fd, .engine = engine);
378*d83cc019SAndroid Build Coastguard Worker 
379*d83cc019SAndroid Build Coastguard Worker 		igt_spin_set_timeout(spin, timeout_100ms);
380*d83cc019SAndroid Build Coastguard Worker 		gem_sync(fd, spin->handle);
381*d83cc019SAndroid Build Coastguard Worker 
382*d83cc019SAndroid Build Coastguard Worker 		igt_spin_free(fd, spin);
383*d83cc019SAndroid Build Coastguard Worker 		spin = next;
384*d83cc019SAndroid Build Coastguard Worker 	}
385*d83cc019SAndroid Build Coastguard Worker 	igt_spin_free(fd, spin);
386*d83cc019SAndroid Build Coastguard Worker 
387*d83cc019SAndroid Build Coastguard Worker 	*shared = 1;
388*d83cc019SAndroid Build Coastguard Worker 	igt_waitchildren();
389*d83cc019SAndroid Build Coastguard Worker 
390*d83cc019SAndroid Build Coastguard Worker 	munmap((void *)shared, 4096);
391*d83cc019SAndroid Build Coastguard Worker 	close(debugfs);
392*d83cc019SAndroid Build Coastguard Worker 	close(fd);
393*d83cc019SAndroid Build Coastguard Worker }
394*d83cc019SAndroid Build Coastguard Worker 
395*d83cc019SAndroid Build Coastguard Worker igt_main
396*d83cc019SAndroid Build Coastguard Worker {
397*d83cc019SAndroid Build Coastguard Worker 	const struct test {
398*d83cc019SAndroid Build Coastguard Worker 		const char *name;
399*d83cc019SAndroid Build Coastguard Worker 		void (*func)(int, uint64_t);
400*d83cc019SAndroid Build Coastguard Worker 	} tests[] = {
401*d83cc019SAndroid Build Coastguard Worker 		{ "get-pages", get_pages },
402*d83cc019SAndroid Build Coastguard Worker 		{ "get-pages-dirty", get_pages_dirty },
403*d83cc019SAndroid Build Coastguard Worker 		{ "pwrite", pwrite_ },
404*d83cc019SAndroid Build Coastguard Worker 		{ "pread", pread_ },
405*d83cc019SAndroid Build Coastguard Worker 		{ "mmap-gtt", mmap_gtt },
406*d83cc019SAndroid Build Coastguard Worker 		{ "mmap-cpu", mmap_cpu },
407*d83cc019SAndroid Build Coastguard Worker 		{ "execbuf1", execbuf1 },
408*d83cc019SAndroid Build Coastguard Worker 		{ "execbufN", execbufN },
409*d83cc019SAndroid Build Coastguard Worker 		{ "execbufX", execbufX },
410*d83cc019SAndroid Build Coastguard Worker 		{ "hang", hang },
411*d83cc019SAndroid Build Coastguard Worker 		{ NULL },
412*d83cc019SAndroid Build Coastguard Worker 	};
413*d83cc019SAndroid Build Coastguard Worker 	const struct mode {
414*d83cc019SAndroid Build Coastguard Worker 		const char *suffix;
415*d83cc019SAndroid Build Coastguard Worker 		unsigned flags;
416*d83cc019SAndroid Build Coastguard Worker 	} modes[] = {
417*d83cc019SAndroid Build Coastguard Worker 		{ "-sanitycheck", SOLO },
418*d83cc019SAndroid Build Coastguard Worker 		{ "", 0 },
419*d83cc019SAndroid Build Coastguard Worker 		{ "-userptr", USERPTR },
420*d83cc019SAndroid Build Coastguard Worker 		{ "-userptr-dirty", USERPTR | USERPTR_DIRTY },
421*d83cc019SAndroid Build Coastguard Worker 		{ "-oom", USERPTR | OOM },
422*d83cc019SAndroid Build Coastguard Worker 		{ NULL },
423*d83cc019SAndroid Build Coastguard Worker 	};
424*d83cc019SAndroid Build Coastguard Worker 	uint64_t alloc_size = 0;
425*d83cc019SAndroid Build Coastguard Worker 	int num_processes = 0;
426*d83cc019SAndroid Build Coastguard Worker 
427*d83cc019SAndroid Build Coastguard Worker 	igt_skip_on_simulation();
428*d83cc019SAndroid Build Coastguard Worker 
429*d83cc019SAndroid Build Coastguard Worker 	igt_fixture {
430*d83cc019SAndroid Build Coastguard Worker 		uint64_t mem_size = intel_get_total_ram_mb();
431*d83cc019SAndroid Build Coastguard Worker 		unsigned int engine;
432*d83cc019SAndroid Build Coastguard Worker 		int fd;
433*d83cc019SAndroid Build Coastguard Worker 
434*d83cc019SAndroid Build Coastguard Worker 		fd = drm_open_driver(DRIVER_INTEL);
435*d83cc019SAndroid Build Coastguard Worker 		igt_require_gem(fd);
436*d83cc019SAndroid Build Coastguard Worker 
437*d83cc019SAndroid Build Coastguard Worker 		/*
438*d83cc019SAndroid Build Coastguard Worker 		 * Spawn enough processes to use all memory, but each only
439*d83cc019SAndroid Build Coastguard Worker 		 * uses half the available mappable aperture ~128MiB.
440*d83cc019SAndroid Build Coastguard Worker 		 * Individually the processes would be ok, but en masse
441*d83cc019SAndroid Build Coastguard Worker 		 * we expect the shrinker to start purging objects,
442*d83cc019SAndroid Build Coastguard Worker 		 * and possibly fail.
443*d83cc019SAndroid Build Coastguard Worker 		 */
444*d83cc019SAndroid Build Coastguard Worker 		alloc_size = gem_mappable_aperture_size() / 2;
445*d83cc019SAndroid Build Coastguard Worker 		num_processes = 1 + (mem_size / (alloc_size >> 20));
446*d83cc019SAndroid Build Coastguard Worker 
447*d83cc019SAndroid Build Coastguard Worker 		igt_info("Using %d processes and %'lluMiB per process\n",
448*d83cc019SAndroid Build Coastguard Worker 			 num_processes, (long long)(alloc_size >> 20));
449*d83cc019SAndroid Build Coastguard Worker 
450*d83cc019SAndroid Build Coastguard Worker 		intel_require_memory(num_processes, alloc_size,
451*d83cc019SAndroid Build Coastguard Worker 				     CHECK_SWAP | CHECK_RAM);
452*d83cc019SAndroid Build Coastguard Worker 
453*d83cc019SAndroid Build Coastguard Worker 		nengine = 0;
454*d83cc019SAndroid Build Coastguard Worker 		for_each_engine(fd, engine)
455*d83cc019SAndroid Build Coastguard Worker 			engines[nengine++] = engine;
456*d83cc019SAndroid Build Coastguard Worker 		igt_require(nengine);
457*d83cc019SAndroid Build Coastguard Worker 
458*d83cc019SAndroid Build Coastguard Worker 		close(fd);
459*d83cc019SAndroid Build Coastguard Worker 	}
460*d83cc019SAndroid Build Coastguard Worker 
461*d83cc019SAndroid Build Coastguard Worker 	igt_subtest("reclaim")
462*d83cc019SAndroid Build Coastguard Worker 		reclaim(I915_EXEC_DEFAULT, 2);
463*d83cc019SAndroid Build Coastguard Worker 
464*d83cc019SAndroid Build Coastguard Worker 	for(const struct test *t = tests; t->name; t++) {
465*d83cc019SAndroid Build Coastguard Worker 		for(const struct mode *m = modes; m->suffix; m++) {
466*d83cc019SAndroid Build Coastguard Worker 			igt_subtest_f("%s%s", t->name, m->suffix)
467*d83cc019SAndroid Build Coastguard Worker 				run_test(num_processes, alloc_size,
468*d83cc019SAndroid Build Coastguard Worker 					 t->func, m->flags);
469*d83cc019SAndroid Build Coastguard Worker 		}
470*d83cc019SAndroid Build Coastguard Worker 	}
471*d83cc019SAndroid Build Coastguard Worker }
472