xref: /aosp_15_r20/external/igt-gpu-tools/benchmarks/gem_syslatency.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 #include "igt.h"
26*d83cc019SAndroid Build Coastguard Worker #include <unistd.h>
27*d83cc019SAndroid Build Coastguard Worker #include <stdlib.h>
28*d83cc019SAndroid Build Coastguard Worker #include <stdint.h>
29*d83cc019SAndroid Build Coastguard Worker #include <stdio.h>
30*d83cc019SAndroid Build Coastguard Worker #include <string.h>
31*d83cc019SAndroid Build Coastguard Worker #include <fcntl.h>
32*d83cc019SAndroid Build Coastguard Worker #include <ftw.h>
33*d83cc019SAndroid Build Coastguard Worker #include <inttypes.h>
34*d83cc019SAndroid Build Coastguard Worker #include <pthread.h>
35*d83cc019SAndroid Build Coastguard Worker #include <sched.h>
36*d83cc019SAndroid Build Coastguard Worker #include <signal.h>
37*d83cc019SAndroid Build Coastguard Worker #include <errno.h>
38*d83cc019SAndroid Build Coastguard Worker #include <sys/stat.h>
39*d83cc019SAndroid Build Coastguard Worker #include <sys/ioctl.h>
40*d83cc019SAndroid Build Coastguard Worker #include <sys/time.h>
41*d83cc019SAndroid Build Coastguard Worker #include <time.h>
42*d83cc019SAndroid Build Coastguard Worker #include <limits.h>
43*d83cc019SAndroid Build Coastguard Worker #include "drm.h"
44*d83cc019SAndroid Build Coastguard Worker 
45*d83cc019SAndroid Build Coastguard Worker #include <linux/unistd.h>
46*d83cc019SAndroid Build Coastguard Worker 
47*d83cc019SAndroid Build Coastguard Worker #define sigev_notify_thread_id _sigev_un._tid
48*d83cc019SAndroid Build Coastguard Worker 
49*d83cc019SAndroid Build Coastguard Worker static volatile int done;
50*d83cc019SAndroid Build Coastguard Worker 
51*d83cc019SAndroid Build Coastguard Worker struct gem_busyspin {
52*d83cc019SAndroid Build Coastguard Worker 	pthread_t thread;
53*d83cc019SAndroid Build Coastguard Worker 	unsigned long sz;
54*d83cc019SAndroid Build Coastguard Worker 	unsigned long count;
55*d83cc019SAndroid Build Coastguard Worker 	bool leak;
56*d83cc019SAndroid Build Coastguard Worker 	bool interrupts;
57*d83cc019SAndroid Build Coastguard Worker };
58*d83cc019SAndroid Build Coastguard Worker 
59*d83cc019SAndroid Build Coastguard Worker struct sys_wait {
60*d83cc019SAndroid Build Coastguard Worker 	pthread_t thread;
61*d83cc019SAndroid Build Coastguard Worker 	struct igt_mean mean;
62*d83cc019SAndroid Build Coastguard Worker };
63*d83cc019SAndroid Build Coastguard Worker 
force_low_latency(void)64*d83cc019SAndroid Build Coastguard Worker static void force_low_latency(void)
65*d83cc019SAndroid Build Coastguard Worker {
66*d83cc019SAndroid Build Coastguard Worker 	int32_t target = 0;
67*d83cc019SAndroid Build Coastguard Worker 	int fd = open("/dev/cpu_dma_latency", O_RDWR);
68*d83cc019SAndroid Build Coastguard Worker 	if (fd < 0 || write(fd, &target, sizeof(target)) < 0)
69*d83cc019SAndroid Build Coastguard Worker 		fprintf(stderr,
70*d83cc019SAndroid Build Coastguard Worker 			"Unable to prevent CPU sleeps and force low latency using /dev/cpu_dma_latency: %s\n",
71*d83cc019SAndroid Build Coastguard Worker 			strerror(errno));
72*d83cc019SAndroid Build Coastguard Worker }
73*d83cc019SAndroid Build Coastguard Worker 
74*d83cc019SAndroid Build Coastguard Worker #define LOCAL_I915_EXEC_NO_RELOC (1<<11)
75*d83cc019SAndroid Build Coastguard Worker #define LOCAL_I915_EXEC_HANDLE_LUT (1<<12)
76*d83cc019SAndroid Build Coastguard Worker 
77*d83cc019SAndroid Build Coastguard Worker #define LOCAL_I915_EXEC_BSD_SHIFT      (13)
78*d83cc019SAndroid Build Coastguard Worker #define LOCAL_I915_EXEC_BSD_MASK       (3 << LOCAL_I915_EXEC_BSD_SHIFT)
79*d83cc019SAndroid Build Coastguard Worker 
80*d83cc019SAndroid Build Coastguard Worker #define ENGINE_FLAGS  (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK)
81*d83cc019SAndroid Build Coastguard Worker 
ignore_engine(int fd,unsigned engine)82*d83cc019SAndroid Build Coastguard Worker static bool ignore_engine(int fd, unsigned engine)
83*d83cc019SAndroid Build Coastguard Worker {
84*d83cc019SAndroid Build Coastguard Worker 	if (engine == 0)
85*d83cc019SAndroid Build Coastguard Worker 		return true;
86*d83cc019SAndroid Build Coastguard Worker 
87*d83cc019SAndroid Build Coastguard Worker 	if (gem_has_bsd2(fd) && engine == I915_EXEC_BSD)
88*d83cc019SAndroid Build Coastguard Worker 		return true;
89*d83cc019SAndroid Build Coastguard Worker 
90*d83cc019SAndroid Build Coastguard Worker 	return false;
91*d83cc019SAndroid Build Coastguard Worker }
92*d83cc019SAndroid Build Coastguard Worker 
gem_busyspin(void * arg)93*d83cc019SAndroid Build Coastguard Worker static void *gem_busyspin(void *arg)
94*d83cc019SAndroid Build Coastguard Worker {
95*d83cc019SAndroid Build Coastguard Worker 	const uint32_t bbe = MI_BATCH_BUFFER_END;
96*d83cc019SAndroid Build Coastguard Worker 	struct gem_busyspin *bs = arg;
97*d83cc019SAndroid Build Coastguard Worker 	struct drm_i915_gem_execbuffer2 execbuf;
98*d83cc019SAndroid Build Coastguard Worker 	struct drm_i915_gem_exec_object2 obj[2];
99*d83cc019SAndroid Build Coastguard Worker 	const unsigned sz =
100*d83cc019SAndroid Build Coastguard Worker 		bs->sz ? bs->sz + sizeof(bbe) : bs->leak ? 16 << 20 : 4 << 10;
101*d83cc019SAndroid Build Coastguard Worker 	unsigned engines[16];
102*d83cc019SAndroid Build Coastguard Worker 	unsigned nengine;
103*d83cc019SAndroid Build Coastguard Worker 	unsigned engine;
104*d83cc019SAndroid Build Coastguard Worker 	int fd;
105*d83cc019SAndroid Build Coastguard Worker 
106*d83cc019SAndroid Build Coastguard Worker 	fd = drm_open_driver(DRIVER_INTEL);
107*d83cc019SAndroid Build Coastguard Worker 
108*d83cc019SAndroid Build Coastguard Worker 	nengine = 0;
109*d83cc019SAndroid Build Coastguard Worker 	for_each_engine(fd, engine)
110*d83cc019SAndroid Build Coastguard Worker 		if (!ignore_engine(fd, engine)) engines[nengine++] = engine;
111*d83cc019SAndroid Build Coastguard Worker 
112*d83cc019SAndroid Build Coastguard Worker 	memset(obj, 0, sizeof(obj));
113*d83cc019SAndroid Build Coastguard Worker 	obj[0].handle = gem_create(fd, 4096);
114*d83cc019SAndroid Build Coastguard Worker 	obj[0].flags = EXEC_OBJECT_WRITE;
115*d83cc019SAndroid Build Coastguard Worker 	obj[1].handle = gem_create(fd, sz);
116*d83cc019SAndroid Build Coastguard Worker 	gem_write(fd, obj[1].handle, bs->sz, &bbe, sizeof(bbe));
117*d83cc019SAndroid Build Coastguard Worker 
118*d83cc019SAndroid Build Coastguard Worker 	memset(&execbuf, 0, sizeof(execbuf));
119*d83cc019SAndroid Build Coastguard Worker 	if (bs->interrupts) {
120*d83cc019SAndroid Build Coastguard Worker 		execbuf.buffers_ptr = (uintptr_t)&obj[0];
121*d83cc019SAndroid Build Coastguard Worker 		execbuf.buffer_count = 2;
122*d83cc019SAndroid Build Coastguard Worker 	} else {
123*d83cc019SAndroid Build Coastguard Worker 		execbuf.buffers_ptr = (uintptr_t)&obj[1];
124*d83cc019SAndroid Build Coastguard Worker 		execbuf.buffer_count = 1;
125*d83cc019SAndroid Build Coastguard Worker 	}
126*d83cc019SAndroid Build Coastguard Worker 	execbuf.flags |= LOCAL_I915_EXEC_HANDLE_LUT;
127*d83cc019SAndroid Build Coastguard Worker 	execbuf.flags |= LOCAL_I915_EXEC_NO_RELOC;
128*d83cc019SAndroid Build Coastguard Worker 	if (__gem_execbuf(fd, &execbuf)) {
129*d83cc019SAndroid Build Coastguard Worker 		execbuf.flags = 0;
130*d83cc019SAndroid Build Coastguard Worker 		gem_execbuf(fd, &execbuf);
131*d83cc019SAndroid Build Coastguard Worker 	}
132*d83cc019SAndroid Build Coastguard Worker 
133*d83cc019SAndroid Build Coastguard Worker 	while (!done) {
134*d83cc019SAndroid Build Coastguard Worker 		for (int n = 0; n < nengine; n++) {
135*d83cc019SAndroid Build Coastguard Worker 			const int m = rand() % nengine;
136*d83cc019SAndroid Build Coastguard Worker 			unsigned int tmp = engines[n];
137*d83cc019SAndroid Build Coastguard Worker 			engines[n] = engines[m];
138*d83cc019SAndroid Build Coastguard Worker 			engines[m] = tmp;
139*d83cc019SAndroid Build Coastguard Worker 		}
140*d83cc019SAndroid Build Coastguard Worker 		for (int n = 0; n < nengine; n++) {
141*d83cc019SAndroid Build Coastguard Worker 			execbuf.flags &= ~ENGINE_FLAGS;
142*d83cc019SAndroid Build Coastguard Worker 			execbuf.flags |= engines[n];
143*d83cc019SAndroid Build Coastguard Worker 			gem_execbuf(fd, &execbuf);
144*d83cc019SAndroid Build Coastguard Worker 		}
145*d83cc019SAndroid Build Coastguard Worker 		bs->count += nengine;
146*d83cc019SAndroid Build Coastguard Worker 		if (bs->leak) {
147*d83cc019SAndroid Build Coastguard Worker 			gem_madvise(fd, obj[1].handle, I915_MADV_DONTNEED);
148*d83cc019SAndroid Build Coastguard Worker 			obj[1].handle = gem_create(fd, sz);
149*d83cc019SAndroid Build Coastguard Worker 			gem_write(fd, obj[1].handle, bs->sz, &bbe, sizeof(bbe));
150*d83cc019SAndroid Build Coastguard Worker 		}
151*d83cc019SAndroid Build Coastguard Worker 	}
152*d83cc019SAndroid Build Coastguard Worker 
153*d83cc019SAndroid Build Coastguard Worker 	close(fd);
154*d83cc019SAndroid Build Coastguard Worker 	return NULL;
155*d83cc019SAndroid Build Coastguard Worker }
156*d83cc019SAndroid Build Coastguard Worker 
elapsed(const struct timespec * a,const struct timespec * b)157*d83cc019SAndroid Build Coastguard Worker static double elapsed(const struct timespec *a, const struct timespec *b)
158*d83cc019SAndroid Build Coastguard Worker {
159*d83cc019SAndroid Build Coastguard Worker 	return 1e9*(b->tv_sec - a->tv_sec) + (b->tv_nsec - a ->tv_nsec);
160*d83cc019SAndroid Build Coastguard Worker }
161*d83cc019SAndroid Build Coastguard Worker 
sys_wait(void * arg)162*d83cc019SAndroid Build Coastguard Worker static void *sys_wait(void *arg)
163*d83cc019SAndroid Build Coastguard Worker {
164*d83cc019SAndroid Build Coastguard Worker 	struct sys_wait *w = arg;
165*d83cc019SAndroid Build Coastguard Worker 	struct sigevent sev;
166*d83cc019SAndroid Build Coastguard Worker 	timer_t timer;
167*d83cc019SAndroid Build Coastguard Worker 	sigset_t mask;
168*d83cc019SAndroid Build Coastguard Worker 	struct timespec now;
169*d83cc019SAndroid Build Coastguard Worker #define SIG SIGRTMIN
170*d83cc019SAndroid Build Coastguard Worker 
171*d83cc019SAndroid Build Coastguard Worker 	sigemptyset(&mask);
172*d83cc019SAndroid Build Coastguard Worker 	sigaddset(&mask, SIG);
173*d83cc019SAndroid Build Coastguard Worker 	sigprocmask(SIG_SETMASK, &mask, NULL);
174*d83cc019SAndroid Build Coastguard Worker 
175*d83cc019SAndroid Build Coastguard Worker 	sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID;
176*d83cc019SAndroid Build Coastguard Worker 	sev.sigev_notify_thread_id = gettid();
177*d83cc019SAndroid Build Coastguard Worker 	sev.sigev_signo = SIG;
178*d83cc019SAndroid Build Coastguard Worker 	timer_create(CLOCK_MONOTONIC, &sev, &timer);
179*d83cc019SAndroid Build Coastguard Worker 
180*d83cc019SAndroid Build Coastguard Worker 	clock_gettime(CLOCK_MONOTONIC, &now);
181*d83cc019SAndroid Build Coastguard Worker 	while (!done) {
182*d83cc019SAndroid Build Coastguard Worker 		struct itimerspec its;
183*d83cc019SAndroid Build Coastguard Worker 		int sigs;
184*d83cc019SAndroid Build Coastguard Worker 
185*d83cc019SAndroid Build Coastguard Worker 		its.it_value = now;
186*d83cc019SAndroid Build Coastguard Worker 		its.it_value.tv_nsec += 100 * 1000;
187*d83cc019SAndroid Build Coastguard Worker 		its.it_value.tv_nsec += rand() % (NSEC_PER_SEC / 1000);
188*d83cc019SAndroid Build Coastguard Worker 		if (its.it_value.tv_nsec >= NSEC_PER_SEC) {
189*d83cc019SAndroid Build Coastguard Worker 			its.it_value.tv_nsec -= NSEC_PER_SEC;
190*d83cc019SAndroid Build Coastguard Worker 			its.it_value.tv_sec += 1;
191*d83cc019SAndroid Build Coastguard Worker 		}
192*d83cc019SAndroid Build Coastguard Worker 		its.it_interval.tv_sec = its.it_interval.tv_nsec = 0;
193*d83cc019SAndroid Build Coastguard Worker 		timer_settime(timer, TIMER_ABSTIME, &its, NULL);
194*d83cc019SAndroid Build Coastguard Worker 
195*d83cc019SAndroid Build Coastguard Worker 		sigwait(&mask, &sigs);
196*d83cc019SAndroid Build Coastguard Worker 		clock_gettime(CLOCK_MONOTONIC, &now);
197*d83cc019SAndroid Build Coastguard Worker 		igt_mean_add(&w->mean, elapsed(&its.it_value, &now));
198*d83cc019SAndroid Build Coastguard Worker 	}
199*d83cc019SAndroid Build Coastguard Worker 
200*d83cc019SAndroid Build Coastguard Worker 	sigprocmask(SIG_UNBLOCK, &mask, NULL);
201*d83cc019SAndroid Build Coastguard Worker 	timer_delete(timer);
202*d83cc019SAndroid Build Coastguard Worker 
203*d83cc019SAndroid Build Coastguard Worker 	return NULL;
204*d83cc019SAndroid Build Coastguard Worker }
205*d83cc019SAndroid Build Coastguard Worker 
206*d83cc019SAndroid Build Coastguard Worker #define PAGE_SIZE 4096
sys_thp_alloc(void * arg)207*d83cc019SAndroid Build Coastguard Worker static void *sys_thp_alloc(void *arg)
208*d83cc019SAndroid Build Coastguard Worker {
209*d83cc019SAndroid Build Coastguard Worker 	struct sys_wait *w = arg;
210*d83cc019SAndroid Build Coastguard Worker 	struct timespec now;
211*d83cc019SAndroid Build Coastguard Worker 
212*d83cc019SAndroid Build Coastguard Worker 	clock_gettime(CLOCK_MONOTONIC, &now);
213*d83cc019SAndroid Build Coastguard Worker 	while (!done) {
214*d83cc019SAndroid Build Coastguard Worker 		const size_t sz = 2 << 20;
215*d83cc019SAndroid Build Coastguard Worker 		const struct timespec start = now;
216*d83cc019SAndroid Build Coastguard Worker 		void *ptr;
217*d83cc019SAndroid Build Coastguard Worker 
218*d83cc019SAndroid Build Coastguard Worker 		ptr = mmap(NULL, sz,
219*d83cc019SAndroid Build Coastguard Worker 			   PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
220*d83cc019SAndroid Build Coastguard Worker 			   -1, 0);
221*d83cc019SAndroid Build Coastguard Worker 		assert(ptr != MAP_FAILED);
222*d83cc019SAndroid Build Coastguard Worker 		madvise(ptr, sz, MADV_HUGEPAGE);
223*d83cc019SAndroid Build Coastguard Worker 		for (size_t page = 0; page < sz; page += PAGE_SIZE)
224*d83cc019SAndroid Build Coastguard Worker 			*(volatile uint32_t *)((unsigned char *)ptr + page) = 0;
225*d83cc019SAndroid Build Coastguard Worker 		munmap(ptr, sz);
226*d83cc019SAndroid Build Coastguard Worker 
227*d83cc019SAndroid Build Coastguard Worker 		clock_gettime(CLOCK_MONOTONIC, &now);
228*d83cc019SAndroid Build Coastguard Worker 		igt_mean_add(&w->mean, elapsed(&start, &now));
229*d83cc019SAndroid Build Coastguard Worker 	}
230*d83cc019SAndroid Build Coastguard Worker 
231*d83cc019SAndroid Build Coastguard Worker 	return NULL;
232*d83cc019SAndroid Build Coastguard Worker }
233*d83cc019SAndroid Build Coastguard Worker 
bind_cpu(pthread_attr_t * attr,int cpu)234*d83cc019SAndroid Build Coastguard Worker static void bind_cpu(pthread_attr_t *attr, int cpu)
235*d83cc019SAndroid Build Coastguard Worker {
236*d83cc019SAndroid Build Coastguard Worker #ifdef __USE_GNU
237*d83cc019SAndroid Build Coastguard Worker 	cpu_set_t mask;
238*d83cc019SAndroid Build Coastguard Worker 
239*d83cc019SAndroid Build Coastguard Worker 	if (cpu == -1)
240*d83cc019SAndroid Build Coastguard Worker 		return;
241*d83cc019SAndroid Build Coastguard Worker 
242*d83cc019SAndroid Build Coastguard Worker 	CPU_ZERO(&mask);
243*d83cc019SAndroid Build Coastguard Worker 	CPU_SET(cpu, &mask);
244*d83cc019SAndroid Build Coastguard Worker 
245*d83cc019SAndroid Build Coastguard Worker 	pthread_attr_setaffinity_np(attr, sizeof(mask), &mask);
246*d83cc019SAndroid Build Coastguard Worker #endif
247*d83cc019SAndroid Build Coastguard Worker }
248*d83cc019SAndroid Build Coastguard Worker 
rtprio(pthread_attr_t * attr,int prio)249*d83cc019SAndroid Build Coastguard Worker static void rtprio(pthread_attr_t *attr, int prio)
250*d83cc019SAndroid Build Coastguard Worker {
251*d83cc019SAndroid Build Coastguard Worker #ifdef PTHREAD_EXPLICIT_SCHED
252*d83cc019SAndroid Build Coastguard Worker 	struct sched_param param = { .sched_priority = 99 };
253*d83cc019SAndroid Build Coastguard Worker 	pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED);
254*d83cc019SAndroid Build Coastguard Worker 	pthread_attr_setschedpolicy(attr, SCHED_FIFO);
255*d83cc019SAndroid Build Coastguard Worker 	pthread_attr_setschedparam(attr, &param);
256*d83cc019SAndroid Build Coastguard Worker #endif
257*d83cc019SAndroid Build Coastguard Worker }
258*d83cc019SAndroid Build Coastguard Worker 
l_estimate(igt_stats_t * stats)259*d83cc019SAndroid Build Coastguard Worker static double l_estimate(igt_stats_t *stats)
260*d83cc019SAndroid Build Coastguard Worker {
261*d83cc019SAndroid Build Coastguard Worker 	if (stats->n_values > 9)
262*d83cc019SAndroid Build Coastguard Worker 		return igt_stats_get_trimean(stats);
263*d83cc019SAndroid Build Coastguard Worker 	else if (stats->n_values > 5)
264*d83cc019SAndroid Build Coastguard Worker 		return igt_stats_get_median(stats);
265*d83cc019SAndroid Build Coastguard Worker 	else
266*d83cc019SAndroid Build Coastguard Worker 		return igt_stats_get_mean(stats);
267*d83cc019SAndroid Build Coastguard Worker }
268*d83cc019SAndroid Build Coastguard Worker 
min_measurement_error(void)269*d83cc019SAndroid Build Coastguard Worker static double min_measurement_error(void)
270*d83cc019SAndroid Build Coastguard Worker {
271*d83cc019SAndroid Build Coastguard Worker 	struct timespec start, end;
272*d83cc019SAndroid Build Coastguard Worker 	int n;
273*d83cc019SAndroid Build Coastguard Worker 
274*d83cc019SAndroid Build Coastguard Worker 	clock_gettime(CLOCK_MONOTONIC, &start);
275*d83cc019SAndroid Build Coastguard Worker 	for (n = 0; n < 1024; n++)
276*d83cc019SAndroid Build Coastguard Worker 		clock_gettime(CLOCK_MONOTONIC, &end);
277*d83cc019SAndroid Build Coastguard Worker 
278*d83cc019SAndroid Build Coastguard Worker 	return elapsed(&start, &end) / n;
279*d83cc019SAndroid Build Coastguard Worker }
280*d83cc019SAndroid Build Coastguard Worker 
print_entry(const char * filepath,const struct stat * info,const int typeflag,struct FTW * pathinfo)281*d83cc019SAndroid Build Coastguard Worker static int print_entry(const char *filepath, const struct stat *info,
282*d83cc019SAndroid Build Coastguard Worker 		       const int typeflag, struct FTW *pathinfo)
283*d83cc019SAndroid Build Coastguard Worker {
284*d83cc019SAndroid Build Coastguard Worker 	int fd;
285*d83cc019SAndroid Build Coastguard Worker 
286*d83cc019SAndroid Build Coastguard Worker 	fd = open(filepath, O_RDONLY);
287*d83cc019SAndroid Build Coastguard Worker 	if (fd != -1)  {
288*d83cc019SAndroid Build Coastguard Worker 		void *ptr;
289*d83cc019SAndroid Build Coastguard Worker 
290*d83cc019SAndroid Build Coastguard Worker 		ptr = mmap(NULL, info->st_size,
291*d83cc019SAndroid Build Coastguard Worker 			   PROT_READ, MAP_SHARED | MAP_POPULATE,
292*d83cc019SAndroid Build Coastguard Worker 			   fd, 0);
293*d83cc019SAndroid Build Coastguard Worker 		if (ptr != MAP_FAILED)
294*d83cc019SAndroid Build Coastguard Worker 			munmap(ptr, info->st_size);
295*d83cc019SAndroid Build Coastguard Worker 
296*d83cc019SAndroid Build Coastguard Worker 		close(fd);
297*d83cc019SAndroid Build Coastguard Worker 	}
298*d83cc019SAndroid Build Coastguard Worker 
299*d83cc019SAndroid Build Coastguard Worker 	return 0;
300*d83cc019SAndroid Build Coastguard Worker }
301*d83cc019SAndroid Build Coastguard Worker 
background_fs(void * path)302*d83cc019SAndroid Build Coastguard Worker static void *background_fs(void *path)
303*d83cc019SAndroid Build Coastguard Worker {
304*d83cc019SAndroid Build Coastguard Worker 	while (1)
305*d83cc019SAndroid Build Coastguard Worker 		nftw(path, print_entry, 20, FTW_PHYS | FTW_MOUNT);
306*d83cc019SAndroid Build Coastguard Worker 	return NULL;
307*d83cc019SAndroid Build Coastguard Worker }
308*d83cc019SAndroid Build Coastguard Worker 
calibrate_nop(unsigned int target_us,unsigned int tolerance_pct)309*d83cc019SAndroid Build Coastguard Worker static unsigned long calibrate_nop(unsigned int target_us,
310*d83cc019SAndroid Build Coastguard Worker 				   unsigned int tolerance_pct)
311*d83cc019SAndroid Build Coastguard Worker {
312*d83cc019SAndroid Build Coastguard Worker 	const uint32_t bbe = MI_BATCH_BUFFER_END;
313*d83cc019SAndroid Build Coastguard Worker 	const unsigned int loops = 100;
314*d83cc019SAndroid Build Coastguard Worker 	struct drm_i915_gem_exec_object2 obj = {};
315*d83cc019SAndroid Build Coastguard Worker 	struct drm_i915_gem_execbuffer2 eb =
316*d83cc019SAndroid Build Coastguard Worker 		{ .buffer_count = 1, .buffers_ptr = (uintptr_t)&obj};
317*d83cc019SAndroid Build Coastguard Worker 	struct timespec t_0, t_end;
318*d83cc019SAndroid Build Coastguard Worker 	long sz, prev;
319*d83cc019SAndroid Build Coastguard Worker 	int fd;
320*d83cc019SAndroid Build Coastguard Worker 
321*d83cc019SAndroid Build Coastguard Worker 	fd = drm_open_driver(DRIVER_INTEL);
322*d83cc019SAndroid Build Coastguard Worker 
323*d83cc019SAndroid Build Coastguard Worker 	clock_gettime(CLOCK_MONOTONIC, &t_0);
324*d83cc019SAndroid Build Coastguard Worker 
325*d83cc019SAndroid Build Coastguard Worker 	sz = 256 * 1024;
326*d83cc019SAndroid Build Coastguard Worker 	do {
327*d83cc019SAndroid Build Coastguard Worker 		struct timespec t_start;
328*d83cc019SAndroid Build Coastguard Worker 
329*d83cc019SAndroid Build Coastguard Worker 		obj.handle = gem_create(fd, sz + sizeof(bbe));
330*d83cc019SAndroid Build Coastguard Worker 		gem_write(fd, obj.handle, sz, &bbe, sizeof(bbe));
331*d83cc019SAndroid Build Coastguard Worker 		gem_execbuf(fd, &eb);
332*d83cc019SAndroid Build Coastguard Worker 		gem_sync(fd, obj.handle);
333*d83cc019SAndroid Build Coastguard Worker 
334*d83cc019SAndroid Build Coastguard Worker 		clock_gettime(CLOCK_MONOTONIC, &t_start);
335*d83cc019SAndroid Build Coastguard Worker 		for (int loop = 0; loop < loops; loop++)
336*d83cc019SAndroid Build Coastguard Worker 			gem_execbuf(fd, &eb);
337*d83cc019SAndroid Build Coastguard Worker 		gem_sync(fd, obj.handle);
338*d83cc019SAndroid Build Coastguard Worker 		clock_gettime(CLOCK_MONOTONIC, &t_end);
339*d83cc019SAndroid Build Coastguard Worker 
340*d83cc019SAndroid Build Coastguard Worker 		gem_close(fd, obj.handle);
341*d83cc019SAndroid Build Coastguard Worker 
342*d83cc019SAndroid Build Coastguard Worker 		prev = sz;
343*d83cc019SAndroid Build Coastguard Worker 		sz = loops * sz / elapsed(&t_start, &t_end) * 1e3 * target_us;
344*d83cc019SAndroid Build Coastguard Worker 		sz = ALIGN(sz, sizeof(uint32_t));
345*d83cc019SAndroid Build Coastguard Worker 	} while (elapsed(&t_0, &t_end) < 5 ||
346*d83cc019SAndroid Build Coastguard Worker 		 abs(sz - prev) > (sz * tolerance_pct / 100));
347*d83cc019SAndroid Build Coastguard Worker 
348*d83cc019SAndroid Build Coastguard Worker 	close(fd);
349*d83cc019SAndroid Build Coastguard Worker 
350*d83cc019SAndroid Build Coastguard Worker 	return sz;
351*d83cc019SAndroid Build Coastguard Worker }
352*d83cc019SAndroid Build Coastguard Worker 
main(int argc,char ** argv)353*d83cc019SAndroid Build Coastguard Worker int main(int argc, char **argv)
354*d83cc019SAndroid Build Coastguard Worker {
355*d83cc019SAndroid Build Coastguard Worker 	struct gem_busyspin *busy;
356*d83cc019SAndroid Build Coastguard Worker 	struct sys_wait *wait;
357*d83cc019SAndroid Build Coastguard Worker 	void *sys_fn = sys_wait;
358*d83cc019SAndroid Build Coastguard Worker 	pthread_attr_t attr;
359*d83cc019SAndroid Build Coastguard Worker 	pthread_t bg_fs = 0;
360*d83cc019SAndroid Build Coastguard Worker 	int ncpus = sysconf(_SC_NPROCESSORS_ONLN);
361*d83cc019SAndroid Build Coastguard Worker 	igt_stats_t cycles, mean, max;
362*d83cc019SAndroid Build Coastguard Worker 	double min;
363*d83cc019SAndroid Build Coastguard Worker 	int time = 10;
364*d83cc019SAndroid Build Coastguard Worker 	int field = -1;
365*d83cc019SAndroid Build Coastguard Worker 	int enable_gem_sysbusy = 1;
366*d83cc019SAndroid Build Coastguard Worker 	bool leak = false;
367*d83cc019SAndroid Build Coastguard Worker 	bool interrupts = false;
368*d83cc019SAndroid Build Coastguard Worker 	long batch = 0;
369*d83cc019SAndroid Build Coastguard Worker 	int n, c;
370*d83cc019SAndroid Build Coastguard Worker 
371*d83cc019SAndroid Build Coastguard Worker 	while ((c = getopt(argc, argv, "r:t:f:bmni1")) != -1) {
372*d83cc019SAndroid Build Coastguard Worker 		switch (c) {
373*d83cc019SAndroid Build Coastguard Worker 		case '1':
374*d83cc019SAndroid Build Coastguard Worker 			ncpus = 1;
375*d83cc019SAndroid Build Coastguard Worker 			break;
376*d83cc019SAndroid Build Coastguard Worker 		case 'n': /* dry run, measure baseline system latency */
377*d83cc019SAndroid Build Coastguard Worker 			enable_gem_sysbusy = 0;
378*d83cc019SAndroid Build Coastguard Worker 			break;
379*d83cc019SAndroid Build Coastguard Worker 		case 'i': /* interrupts ahoy! */
380*d83cc019SAndroid Build Coastguard Worker 			interrupts = true;
381*d83cc019SAndroid Build Coastguard Worker 			break;
382*d83cc019SAndroid Build Coastguard Worker 		case 't':
383*d83cc019SAndroid Build Coastguard Worker 			/* How long to run the benchmark for (seconds) */
384*d83cc019SAndroid Build Coastguard Worker 			time = atoi(optarg);
385*d83cc019SAndroid Build Coastguard Worker 			if (time < 0)
386*d83cc019SAndroid Build Coastguard Worker 				time = INT_MAX;
387*d83cc019SAndroid Build Coastguard Worker 			break;
388*d83cc019SAndroid Build Coastguard Worker 		case 'r':
389*d83cc019SAndroid Build Coastguard Worker 			/* Duration of each batch (microseconds) */
390*d83cc019SAndroid Build Coastguard Worker 			batch = atoi(optarg);
391*d83cc019SAndroid Build Coastguard Worker 			break;
392*d83cc019SAndroid Build Coastguard Worker 		case 'f':
393*d83cc019SAndroid Build Coastguard Worker 			/* Select an output field */
394*d83cc019SAndroid Build Coastguard Worker 			field = atoi(optarg);
395*d83cc019SAndroid Build Coastguard Worker 			break;
396*d83cc019SAndroid Build Coastguard Worker 		case 'b':
397*d83cc019SAndroid Build Coastguard Worker 			pthread_create(&bg_fs, NULL,
398*d83cc019SAndroid Build Coastguard Worker 				       background_fs, (void *)"/");
399*d83cc019SAndroid Build Coastguard Worker 			sleep(5);
400*d83cc019SAndroid Build Coastguard Worker 			break;
401*d83cc019SAndroid Build Coastguard Worker 		case 'm':
402*d83cc019SAndroid Build Coastguard Worker 			sys_fn = sys_thp_alloc;
403*d83cc019SAndroid Build Coastguard Worker 			leak = true;
404*d83cc019SAndroid Build Coastguard Worker 			break;
405*d83cc019SAndroid Build Coastguard Worker 		default:
406*d83cc019SAndroid Build Coastguard Worker 			break;
407*d83cc019SAndroid Build Coastguard Worker 		}
408*d83cc019SAndroid Build Coastguard Worker 	}
409*d83cc019SAndroid Build Coastguard Worker 
410*d83cc019SAndroid Build Coastguard Worker 	/* Prevent CPU sleeps so that busy and idle loads are consistent. */
411*d83cc019SAndroid Build Coastguard Worker 	force_low_latency();
412*d83cc019SAndroid Build Coastguard Worker 	min = min_measurement_error();
413*d83cc019SAndroid Build Coastguard Worker 
414*d83cc019SAndroid Build Coastguard Worker 	if (batch > 0)
415*d83cc019SAndroid Build Coastguard Worker 		batch = calibrate_nop(batch, 2);
416*d83cc019SAndroid Build Coastguard Worker 	else
417*d83cc019SAndroid Build Coastguard Worker 		batch = -batch;
418*d83cc019SAndroid Build Coastguard Worker 
419*d83cc019SAndroid Build Coastguard Worker 	busy = calloc(ncpus, sizeof(*busy));
420*d83cc019SAndroid Build Coastguard Worker 	pthread_attr_init(&attr);
421*d83cc019SAndroid Build Coastguard Worker 	if (enable_gem_sysbusy) {
422*d83cc019SAndroid Build Coastguard Worker 		for (n = 0; n < ncpus; n++) {
423*d83cc019SAndroid Build Coastguard Worker 			bind_cpu(&attr, n);
424*d83cc019SAndroid Build Coastguard Worker 			busy[n].sz = batch;
425*d83cc019SAndroid Build Coastguard Worker 			busy[n].leak = leak;
426*d83cc019SAndroid Build Coastguard Worker 			busy[n].interrupts = interrupts;
427*d83cc019SAndroid Build Coastguard Worker 			pthread_create(&busy[n].thread, &attr,
428*d83cc019SAndroid Build Coastguard Worker 				       gem_busyspin, &busy[n]);
429*d83cc019SAndroid Build Coastguard Worker 		}
430*d83cc019SAndroid Build Coastguard Worker 	}
431*d83cc019SAndroid Build Coastguard Worker 
432*d83cc019SAndroid Build Coastguard Worker 	wait = calloc(ncpus, sizeof(*wait));
433*d83cc019SAndroid Build Coastguard Worker 	pthread_attr_init(&attr);
434*d83cc019SAndroid Build Coastguard Worker 	rtprio(&attr, 99);
435*d83cc019SAndroid Build Coastguard Worker 	for (n = 0; n < ncpus; n++) {
436*d83cc019SAndroid Build Coastguard Worker 		igt_mean_init(&wait[n].mean);
437*d83cc019SAndroid Build Coastguard Worker 		bind_cpu(&attr, n);
438*d83cc019SAndroid Build Coastguard Worker 		pthread_create(&wait[n].thread, &attr, sys_fn, &wait[n]);
439*d83cc019SAndroid Build Coastguard Worker 	}
440*d83cc019SAndroid Build Coastguard Worker 
441*d83cc019SAndroid Build Coastguard Worker 	sleep(time);
442*d83cc019SAndroid Build Coastguard Worker 	done = 1;
443*d83cc019SAndroid Build Coastguard Worker 
444*d83cc019SAndroid Build Coastguard Worker 	igt_stats_init_with_size(&cycles, ncpus);
445*d83cc019SAndroid Build Coastguard Worker 	if (enable_gem_sysbusy) {
446*d83cc019SAndroid Build Coastguard Worker 		for (n = 0; n < ncpus; n++) {
447*d83cc019SAndroid Build Coastguard Worker 			pthread_join(busy[n].thread, NULL);
448*d83cc019SAndroid Build Coastguard Worker 			igt_stats_push(&cycles, busy[n].count);
449*d83cc019SAndroid Build Coastguard Worker 		}
450*d83cc019SAndroid Build Coastguard Worker 	}
451*d83cc019SAndroid Build Coastguard Worker 
452*d83cc019SAndroid Build Coastguard Worker 	igt_stats_init_with_size(&mean, ncpus);
453*d83cc019SAndroid Build Coastguard Worker 	igt_stats_init_with_size(&max, ncpus);
454*d83cc019SAndroid Build Coastguard Worker 	for (n = 0; n < ncpus; n++) {
455*d83cc019SAndroid Build Coastguard Worker 		pthread_join(wait[n].thread, NULL);
456*d83cc019SAndroid Build Coastguard Worker 		igt_stats_push_float(&mean, wait[n].mean.mean);
457*d83cc019SAndroid Build Coastguard Worker 		igt_stats_push_float(&max, wait[n].mean.max);
458*d83cc019SAndroid Build Coastguard Worker 	}
459*d83cc019SAndroid Build Coastguard Worker 	if (bg_fs) {
460*d83cc019SAndroid Build Coastguard Worker 		pthread_cancel(bg_fs);
461*d83cc019SAndroid Build Coastguard Worker 		pthread_join(bg_fs, NULL);
462*d83cc019SAndroid Build Coastguard Worker 	}
463*d83cc019SAndroid Build Coastguard Worker 
464*d83cc019SAndroid Build Coastguard Worker 	switch (field) {
465*d83cc019SAndroid Build Coastguard Worker 	default:
466*d83cc019SAndroid Build Coastguard Worker 		printf("gem_syslatency: cycles=%.0f, latency mean=%.3fus max=%.0fus\n",
467*d83cc019SAndroid Build Coastguard Worker 		       igt_stats_get_mean(&cycles),
468*d83cc019SAndroid Build Coastguard Worker 		       (igt_stats_get_mean(&mean) - min)/ 1000,
469*d83cc019SAndroid Build Coastguard Worker 		       (l_estimate(&max) - min) / 1000);
470*d83cc019SAndroid Build Coastguard Worker 		break;
471*d83cc019SAndroid Build Coastguard Worker 	case 0:
472*d83cc019SAndroid Build Coastguard Worker 		printf("%.0f\n", igt_stats_get_mean(&cycles));
473*d83cc019SAndroid Build Coastguard Worker 		break;
474*d83cc019SAndroid Build Coastguard Worker 	case 1:
475*d83cc019SAndroid Build Coastguard Worker 		printf("%.3f\n", (igt_stats_get_mean(&mean) - min) / 1000);
476*d83cc019SAndroid Build Coastguard Worker 		break;
477*d83cc019SAndroid Build Coastguard Worker 	case 2:
478*d83cc019SAndroid Build Coastguard Worker 		printf("%.0f\n", (l_estimate(&max) - min) / 1000);
479*d83cc019SAndroid Build Coastguard Worker 		break;
480*d83cc019SAndroid Build Coastguard Worker 	}
481*d83cc019SAndroid Build Coastguard Worker 
482*d83cc019SAndroid Build Coastguard Worker 	return 0;
483*d83cc019SAndroid Build Coastguard Worker 
484*d83cc019SAndroid Build Coastguard Worker }
485