xref: /dragonfly/test/interbench/interbench.c (revision 86d7f5d3)
1*86d7f5d3SJohn Marino /*******************************************
2*86d7f5d3SJohn Marino  *
3*86d7f5d3SJohn Marino  * Interbench - Interactivity benchmark
4*86d7f5d3SJohn Marino  *
5*86d7f5d3SJohn Marino  * Author:  Con Kolivas <kernel@kolivas.org>
6*86d7f5d3SJohn Marino  *
7*86d7f5d3SJohn Marino  * This program is free software; you can redistribute it and/or modify
8*86d7f5d3SJohn Marino  * it under the terms of the GNU General Public License as published by
9*86d7f5d3SJohn Marino  * the Free Software Foundation; either version 2 of the License, or
10*86d7f5d3SJohn Marino  * (at your option) any later version.
11*86d7f5d3SJohn Marino  *
12*86d7f5d3SJohn Marino  * This program is distributed in the hope that it will be useful,
13*86d7f5d3SJohn Marino  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*86d7f5d3SJohn Marino  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*86d7f5d3SJohn Marino  * GNU General Public License for more details.
16*86d7f5d3SJohn Marino  *
17*86d7f5d3SJohn Marino  * You should have received a copy of the GNU General Public License
18*86d7f5d3SJohn Marino  * along with this program; if not, write to the Free Software
19*86d7f5d3SJohn Marino  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*86d7f5d3SJohn Marino  *
21*86d7f5d3SJohn Marino  *******************************************/
22*86d7f5d3SJohn Marino 
23*86d7f5d3SJohn Marino #define _GNU_SOURCE
24*86d7f5d3SJohn Marino #define _FILE_OFFSET_BITS 64	/* Large file support */
25*86d7f5d3SJohn Marino #define INTERBENCH_VERSION	"0.30"
26*86d7f5d3SJohn Marino 
27*86d7f5d3SJohn Marino #include <stdio.h>
28*86d7f5d3SJohn Marino #include <stdlib.h>
29*86d7f5d3SJohn Marino #include <stdarg.h>
30*86d7f5d3SJohn Marino #include <strings.h>
31*86d7f5d3SJohn Marino #include <string.h>
32*86d7f5d3SJohn Marino #include <unistd.h>
33*86d7f5d3SJohn Marino #include <fcntl.h>
34*86d7f5d3SJohn Marino #include <sched.h>
35*86d7f5d3SJohn Marino #include <time.h>
36*86d7f5d3SJohn Marino #include <errno.h>
37*86d7f5d3SJohn Marino #include <semaphore.h>
38*86d7f5d3SJohn Marino #include <pthread.h>
39*86d7f5d3SJohn Marino #include <math.h>
40*86d7f5d3SJohn Marino #include <fenv.h>
41*86d7f5d3SJohn Marino #include <signal.h>
42*86d7f5d3SJohn Marino #include <sys/utsname.h>
43*86d7f5d3SJohn Marino #include <sys/time.h>
44*86d7f5d3SJohn Marino #include <sys/resource.h>
45*86d7f5d3SJohn Marino #include <sys/types.h>
46*86d7f5d3SJohn Marino #include <sys/mman.h>
47*86d7f5d3SJohn Marino #include <sys/wait.h>
48*86d7f5d3SJohn Marino #include <sys/stat.h>
49*86d7f5d3SJohn Marino #include <sys/sysctl.h>
50*86d7f5d3SJohn Marino #include <sys/vmmeter.h>
51*86d7f5d3SJohn Marino #include "interbench.h"
52*86d7f5d3SJohn Marino 
53*86d7f5d3SJohn Marino #define MAX_UNAME_LENGTH	100
54*86d7f5d3SJohn Marino #define MAX_LOG_LENGTH		((MAX_UNAME_LENGTH) + 4)
55*86d7f5d3SJohn Marino #define MIN_BLK_SIZE		1024
56*86d7f5d3SJohn Marino #define DEFAULT_RESERVE		64
57*86d7f5d3SJohn Marino #define MB			(1024 * 1024)	/* 2^20 bytes */
58*86d7f5d3SJohn Marino #define KB			1024
59*86d7f5d3SJohn Marino #define MAX_MEM_IN_MB		(1024 * 64)	/* 64 GB */
60*86d7f5d3SJohn Marino 
61*86d7f5d3SJohn Marino struct user_data {
62*86d7f5d3SJohn Marino 	unsigned long loops_per_ms;
63*86d7f5d3SJohn Marino 	unsigned long ram, swap;
64*86d7f5d3SJohn Marino 	int duration;
65*86d7f5d3SJohn Marino 	int do_rt;
66*86d7f5d3SJohn Marino 	int bench_nice;
67*86d7f5d3SJohn Marino 	int load_nice;
68*86d7f5d3SJohn Marino 	unsigned long custom_run;
69*86d7f5d3SJohn Marino 	unsigned long custom_interval;
70*86d7f5d3SJohn Marino 	unsigned long cpu_load;
71*86d7f5d3SJohn Marino 	char logfilename[MAX_LOG_LENGTH];
72*86d7f5d3SJohn Marino 	int log;
73*86d7f5d3SJohn Marino 	char unamer[MAX_UNAME_LENGTH];
74*86d7f5d3SJohn Marino 	char datestamp[13];
75*86d7f5d3SJohn Marino 	FILE *logfile;
76*86d7f5d3SJohn Marino } ud = {
77*86d7f5d3SJohn Marino 	.duration = 30,
78*86d7f5d3SJohn Marino 	.cpu_load = 4,
79*86d7f5d3SJohn Marino 	.log = 1,
80*86d7f5d3SJohn Marino };
81*86d7f5d3SJohn Marino 
82*86d7f5d3SJohn Marino /* Pipes main to/from load and bench processes */
83*86d7f5d3SJohn Marino static int m2l[2], l2m[2], m2b[2], b2m[2];
84*86d7f5d3SJohn Marino 
85*86d7f5d3SJohn Marino /* Which member of becnhmarks is used when not benchmarking */
86*86d7f5d3SJohn Marino #define NOT_BENCHING	(THREADS)
87*86d7f5d3SJohn Marino #define CUSTOM		(THREADS - 1)
88*86d7f5d3SJohn Marino 
89*86d7f5d3SJohn Marino /*
90*86d7f5d3SJohn Marino  * To add another load or a benchmark you need to increment the value of
91*86d7f5d3SJohn Marino  * THREADS, add a function prototype for your function and add an entry to
92*86d7f5d3SJohn Marino  * the threadlist. To specify whether the function is a benchmark or a load
93*86d7f5d3SJohn Marino  * set the benchmark and/or load flag as appropriate. The basic requirements
94*86d7f5d3SJohn Marino  * of a new load can be seen by using emulate_none as a template.
95*86d7f5d3SJohn Marino  */
96*86d7f5d3SJohn Marino 
97*86d7f5d3SJohn Marino void emulate_none(struct thread *th);
98*86d7f5d3SJohn Marino void emulate_audio(struct thread *th);
99*86d7f5d3SJohn Marino void emulate_video(struct thread *th);
100*86d7f5d3SJohn Marino void emulate_x(struct thread *th);
101*86d7f5d3SJohn Marino void emulate_game(struct thread *th);
102*86d7f5d3SJohn Marino void emulate_burn(struct thread *th);
103*86d7f5d3SJohn Marino void emulate_write(struct thread *th);
104*86d7f5d3SJohn Marino void emulate_read(struct thread *th);
105*86d7f5d3SJohn Marino void emulate_ring(struct thread *th);
106*86d7f5d3SJohn Marino void emulate_compile(struct thread *th);
107*86d7f5d3SJohn Marino void emulate_memload(struct thread *th);
108*86d7f5d3SJohn Marino void emulate_hackbench(struct thread *th);
109*86d7f5d3SJohn Marino void emulate_custom(struct thread *th);
110*86d7f5d3SJohn Marino 
111*86d7f5d3SJohn Marino struct thread threadlist[THREADS] = {
112*86d7f5d3SJohn Marino 	{.label = "None", .name = emulate_none, .load = 1, .rtload = 1},
113*86d7f5d3SJohn Marino 	{.label = "Audio", .name = emulate_audio, .bench = 1, .rtbench = 1},
114*86d7f5d3SJohn Marino 	{.label = "Video", .name = emulate_video, .bench = 1, .rtbench = 1, .load = 1, .rtload = 1},
115*86d7f5d3SJohn Marino 	{.label = "X", .name = emulate_x, .bench = 1, .load = 1, .rtload = 1},
116*86d7f5d3SJohn Marino 	{.label = "Gaming", .name = emulate_game, .nodeadlines = 1, .bench = 1},
117*86d7f5d3SJohn Marino 	{.label = "Burn", .name = emulate_burn, .load = 1, .rtload = 1},
118*86d7f5d3SJohn Marino 	{.label = "Write", .name = emulate_write, .load = 1, .rtload = 1},
119*86d7f5d3SJohn Marino 	{.label = "Read", .name = emulate_read, .load = 1, .rtload = 1},
120*86d7f5d3SJohn Marino 	{.label = "Ring", .name = emulate_ring, .load = 0, .rtload = 0},	/* No useful data from this */
121*86d7f5d3SJohn Marino 	{.label = "Compile", .name = emulate_compile, .load = 1, .rtload = 1},
122*86d7f5d3SJohn Marino 	{.label = "Memload", .name = emulate_memload, .load = 1, .rtload = 1},
123*86d7f5d3SJohn Marino 	{.label = "Hack", .name = emulate_hackbench, .load = 0, .rtload = 0},	/* This is causing signal headaches */
124*86d7f5d3SJohn Marino 	{.label = "Custom", .name = emulate_custom},	/* Leave custom as last entry */
125*86d7f5d3SJohn Marino };
126*86d7f5d3SJohn Marino 
127*86d7f5d3SJohn Marino void init_sem(sem_t *sem);
128*86d7f5d3SJohn Marino void init_all_sems(struct sems *s);
129*86d7f5d3SJohn Marino void initialise_thread(int i);
130*86d7f5d3SJohn Marino void start_thread(struct thread *th);
131*86d7f5d3SJohn Marino void stop_thread(struct thread *th);
132*86d7f5d3SJohn Marino 
terminal_error(const char * name)133*86d7f5d3SJohn Marino void terminal_error(const char *name)
134*86d7f5d3SJohn Marino {
135*86d7f5d3SJohn Marino 	fprintf(stderr, "\n");
136*86d7f5d3SJohn Marino 	perror(name);
137*86d7f5d3SJohn Marino 	exit (1);
138*86d7f5d3SJohn Marino }
139*86d7f5d3SJohn Marino 
terminal_fileopen_error(FILE * fp,char * name)140*86d7f5d3SJohn Marino void terminal_fileopen_error(FILE *fp, char *name)
141*86d7f5d3SJohn Marino {
142*86d7f5d3SJohn Marino 	if (fclose(fp) == -1)
143*86d7f5d3SJohn Marino 		terminal_error("fclose");
144*86d7f5d3SJohn Marino 	terminal_error(name);
145*86d7f5d3SJohn Marino }
146*86d7f5d3SJohn Marino 
get_nsecs(struct timespec * myts)147*86d7f5d3SJohn Marino unsigned long long get_nsecs(struct timespec *myts)
148*86d7f5d3SJohn Marino {
149*86d7f5d3SJohn Marino 	if (clock_gettime(CLOCK_REALTIME, myts))
150*86d7f5d3SJohn Marino 		terminal_error("clock_gettime");
151*86d7f5d3SJohn Marino 	return (myts->tv_sec * 1000000000 + myts->tv_nsec );
152*86d7f5d3SJohn Marino }
153*86d7f5d3SJohn Marino 
get_usecs(struct timespec * myts)154*86d7f5d3SJohn Marino unsigned long get_usecs(struct timespec *myts)
155*86d7f5d3SJohn Marino {
156*86d7f5d3SJohn Marino 	if (clock_gettime(CLOCK_REALTIME, myts))
157*86d7f5d3SJohn Marino 		terminal_error("clock_gettime");
158*86d7f5d3SJohn Marino 	return (myts->tv_sec * 1000000 + myts->tv_nsec / 1000 );
159*86d7f5d3SJohn Marino }
160*86d7f5d3SJohn Marino 
set_fifo(int prio)161*86d7f5d3SJohn Marino void set_fifo(int prio)
162*86d7f5d3SJohn Marino {
163*86d7f5d3SJohn Marino 	struct sched_param sp;
164*86d7f5d3SJohn Marino 
165*86d7f5d3SJohn Marino 	memset(&sp, 0, sizeof(sp));
166*86d7f5d3SJohn Marino 	sp.sched_priority = prio;
167*86d7f5d3SJohn Marino 	if (sched_setscheduler(0, SCHED_FIFO, &sp) == -1) {
168*86d7f5d3SJohn Marino 		if (errno != EPERM)
169*86d7f5d3SJohn Marino 			terminal_error("sched_setscheduler");
170*86d7f5d3SJohn Marino 	}
171*86d7f5d3SJohn Marino }
172*86d7f5d3SJohn Marino 
set_mlock(void)173*86d7f5d3SJohn Marino void set_mlock(void)
174*86d7f5d3SJohn Marino {
175*86d7f5d3SJohn Marino 	int mlockflags;
176*86d7f5d3SJohn Marino 
177*86d7f5d3SJohn Marino 	mlockflags = MCL_CURRENT | MCL_FUTURE;
178*86d7f5d3SJohn Marino #if 0
179*86d7f5d3SJohn Marino 	mlockall(mlockflags);	/* Is not critical if this fails */
180*86d7f5d3SJohn Marino #endif
181*86d7f5d3SJohn Marino }
182*86d7f5d3SJohn Marino 
set_munlock(void)183*86d7f5d3SJohn Marino void set_munlock(void)
184*86d7f5d3SJohn Marino {
185*86d7f5d3SJohn Marino #if 0
186*86d7f5d3SJohn Marino 	if (munlockall() == -1)
187*86d7f5d3SJohn Marino 		terminal_error("munlockall");
188*86d7f5d3SJohn Marino #endif
189*86d7f5d3SJohn Marino }
190*86d7f5d3SJohn Marino 
set_thread_fifo(pthread_t pthread,int prio)191*86d7f5d3SJohn Marino void set_thread_fifo(pthread_t pthread, int prio)
192*86d7f5d3SJohn Marino {
193*86d7f5d3SJohn Marino 	struct sched_param sp;
194*86d7f5d3SJohn Marino 	memset(&sp, 0, sizeof(sp));
195*86d7f5d3SJohn Marino 	sp.sched_priority = prio;
196*86d7f5d3SJohn Marino 	if (pthread_setschedparam(pthread, SCHED_FIFO, &sp) == -1)
197*86d7f5d3SJohn Marino 		terminal_error("pthread_setschedparam");
198*86d7f5d3SJohn Marino }
199*86d7f5d3SJohn Marino 
set_normal(void)200*86d7f5d3SJohn Marino void set_normal(void)
201*86d7f5d3SJohn Marino {
202*86d7f5d3SJohn Marino 	struct sched_param sp;
203*86d7f5d3SJohn Marino 	memset(&sp, 0, sizeof(sp));
204*86d7f5d3SJohn Marino 	sp.sched_priority = 0;
205*86d7f5d3SJohn Marino 	if (sched_setscheduler(0, SCHED_OTHER, &sp) == -1) {
206*86d7f5d3SJohn Marino 		fprintf(stderr, "Weird, could not unset RT scheduling!\n");
207*86d7f5d3SJohn Marino 	}
208*86d7f5d3SJohn Marino }
209*86d7f5d3SJohn Marino 
set_nice(int prio)210*86d7f5d3SJohn Marino void set_nice(int prio)
211*86d7f5d3SJohn Marino {
212*86d7f5d3SJohn Marino 	if (setpriority(PRIO_PROCESS, 0, prio) == -1)
213*86d7f5d3SJohn Marino 		terminal_error("setpriority");
214*86d7f5d3SJohn Marino }
215*86d7f5d3SJohn Marino 
test_fifo(void)216*86d7f5d3SJohn Marino int test_fifo(void)
217*86d7f5d3SJohn Marino {
218*86d7f5d3SJohn Marino 	struct sched_param sp;
219*86d7f5d3SJohn Marino 	memset(&sp, 0, sizeof(sp));
220*86d7f5d3SJohn Marino 	sp.sched_priority = 99;
221*86d7f5d3SJohn Marino 	if (sched_setscheduler(0, SCHED_FIFO, &sp) == -1) {
222*86d7f5d3SJohn Marino 		if (errno != EPERM)
223*86d7f5d3SJohn Marino 			terminal_error("sched_setscheduler");
224*86d7f5d3SJohn Marino 		goto out_fail;
225*86d7f5d3SJohn Marino 	}
226*86d7f5d3SJohn Marino 	if (sched_getscheduler(0) != SCHED_FIFO)
227*86d7f5d3SJohn Marino 		goto out_fail;
228*86d7f5d3SJohn Marino 	set_normal();
229*86d7f5d3SJohn Marino 	return 1;
230*86d7f5d3SJohn Marino out_fail:
231*86d7f5d3SJohn Marino 	set_normal();
232*86d7f5d3SJohn Marino 	return 0;
233*86d7f5d3SJohn Marino }
234*86d7f5d3SJohn Marino 
set_thread_normal(pthread_t pthread)235*86d7f5d3SJohn Marino void set_thread_normal(pthread_t pthread)
236*86d7f5d3SJohn Marino {
237*86d7f5d3SJohn Marino 	struct sched_param sp;
238*86d7f5d3SJohn Marino 	memset(&sp, 0, sizeof(sp));
239*86d7f5d3SJohn Marino 	sp.sched_priority = 0;
240*86d7f5d3SJohn Marino 	if (pthread_setschedparam(pthread, SCHED_OTHER, &sp) == -1)
241*86d7f5d3SJohn Marino 		terminal_error("pthread_setschedparam");
242*86d7f5d3SJohn Marino }
243*86d7f5d3SJohn Marino 
sync_flush(void)244*86d7f5d3SJohn Marino void sync_flush(void)
245*86d7f5d3SJohn Marino {
246*86d7f5d3SJohn Marino 	if ((fflush(NULL)) == EOF)
247*86d7f5d3SJohn Marino 		terminal_error("fflush");
248*86d7f5d3SJohn Marino 	sync();
249*86d7f5d3SJohn Marino 	sync();
250*86d7f5d3SJohn Marino 	sync();
251*86d7f5d3SJohn Marino }
252*86d7f5d3SJohn Marino 
compute_allocable_mem(void)253*86d7f5d3SJohn Marino unsigned long compute_allocable_mem(void)
254*86d7f5d3SJohn Marino {
255*86d7f5d3SJohn Marino 	unsigned long total = ud.ram + ud.swap;
256*86d7f5d3SJohn Marino 	unsigned long usage = ud.ram * 110 / 100 ;
257*86d7f5d3SJohn Marino 
258*86d7f5d3SJohn Marino 	/* Leave at least DEFAULT_RESERVE free space and check for maths overflow. */
259*86d7f5d3SJohn Marino 	if (total - DEFAULT_RESERVE < usage)
260*86d7f5d3SJohn Marino 		usage = total - DEFAULT_RESERVE;
261*86d7f5d3SJohn Marino 	usage /= 1024;	/* to megabytes */
262*86d7f5d3SJohn Marino 	if (usage > 2930)
263*86d7f5d3SJohn Marino 		usage = 2930;
264*86d7f5d3SJohn Marino 	return usage;
265*86d7f5d3SJohn Marino }
266*86d7f5d3SJohn Marino 
burn_loops(unsigned long loops)267*86d7f5d3SJohn Marino void burn_loops(unsigned long loops)
268*86d7f5d3SJohn Marino {
269*86d7f5d3SJohn Marino 	unsigned long i;
270*86d7f5d3SJohn Marino 
271*86d7f5d3SJohn Marino 	/*
272*86d7f5d3SJohn Marino 	 * We need some magic here to prevent the compiler from optimising
273*86d7f5d3SJohn Marino 	 * this loop away. Otherwise trying to emulate a fixed cpu load
274*86d7f5d3SJohn Marino 	 * with this loop will not work.
275*86d7f5d3SJohn Marino 	 */
276*86d7f5d3SJohn Marino 	for (i = 0 ; i < loops ; i++)
277*86d7f5d3SJohn Marino 	     asm volatile("" : : : "memory");
278*86d7f5d3SJohn Marino }
279*86d7f5d3SJohn Marino 
280*86d7f5d3SJohn Marino /* Use this many usecs of cpu time */
burn_usecs(unsigned long usecs)281*86d7f5d3SJohn Marino void burn_usecs(unsigned long usecs)
282*86d7f5d3SJohn Marino {
283*86d7f5d3SJohn Marino 	unsigned long ms_loops;
284*86d7f5d3SJohn Marino 
285*86d7f5d3SJohn Marino 	ms_loops = ud.loops_per_ms / 1000 * usecs;
286*86d7f5d3SJohn Marino 	burn_loops(ms_loops);
287*86d7f5d3SJohn Marino }
288*86d7f5d3SJohn Marino 
microsleep(unsigned long long usecs)289*86d7f5d3SJohn Marino void microsleep(unsigned long long usecs)
290*86d7f5d3SJohn Marino {
291*86d7f5d3SJohn Marino 	struct timespec req, rem;
292*86d7f5d3SJohn Marino 
293*86d7f5d3SJohn Marino 	rem.tv_sec = rem.tv_nsec = 0;
294*86d7f5d3SJohn Marino 
295*86d7f5d3SJohn Marino 	req.tv_sec = usecs / 1000000;
296*86d7f5d3SJohn Marino 	req.tv_nsec = (usecs - (req.tv_sec * 1000000)) * 1000;
297*86d7f5d3SJohn Marino continue_sleep:
298*86d7f5d3SJohn Marino 	if ((nanosleep(&req, &rem)) == -1) {
299*86d7f5d3SJohn Marino 		if (errno == EINTR) {
300*86d7f5d3SJohn Marino 			if (rem.tv_sec || rem.tv_nsec) {
301*86d7f5d3SJohn Marino 				req.tv_sec = rem.tv_sec;
302*86d7f5d3SJohn Marino 				req.tv_nsec = rem.tv_nsec;
303*86d7f5d3SJohn Marino 				goto continue_sleep;
304*86d7f5d3SJohn Marino 			}
305*86d7f5d3SJohn Marino 			goto out;
306*86d7f5d3SJohn Marino 		}
307*86d7f5d3SJohn Marino 		terminal_error("nanosleep");
308*86d7f5d3SJohn Marino 	}
309*86d7f5d3SJohn Marino out:
310*86d7f5d3SJohn Marino 	return;
311*86d7f5d3SJohn Marino }
312*86d7f5d3SJohn Marino 
313*86d7f5d3SJohn Marino /*
314*86d7f5d3SJohn Marino  * Yes, sem_post and sem_wait shouldn't return -1 but they do so we must
315*86d7f5d3SJohn Marino  * handle it.
316*86d7f5d3SJohn Marino  */
post_sem(sem_t * s)317*86d7f5d3SJohn Marino inline void post_sem(sem_t *s)
318*86d7f5d3SJohn Marino {
319*86d7f5d3SJohn Marino retry:
320*86d7f5d3SJohn Marino 	if ((sem_post(s)) == -1) {
321*86d7f5d3SJohn Marino 		if (errno == EINTR)
322*86d7f5d3SJohn Marino 			goto retry;
323*86d7f5d3SJohn Marino 		terminal_error("sem_post");
324*86d7f5d3SJohn Marino 	}
325*86d7f5d3SJohn Marino }
326*86d7f5d3SJohn Marino 
wait_sem(sem_t * s)327*86d7f5d3SJohn Marino inline void wait_sem(sem_t *s)
328*86d7f5d3SJohn Marino {
329*86d7f5d3SJohn Marino retry:
330*86d7f5d3SJohn Marino 	if ((sem_wait(s)) == -1) {
331*86d7f5d3SJohn Marino 		if (errno == EINTR)
332*86d7f5d3SJohn Marino 			goto retry;
333*86d7f5d3SJohn Marino 		terminal_error("sem_wait");
334*86d7f5d3SJohn Marino 	}
335*86d7f5d3SJohn Marino }
336*86d7f5d3SJohn Marino 
trywait_sem(sem_t * s)337*86d7f5d3SJohn Marino inline int trywait_sem(sem_t *s)
338*86d7f5d3SJohn Marino {
339*86d7f5d3SJohn Marino 	int ret;
340*86d7f5d3SJohn Marino 
341*86d7f5d3SJohn Marino retry:
342*86d7f5d3SJohn Marino 	if ((ret = sem_trywait(s)) == -1) {
343*86d7f5d3SJohn Marino 		if (errno == EINTR)
344*86d7f5d3SJohn Marino 			goto retry;
345*86d7f5d3SJohn Marino 		if (errno != EAGAIN)
346*86d7f5d3SJohn Marino 			terminal_error("sem_trywait");
347*86d7f5d3SJohn Marino 	}
348*86d7f5d3SJohn Marino 	return ret;
349*86d7f5d3SJohn Marino }
350*86d7f5d3SJohn Marino 
Read(int fd,void * buf,size_t count)351*86d7f5d3SJohn Marino inline ssize_t Read(int fd, void *buf, size_t count)
352*86d7f5d3SJohn Marino {
353*86d7f5d3SJohn Marino 	ssize_t retval;
354*86d7f5d3SJohn Marino 
355*86d7f5d3SJohn Marino retry:
356*86d7f5d3SJohn Marino 	retval = read(fd, buf, count);
357*86d7f5d3SJohn Marino 	if (retval == -1) {
358*86d7f5d3SJohn Marino 		if (errno == EINTR)
359*86d7f5d3SJohn Marino 			goto retry;
360*86d7f5d3SJohn Marino 		terminal_error("read");
361*86d7f5d3SJohn Marino 	}
362*86d7f5d3SJohn Marino 	return retval;
363*86d7f5d3SJohn Marino }
364*86d7f5d3SJohn Marino 
Write(int fd,const void * buf,size_t count)365*86d7f5d3SJohn Marino inline ssize_t Write(int fd, const void *buf, size_t count)
366*86d7f5d3SJohn Marino {
367*86d7f5d3SJohn Marino 	ssize_t retval;
368*86d7f5d3SJohn Marino 
369*86d7f5d3SJohn Marino retry:
370*86d7f5d3SJohn Marino 	retval = write(fd, &buf, count);
371*86d7f5d3SJohn Marino 	if (retval == -1) {
372*86d7f5d3SJohn Marino 		if (errno == EINTR)
373*86d7f5d3SJohn Marino 			goto retry;
374*86d7f5d3SJohn Marino 		terminal_error("write");
375*86d7f5d3SJohn Marino 	}
376*86d7f5d3SJohn Marino 	return retval;
377*86d7f5d3SJohn Marino }
378*86d7f5d3SJohn Marino 
periodic_schedule(struct thread * th,unsigned long run_usecs,unsigned long interval_usecs,unsigned long long deadline)379*86d7f5d3SJohn Marino unsigned long periodic_schedule(struct thread *th, unsigned long run_usecs,
380*86d7f5d3SJohn Marino 	unsigned long interval_usecs, unsigned long long deadline)
381*86d7f5d3SJohn Marino {
382*86d7f5d3SJohn Marino 	unsigned long long latency, missed_latency;
383*86d7f5d3SJohn Marino 	unsigned long long current_time;
384*86d7f5d3SJohn Marino 	struct tk_thread *tk;
385*86d7f5d3SJohn Marino 	struct data_table *tb;
386*86d7f5d3SJohn Marino 	struct timespec myts;
387*86d7f5d3SJohn Marino 
388*86d7f5d3SJohn Marino 	latency = 0;
389*86d7f5d3SJohn Marino 	tb = th->dt;
390*86d7f5d3SJohn Marino 	tk = &th->tkthread;
391*86d7f5d3SJohn Marino 
392*86d7f5d3SJohn Marino 	current_time = get_usecs(&myts);
393*86d7f5d3SJohn Marino 	if (current_time > deadline + tk->slept_interval)
394*86d7f5d3SJohn Marino 		latency = current_time - deadline- tk->slept_interval;
395*86d7f5d3SJohn Marino 
396*86d7f5d3SJohn Marino 	/* calculate the latency for missed frames */
397*86d7f5d3SJohn Marino 	missed_latency = 0;
398*86d7f5d3SJohn Marino 
399*86d7f5d3SJohn Marino 	current_time = get_usecs(&myts);
400*86d7f5d3SJohn Marino 	if (interval_usecs && current_time > deadline + interval_usecs) {
401*86d7f5d3SJohn Marino 		/* We missed the deadline even before we consumed cpu */
402*86d7f5d3SJohn Marino 		unsigned long intervals;
403*86d7f5d3SJohn Marino 
404*86d7f5d3SJohn Marino 		deadline += interval_usecs;
405*86d7f5d3SJohn Marino 		intervals = (current_time - deadline) /
406*86d7f5d3SJohn Marino 			interval_usecs + 1;
407*86d7f5d3SJohn Marino 
408*86d7f5d3SJohn Marino 		tb->missed_deadlines += intervals;
409*86d7f5d3SJohn Marino 		missed_latency = intervals * interval_usecs;
410*86d7f5d3SJohn Marino 		deadline += intervals * interval_usecs;
411*86d7f5d3SJohn Marino 		tb->missed_burns += intervals;
412*86d7f5d3SJohn Marino 		goto bypass_burn;
413*86d7f5d3SJohn Marino 	}
414*86d7f5d3SJohn Marino 
415*86d7f5d3SJohn Marino 	burn_usecs(run_usecs);
416*86d7f5d3SJohn Marino 	current_time = get_usecs(&myts);
417*86d7f5d3SJohn Marino 	tb->achieved_burns++;
418*86d7f5d3SJohn Marino 
419*86d7f5d3SJohn Marino 	/*
420*86d7f5d3SJohn Marino 	 * If we meet the deadline we move the deadline forward, otherwise
421*86d7f5d3SJohn Marino 	 * we consider it a missed deadline and dropped frame etc.
422*86d7f5d3SJohn Marino 	 */
423*86d7f5d3SJohn Marino 	deadline += interval_usecs;
424*86d7f5d3SJohn Marino 	if (deadline >= current_time) {
425*86d7f5d3SJohn Marino 		tb->deadlines_met++;
426*86d7f5d3SJohn Marino 	} else {
427*86d7f5d3SJohn Marino 		if (interval_usecs) {
428*86d7f5d3SJohn Marino 			unsigned long intervals = (current_time - deadline) /
429*86d7f5d3SJohn Marino 				interval_usecs + 1;
430*86d7f5d3SJohn Marino 
431*86d7f5d3SJohn Marino 			tb->missed_deadlines += intervals;
432*86d7f5d3SJohn Marino 			missed_latency = intervals * interval_usecs;
433*86d7f5d3SJohn Marino 			deadline += intervals * interval_usecs;
434*86d7f5d3SJohn Marino 			if (intervals > 1)
435*86d7f5d3SJohn Marino 				tb->missed_burns += intervals;
436*86d7f5d3SJohn Marino 		} else {
437*86d7f5d3SJohn Marino 			deadline = current_time;
438*86d7f5d3SJohn Marino 			goto out_nosleep;
439*86d7f5d3SJohn Marino 		}
440*86d7f5d3SJohn Marino 	}
441*86d7f5d3SJohn Marino bypass_burn:
442*86d7f5d3SJohn Marino 	tk->sleep_interval = deadline - current_time;
443*86d7f5d3SJohn Marino 
444*86d7f5d3SJohn Marino 	post_sem(&tk->sem.start);
445*86d7f5d3SJohn Marino 	wait_sem(&tk->sem.complete);
446*86d7f5d3SJohn Marino out_nosleep:
447*86d7f5d3SJohn Marino 	/*
448*86d7f5d3SJohn Marino 	 * Must add missed_latency to total here as this function may not be
449*86d7f5d3SJohn Marino 	 * called again and the missed latency can be lost
450*86d7f5d3SJohn Marino 	 */
451*86d7f5d3SJohn Marino 	latency += missed_latency;
452*86d7f5d3SJohn Marino 	if (latency > tb->max_latency)
453*86d7f5d3SJohn Marino 		tb->max_latency = latency;
454*86d7f5d3SJohn Marino 	tb->total_latency += latency;
455*86d7f5d3SJohn Marino 	tb->sum_latency_squared += latency * latency;
456*86d7f5d3SJohn Marino 	tb->nr_samples++;
457*86d7f5d3SJohn Marino 
458*86d7f5d3SJohn Marino 	return deadline;
459*86d7f5d3SJohn Marino }
460*86d7f5d3SJohn Marino 
initialise_thread_data(struct data_table * tb)461*86d7f5d3SJohn Marino void initialise_thread_data(struct data_table *tb)
462*86d7f5d3SJohn Marino {
463*86d7f5d3SJohn Marino 	tb->max_latency =
464*86d7f5d3SJohn Marino 		tb->total_latency =
465*86d7f5d3SJohn Marino 		tb->sum_latency_squared =
466*86d7f5d3SJohn Marino 		tb->deadlines_met =
467*86d7f5d3SJohn Marino 		tb->missed_deadlines =
468*86d7f5d3SJohn Marino 		tb->missed_burns =
469*86d7f5d3SJohn Marino 		tb->nr_samples = 0;
470*86d7f5d3SJohn Marino }
471*86d7f5d3SJohn Marino 
create_pthread(pthread_t * thread,pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)472*86d7f5d3SJohn Marino void create_pthread(pthread_t  * thread, pthread_attr_t * attr,
473*86d7f5d3SJohn Marino 	void * (*start_routine)(void *), void *arg)
474*86d7f5d3SJohn Marino {
475*86d7f5d3SJohn Marino 	if (pthread_create(thread, attr, start_routine, arg))
476*86d7f5d3SJohn Marino 		terminal_error("pthread_create");
477*86d7f5d3SJohn Marino }
478*86d7f5d3SJohn Marino 
join_pthread(pthread_t th,void ** thread_return)479*86d7f5d3SJohn Marino void join_pthread(pthread_t th, void **thread_return)
480*86d7f5d3SJohn Marino {
481*86d7f5d3SJohn Marino 	if (pthread_join(th, thread_return))
482*86d7f5d3SJohn Marino 		terminal_error("pthread_join");
483*86d7f5d3SJohn Marino }
484*86d7f5d3SJohn Marino 
emulate_none(struct thread * th)485*86d7f5d3SJohn Marino void emulate_none(struct thread *th)
486*86d7f5d3SJohn Marino {
487*86d7f5d3SJohn Marino 	sem_t *s = &th->sem.stop;
488*86d7f5d3SJohn Marino 	wait_sem(s);
489*86d7f5d3SJohn Marino }
490*86d7f5d3SJohn Marino 
491*86d7f5d3SJohn Marino #define AUDIO_INTERVAL	(50000)
492*86d7f5d3SJohn Marino #define AUDIO_RUN	(AUDIO_INTERVAL / 20)
493*86d7f5d3SJohn Marino /* We emulate audio by using 5% cpu and waking every 50ms */
emulate_audio(struct thread * th)494*86d7f5d3SJohn Marino void emulate_audio(struct thread *th)
495*86d7f5d3SJohn Marino {
496*86d7f5d3SJohn Marino 	unsigned long long deadline;
497*86d7f5d3SJohn Marino 	sem_t *s = &th->sem.stop;
498*86d7f5d3SJohn Marino 	struct timespec myts;
499*86d7f5d3SJohn Marino 
500*86d7f5d3SJohn Marino 	th->decasecond_deadlines = 1000000 / AUDIO_INTERVAL * 10;
501*86d7f5d3SJohn Marino 	deadline = get_usecs(&myts);
502*86d7f5d3SJohn Marino 
503*86d7f5d3SJohn Marino 	while (1) {
504*86d7f5d3SJohn Marino 		deadline = periodic_schedule(th, AUDIO_RUN, AUDIO_INTERVAL,
505*86d7f5d3SJohn Marino 			deadline);
506*86d7f5d3SJohn Marino 		if (!trywait_sem(s))
507*86d7f5d3SJohn Marino 			return;
508*86d7f5d3SJohn Marino 	}
509*86d7f5d3SJohn Marino }
510*86d7f5d3SJohn Marino 
511*86d7f5d3SJohn Marino /* We emulate video by using 40% cpu and waking for 60fps */
512*86d7f5d3SJohn Marino #define VIDEO_INTERVAL	(1000000 / 60)
513*86d7f5d3SJohn Marino #define VIDEO_RUN	(VIDEO_INTERVAL * 40 / 100)
emulate_video(struct thread * th)514*86d7f5d3SJohn Marino void emulate_video(struct thread *th)
515*86d7f5d3SJohn Marino {
516*86d7f5d3SJohn Marino 	unsigned long long deadline;
517*86d7f5d3SJohn Marino 	sem_t *s = &th->sem.stop;
518*86d7f5d3SJohn Marino 	struct timespec myts;
519*86d7f5d3SJohn Marino 
520*86d7f5d3SJohn Marino 	th->decasecond_deadlines = 1000000 / VIDEO_INTERVAL * 10;
521*86d7f5d3SJohn Marino 	deadline = get_usecs(&myts);
522*86d7f5d3SJohn Marino 
523*86d7f5d3SJohn Marino 	while (1) {
524*86d7f5d3SJohn Marino 		deadline = periodic_schedule(th, VIDEO_RUN, VIDEO_INTERVAL,
525*86d7f5d3SJohn Marino 			deadline);
526*86d7f5d3SJohn Marino 		if (!trywait_sem(s))
527*86d7f5d3SJohn Marino 			return;
528*86d7f5d3SJohn Marino 	}
529*86d7f5d3SJohn Marino }
530*86d7f5d3SJohn Marino 
531*86d7f5d3SJohn Marino /*
532*86d7f5d3SJohn Marino  * We emulate X by running for a variable percentage of cpu from 0-100%
533*86d7f5d3SJohn Marino  * in 1ms chunks.
534*86d7f5d3SJohn Marino  */
emulate_x(struct thread * th)535*86d7f5d3SJohn Marino void emulate_x(struct thread *th)
536*86d7f5d3SJohn Marino {
537*86d7f5d3SJohn Marino 	unsigned long long deadline;
538*86d7f5d3SJohn Marino 	sem_t *s = &th->sem.stop;
539*86d7f5d3SJohn Marino 	struct timespec myts;
540*86d7f5d3SJohn Marino 
541*86d7f5d3SJohn Marino 	th->decasecond_deadlines = 100;
542*86d7f5d3SJohn Marino 	deadline = get_usecs(&myts);
543*86d7f5d3SJohn Marino 
544*86d7f5d3SJohn Marino 	while (1) {
545*86d7f5d3SJohn Marino 		int i, j;
546*86d7f5d3SJohn Marino 		for (i = 0 ; i <= 100 ; i++) {
547*86d7f5d3SJohn Marino 			j = 100 - i;
548*86d7f5d3SJohn Marino 			deadline = periodic_schedule(th, i * 1000, j * 1000,
549*86d7f5d3SJohn Marino 				deadline);
550*86d7f5d3SJohn Marino 			deadline += i * 1000;
551*86d7f5d3SJohn Marino 			if (!trywait_sem(s))
552*86d7f5d3SJohn Marino 				return;
553*86d7f5d3SJohn Marino 		}
554*86d7f5d3SJohn Marino 	}
555*86d7f5d3SJohn Marino }
556*86d7f5d3SJohn Marino 
557*86d7f5d3SJohn Marino /*
558*86d7f5d3SJohn Marino  * We emulate gaming by using 100% cpu and seeing how many frames (jobs
559*86d7f5d3SJohn Marino  * completed) we can do in that time. Deadlines are meaningless with
560*86d7f5d3SJohn Marino  * unlocked frame rates. We do not use periodic schedule because for
561*86d7f5d3SJohn Marino  * this load because this never wants to sleep.
562*86d7f5d3SJohn Marino  */
563*86d7f5d3SJohn Marino #define GAME_INTERVAL	(100000)
564*86d7f5d3SJohn Marino #define GAME_RUN	(GAME_INTERVAL)
emulate_game(struct thread * th)565*86d7f5d3SJohn Marino void emulate_game(struct thread *th)
566*86d7f5d3SJohn Marino {
567*86d7f5d3SJohn Marino 	unsigned long long deadline, current_time, latency;
568*86d7f5d3SJohn Marino 	sem_t *s = &th->sem.stop;
569*86d7f5d3SJohn Marino 	struct timespec myts;
570*86d7f5d3SJohn Marino 	struct data_table *tb;
571*86d7f5d3SJohn Marino 
572*86d7f5d3SJohn Marino 	tb = th->dt;
573*86d7f5d3SJohn Marino 	th->decasecond_deadlines = 1000000 / GAME_INTERVAL * 10;
574*86d7f5d3SJohn Marino 
575*86d7f5d3SJohn Marino 	while (1) {
576*86d7f5d3SJohn Marino 		deadline = get_usecs(&myts) + GAME_INTERVAL;
577*86d7f5d3SJohn Marino 		burn_usecs(GAME_RUN);
578*86d7f5d3SJohn Marino 		current_time = get_usecs(&myts);
579*86d7f5d3SJohn Marino 		/* use usecs instead of simple count for game burn statistics */
580*86d7f5d3SJohn Marino 		tb->achieved_burns += GAME_RUN;
581*86d7f5d3SJohn Marino 		if (current_time > deadline) {
582*86d7f5d3SJohn Marino 			latency = current_time - deadline;
583*86d7f5d3SJohn Marino 			tb->missed_burns += latency;
584*86d7f5d3SJohn Marino 		} else
585*86d7f5d3SJohn Marino 			latency = 0;
586*86d7f5d3SJohn Marino 		if (latency > tb->max_latency)
587*86d7f5d3SJohn Marino 			tb->max_latency = latency;
588*86d7f5d3SJohn Marino 		tb->total_latency += latency;
589*86d7f5d3SJohn Marino 		tb->sum_latency_squared += latency * latency;
590*86d7f5d3SJohn Marino 		tb->nr_samples++;
591*86d7f5d3SJohn Marino 		if (!trywait_sem(s))
592*86d7f5d3SJohn Marino 			return;
593*86d7f5d3SJohn Marino 	}
594*86d7f5d3SJohn Marino }
595*86d7f5d3SJohn Marino 
burn_thread(void * t)596*86d7f5d3SJohn Marino void *burn_thread(void *t)
597*86d7f5d3SJohn Marino {
598*86d7f5d3SJohn Marino 	struct thread *th;
599*86d7f5d3SJohn Marino 	sem_t *s;
600*86d7f5d3SJohn Marino 	long i = (long)t;
601*86d7f5d3SJohn Marino 
602*86d7f5d3SJohn Marino 	th = &threadlist[i];
603*86d7f5d3SJohn Marino 	s = &th->sem.stopchild;
604*86d7f5d3SJohn Marino 
605*86d7f5d3SJohn Marino 	while (1) {
606*86d7f5d3SJohn Marino 		burn_loops(ud.loops_per_ms);
607*86d7f5d3SJohn Marino 		if (!trywait_sem(s)) {
608*86d7f5d3SJohn Marino 			post_sem(s);
609*86d7f5d3SJohn Marino 			break;
610*86d7f5d3SJohn Marino 		}
611*86d7f5d3SJohn Marino 	}
612*86d7f5d3SJohn Marino 	return NULL;
613*86d7f5d3SJohn Marino }
614*86d7f5d3SJohn Marino 
615*86d7f5d3SJohn Marino /* Have ud.cpu_load threads burn cpu continuously */
emulate_burn(struct thread * th)616*86d7f5d3SJohn Marino void emulate_burn(struct thread *th)
617*86d7f5d3SJohn Marino {
618*86d7f5d3SJohn Marino 	sem_t *s = &th->sem.stop;
619*86d7f5d3SJohn Marino 	unsigned long i;
620*86d7f5d3SJohn Marino 	long t;
621*86d7f5d3SJohn Marino 	pthread_t burnthreads[ud.cpu_load];
622*86d7f5d3SJohn Marino 
623*86d7f5d3SJohn Marino 	t = th->threadno;
624*86d7f5d3SJohn Marino 	for (i = 0 ; i < ud.cpu_load ; i++)
625*86d7f5d3SJohn Marino 		create_pthread(&burnthreads[i], NULL, burn_thread,
626*86d7f5d3SJohn Marino 			(void*)(long) t);
627*86d7f5d3SJohn Marino 	wait_sem(s);
628*86d7f5d3SJohn Marino 	post_sem(&th->sem.stopchild);
629*86d7f5d3SJohn Marino 	for (i = 0 ; i < ud.cpu_load ; i++)
630*86d7f5d3SJohn Marino 		join_pthread(burnthreads[i], NULL);
631*86d7f5d3SJohn Marino }
632*86d7f5d3SJohn Marino 
633*86d7f5d3SJohn Marino /* Write a file the size of ram continuously */
emulate_write(struct thread * th)634*86d7f5d3SJohn Marino void emulate_write(struct thread *th)
635*86d7f5d3SJohn Marino {
636*86d7f5d3SJohn Marino 	sem_t *s = &th->sem.stop;
637*86d7f5d3SJohn Marino 	FILE *fp;
638*86d7f5d3SJohn Marino 	char *name = "interbench.write";
639*86d7f5d3SJohn Marino 	void *buf = NULL;
640*86d7f5d3SJohn Marino 	struct stat statbuf;
641*86d7f5d3SJohn Marino 	unsigned long mem;
642*86d7f5d3SJohn Marino 
643*86d7f5d3SJohn Marino 	if (!(fp = fopen(name, "w")))
644*86d7f5d3SJohn Marino 		terminal_error("fopen");
645*86d7f5d3SJohn Marino 	if (stat(name, &statbuf) == -1)
646*86d7f5d3SJohn Marino 		terminal_fileopen_error(fp, "stat");
647*86d7f5d3SJohn Marino 	if (statbuf.st_blksize < MIN_BLK_SIZE)
648*86d7f5d3SJohn Marino 		statbuf.st_blksize = MIN_BLK_SIZE;
649*86d7f5d3SJohn Marino 	mem = ud.ram / (statbuf.st_blksize / 1024);	/* kilobytes to blocks */
650*86d7f5d3SJohn Marino 	if (!(buf = calloc(1, statbuf.st_blksize)))
651*86d7f5d3SJohn Marino 		terminal_fileopen_error(fp, "calloc");
652*86d7f5d3SJohn Marino 	if (fclose(fp) == -1)
653*86d7f5d3SJohn Marino 		terminal_error("fclose");
654*86d7f5d3SJohn Marino 
655*86d7f5d3SJohn Marino 	while (1) {
656*86d7f5d3SJohn Marino 		unsigned int i;
657*86d7f5d3SJohn Marino 
658*86d7f5d3SJohn Marino 		if (!(fp = fopen(name, "w")))
659*86d7f5d3SJohn Marino 			terminal_error("fopen");
660*86d7f5d3SJohn Marino 		if (stat(name, &statbuf) == -1)
661*86d7f5d3SJohn Marino 			terminal_fileopen_error(fp, "stat");
662*86d7f5d3SJohn Marino 		for (i = 0 ; i < mem; i++) {
663*86d7f5d3SJohn Marino 			if (fwrite(buf, statbuf.st_blksize, 1, fp) != 1)
664*86d7f5d3SJohn Marino 				terminal_fileopen_error(fp, "fwrite");
665*86d7f5d3SJohn Marino 			if (!trywait_sem(s))
666*86d7f5d3SJohn Marino 				goto out;
667*86d7f5d3SJohn Marino 		}
668*86d7f5d3SJohn Marino 		if (fclose(fp) == -1)
669*86d7f5d3SJohn Marino 			terminal_error("fclose");
670*86d7f5d3SJohn Marino 	}
671*86d7f5d3SJohn Marino 
672*86d7f5d3SJohn Marino out:
673*86d7f5d3SJohn Marino 	if (fclose(fp) == -1)
674*86d7f5d3SJohn Marino 		terminal_error("fclose");
675*86d7f5d3SJohn Marino 	if (remove(name) == -1)
676*86d7f5d3SJohn Marino 		terminal_error("remove");
677*86d7f5d3SJohn Marino 	sync_flush();
678*86d7f5d3SJohn Marino }
679*86d7f5d3SJohn Marino 
680*86d7f5d3SJohn Marino /* Read a file the size of ram continuously */
emulate_read(struct thread * th)681*86d7f5d3SJohn Marino void emulate_read(struct thread *th)
682*86d7f5d3SJohn Marino {
683*86d7f5d3SJohn Marino 	sem_t *s = &th->sem.stop;
684*86d7f5d3SJohn Marino 	char *name = "interbench.read";
685*86d7f5d3SJohn Marino 	void *buf = NULL;
686*86d7f5d3SJohn Marino 	struct stat statbuf;
687*86d7f5d3SJohn Marino 	unsigned long bsize;
688*86d7f5d3SJohn Marino 	int tmp;
689*86d7f5d3SJohn Marino 
690*86d7f5d3SJohn Marino 	if ((tmp = open(name, O_RDONLY)) == -1)
691*86d7f5d3SJohn Marino 		terminal_error("open");
692*86d7f5d3SJohn Marino 	if (stat(name, &statbuf) == -1)
693*86d7f5d3SJohn Marino 		terminal_error("stat");
694*86d7f5d3SJohn Marino 	bsize = statbuf.st_blksize;
695*86d7f5d3SJohn Marino 	if (!(buf = malloc(bsize)))
696*86d7f5d3SJohn Marino 		terminal_error("malloc");
697*86d7f5d3SJohn Marino 
698*86d7f5d3SJohn Marino 	while (1) {
699*86d7f5d3SJohn Marino 		int rd;
700*86d7f5d3SJohn Marino 
701*86d7f5d3SJohn Marino 		/*
702*86d7f5d3SJohn Marino 		 * We have to read the whole file before quitting the load
703*86d7f5d3SJohn Marino 		 * to prevent the data being cached for the next read. This
704*86d7f5d3SJohn Marino 		 * is also the reason the file is the size of physical ram.
705*86d7f5d3SJohn Marino 		 */
706*86d7f5d3SJohn Marino 		while ((rd = Read(tmp , buf, bsize)) > 0);
707*86d7f5d3SJohn Marino 		if(!trywait_sem(s))
708*86d7f5d3SJohn Marino 			return;
709*86d7f5d3SJohn Marino 		if (lseek(tmp, (off_t)0, SEEK_SET) == -1)
710*86d7f5d3SJohn Marino 			terminal_error("lseek");
711*86d7f5d3SJohn Marino 	}
712*86d7f5d3SJohn Marino }
713*86d7f5d3SJohn Marino 
714*86d7f5d3SJohn Marino #define RINGTHREADS	4
715*86d7f5d3SJohn Marino 
716*86d7f5d3SJohn Marino struct thread ringthreads[RINGTHREADS];
717*86d7f5d3SJohn Marino 
ring_thread(void * t)718*86d7f5d3SJohn Marino void *ring_thread(void *t)
719*86d7f5d3SJohn Marino {
720*86d7f5d3SJohn Marino 	struct thread *th;
721*86d7f5d3SJohn Marino 	struct sems *s;
722*86d7f5d3SJohn Marino 	int i, post_to;
723*86d7f5d3SJohn Marino 
724*86d7f5d3SJohn Marino 	i = (long)t;
725*86d7f5d3SJohn Marino 	th = &ringthreads[i];
726*86d7f5d3SJohn Marino 	s = &th->sem;
727*86d7f5d3SJohn Marino 	post_to = i + 1;
728*86d7f5d3SJohn Marino 	if (post_to == RINGTHREADS)
729*86d7f5d3SJohn Marino 		post_to = 0;
730*86d7f5d3SJohn Marino 	if (i == 0)
731*86d7f5d3SJohn Marino 		post_sem(&s->ready);
732*86d7f5d3SJohn Marino 
733*86d7f5d3SJohn Marino 	while (1) {
734*86d7f5d3SJohn Marino 		wait_sem(&s->start);
735*86d7f5d3SJohn Marino 		post_sem(&ringthreads[post_to].sem.start);
736*86d7f5d3SJohn Marino 		if (!trywait_sem(&s->stop))
737*86d7f5d3SJohn Marino 			goto out;
738*86d7f5d3SJohn Marino 	}
739*86d7f5d3SJohn Marino out:
740*86d7f5d3SJohn Marino 	post_sem(&ringthreads[post_to].sem.start);
741*86d7f5d3SJohn Marino 	post_sem(&s->complete);
742*86d7f5d3SJohn Marino 	return NULL;
743*86d7f5d3SJohn Marino }
744*86d7f5d3SJohn Marino 
745*86d7f5d3SJohn Marino /* Create a ring of 4 processes that wake each other up in a circle */
emulate_ring(struct thread * th)746*86d7f5d3SJohn Marino void emulate_ring(struct thread *th)
747*86d7f5d3SJohn Marino {
748*86d7f5d3SJohn Marino 	sem_t *s = &th->sem.stop;
749*86d7f5d3SJohn Marino 	int i;
750*86d7f5d3SJohn Marino 
751*86d7f5d3SJohn Marino 	for (i = 0 ; i < RINGTHREADS ; i++) {
752*86d7f5d3SJohn Marino 		init_all_sems(&ringthreads[i].sem);
753*86d7f5d3SJohn Marino 		create_pthread(&ringthreads[i].pthread, NULL,
754*86d7f5d3SJohn Marino 			ring_thread, (void*)(long) i);
755*86d7f5d3SJohn Marino 	}
756*86d7f5d3SJohn Marino 
757*86d7f5d3SJohn Marino 	wait_sem(&ringthreads[0].sem.ready);
758*86d7f5d3SJohn Marino 	post_sem(&ringthreads[0].sem.start);
759*86d7f5d3SJohn Marino 	wait_sem(s);
760*86d7f5d3SJohn Marino 	for (i = 0 ; i < RINGTHREADS ; i++)
761*86d7f5d3SJohn Marino 		post_sem(&ringthreads[i].sem.stop);
762*86d7f5d3SJohn Marino 	for (i = 0 ; i < RINGTHREADS ; i++) {
763*86d7f5d3SJohn Marino 		wait_sem(&ringthreads[i].sem.complete);
764*86d7f5d3SJohn Marino 		join_pthread(ringthreads[i].pthread, NULL);
765*86d7f5d3SJohn Marino 	}
766*86d7f5d3SJohn Marino }
767*86d7f5d3SJohn Marino 
768*86d7f5d3SJohn Marino /* We emulate a compile by running burn, write and read threads simultaneously */
emulate_compile(struct thread * th)769*86d7f5d3SJohn Marino void emulate_compile(struct thread *th)
770*86d7f5d3SJohn Marino {
771*86d7f5d3SJohn Marino 	sem_t *s = &th->sem.stop;
772*86d7f5d3SJohn Marino 	unsigned long i, threads[3];
773*86d7f5d3SJohn Marino 
774*86d7f5d3SJohn Marino 	bzero(threads, 3 * sizeof(threads[0]));
775*86d7f5d3SJohn Marino 
776*86d7f5d3SJohn Marino 	for (i = 0 ; i < THREADS ; i++) {
777*86d7f5d3SJohn Marino 		if (strcmp(threadlist[i].label, "Burn") == 0)
778*86d7f5d3SJohn Marino 			threads[0] = i;
779*86d7f5d3SJohn Marino 		if (strcmp(threadlist[i].label, "Write") == 0)
780*86d7f5d3SJohn Marino 			threads[1] = i;
781*86d7f5d3SJohn Marino 		if (strcmp(threadlist[i].label, "Read") == 0)
782*86d7f5d3SJohn Marino 			threads[2] = i;
783*86d7f5d3SJohn Marino 	}
784*86d7f5d3SJohn Marino 	for (i = 0 ; i < 3 ; i++) {
785*86d7f5d3SJohn Marino 		if (!threads[i]) {
786*86d7f5d3SJohn Marino 			fprintf(stderr, "Can't find all threads for compile load\n");
787*86d7f5d3SJohn Marino 			exit(1);
788*86d7f5d3SJohn Marino 		}
789*86d7f5d3SJohn Marino 	}
790*86d7f5d3SJohn Marino 	for (i = 0 ; i < 3 ; i++) {
791*86d7f5d3SJohn Marino 		initialise_thread(threads[i]);
792*86d7f5d3SJohn Marino 		start_thread(&threadlist[threads[i]]);
793*86d7f5d3SJohn Marino 	}
794*86d7f5d3SJohn Marino 	wait_sem(s);
795*86d7f5d3SJohn Marino 	for (i = 0 ; i < 3 ; i++)
796*86d7f5d3SJohn Marino 		stop_thread(&threadlist[threads[i]]);
797*86d7f5d3SJohn Marino }
798*86d7f5d3SJohn Marino 
grab_and_touch(char * block[],int i)799*86d7f5d3SJohn Marino int *grab_and_touch (char *block[], int i)
800*86d7f5d3SJohn Marino {
801*86d7f5d3SJohn Marino 	block[i] = (char *) malloc(MB);
802*86d7f5d3SJohn Marino 	if (!block[i])
803*86d7f5d3SJohn Marino 		return NULL;
804*86d7f5d3SJohn Marino 	return (memset(block[i], 1, MB));
805*86d7f5d3SJohn Marino }
806*86d7f5d3SJohn Marino 
807*86d7f5d3SJohn Marino /* We emulate a memory load by allocating and torturing 110% of available ram */
emulate_memload(struct thread * th)808*86d7f5d3SJohn Marino void emulate_memload(struct thread *th)
809*86d7f5d3SJohn Marino {
810*86d7f5d3SJohn Marino 	sem_t *s = &th->sem.stop;
811*86d7f5d3SJohn Marino 	unsigned long touchable_mem, i;
812*86d7f5d3SJohn Marino 	char *mem_block[MAX_MEM_IN_MB];
813*86d7f5d3SJohn Marino 	void *success;
814*86d7f5d3SJohn Marino 
815*86d7f5d3SJohn Marino 	touchable_mem = compute_allocable_mem();
816*86d7f5d3SJohn Marino 	/* loop until we're killed, frobbing memory in various perverted ways */
817*86d7f5d3SJohn Marino 	while (1) {
818*86d7f5d3SJohn Marino 		for (i = 0;  i < touchable_mem; i++) {
819*86d7f5d3SJohn Marino 			success = grab_and_touch(mem_block, i);
820*86d7f5d3SJohn Marino 			if (!success) {
821*86d7f5d3SJohn Marino 				touchable_mem = i-1;
822*86d7f5d3SJohn Marino 				break;
823*86d7f5d3SJohn Marino 			}
824*86d7f5d3SJohn Marino 		}
825*86d7f5d3SJohn Marino 		if (!trywait_sem(s))
826*86d7f5d3SJohn Marino 			goto out_freemem;
827*86d7f5d3SJohn Marino 		for (i = 0;  i < touchable_mem; i++) {
828*86d7f5d3SJohn Marino 			memcpy(mem_block[i], mem_block[(i + touchable_mem / 2) %
829*86d7f5d3SJohn Marino 				touchable_mem], MB);
830*86d7f5d3SJohn Marino 			if (!trywait_sem(s))
831*86d7f5d3SJohn Marino 				goto out_freemem;
832*86d7f5d3SJohn Marino 		}
833*86d7f5d3SJohn Marino 		for (i = 0; i < touchable_mem; i++) {
834*86d7f5d3SJohn Marino 			free(mem_block[i]);
835*86d7f5d3SJohn Marino 		}
836*86d7f5d3SJohn Marino 		if (!trywait_sem(s))
837*86d7f5d3SJohn Marino 			goto out;
838*86d7f5d3SJohn Marino 	}
839*86d7f5d3SJohn Marino out_freemem:
840*86d7f5d3SJohn Marino 	for (i = 0; i < touchable_mem; i++)
841*86d7f5d3SJohn Marino 		free(mem_block[i]);
842*86d7f5d3SJohn Marino out:
843*86d7f5d3SJohn Marino 	return;
844*86d7f5d3SJohn Marino }
845*86d7f5d3SJohn Marino 
846*86d7f5d3SJohn Marino struct thread hackthread;
847*86d7f5d3SJohn Marino 
emulate_hackbench(struct thread * th)848*86d7f5d3SJohn Marino void emulate_hackbench(struct thread *th)
849*86d7f5d3SJohn Marino {
850*86d7f5d3SJohn Marino 	sem_t *s = &th->sem.stop;
851*86d7f5d3SJohn Marino 
852*86d7f5d3SJohn Marino 	init_all_sems(&hackthread.sem);
853*86d7f5d3SJohn Marino 	create_pthread(&hackthread.pthread, NULL, hackbench_thread, (void *) 0);
854*86d7f5d3SJohn Marino 
855*86d7f5d3SJohn Marino 	wait_sem(s);
856*86d7f5d3SJohn Marino 
857*86d7f5d3SJohn Marino 	post_sem(&hackthread.sem.stop);
858*86d7f5d3SJohn Marino 	wait_sem(&hackthread.sem.complete);
859*86d7f5d3SJohn Marino 
860*86d7f5d3SJohn Marino 	join_pthread(hackthread.pthread, NULL);
861*86d7f5d3SJohn Marino }
862*86d7f5d3SJohn Marino 
863*86d7f5d3SJohn Marino #define CUSTOM_INTERVAL	(ud.custom_interval)
864*86d7f5d3SJohn Marino #define CUSTOM_RUN	(ud.custom_run)
emulate_custom(struct thread * th)865*86d7f5d3SJohn Marino void emulate_custom(struct thread *th)
866*86d7f5d3SJohn Marino {
867*86d7f5d3SJohn Marino 	unsigned long long deadline;
868*86d7f5d3SJohn Marino 	sem_t *s = &th->sem.stop;
869*86d7f5d3SJohn Marino 	struct timespec myts;
870*86d7f5d3SJohn Marino 
871*86d7f5d3SJohn Marino 	th->decasecond_deadlines = 1000000 / CUSTOM_INTERVAL * 10;
872*86d7f5d3SJohn Marino 	deadline = get_usecs(&myts);
873*86d7f5d3SJohn Marino 
874*86d7f5d3SJohn Marino 	while (1) {
875*86d7f5d3SJohn Marino 		deadline = periodic_schedule(th, CUSTOM_RUN, CUSTOM_INTERVAL,
876*86d7f5d3SJohn Marino 			deadline);
877*86d7f5d3SJohn Marino 		if (!trywait_sem(s))
878*86d7f5d3SJohn Marino 			return;
879*86d7f5d3SJohn Marino 	}
880*86d7f5d3SJohn Marino }
881*86d7f5d3SJohn Marino 
timekeeping_thread(void * t)882*86d7f5d3SJohn Marino void *timekeeping_thread(void *t)
883*86d7f5d3SJohn Marino {
884*86d7f5d3SJohn Marino 	struct thread *th;
885*86d7f5d3SJohn Marino 	struct tk_thread *tk;
886*86d7f5d3SJohn Marino 	struct sems *s;
887*86d7f5d3SJohn Marino 	struct timespec myts;
888*86d7f5d3SJohn Marino 	long i = (long)t;
889*86d7f5d3SJohn Marino 
890*86d7f5d3SJohn Marino 	th = &threadlist[i];
891*86d7f5d3SJohn Marino 	tk = &th->tkthread;
892*86d7f5d3SJohn Marino 	s = &th->tkthread.sem;
893*86d7f5d3SJohn Marino 	/*
894*86d7f5d3SJohn Marino 	 * If this timekeeping thread is that of a benchmarked thread we run
895*86d7f5d3SJohn Marino 	 * even higher priority than the benched thread is if running real
896*86d7f5d3SJohn Marino 	 * time. Otherwise, the load timekeeping thread, which does not need
897*86d7f5d3SJohn Marino 	 * accurate accounting remains SCHED_NORMAL;
898*86d7f5d3SJohn Marino 	 */
899*86d7f5d3SJohn Marino 	if (th->dt != &th->benchmarks[NOT_BENCHING])
900*86d7f5d3SJohn Marino 		set_fifo(96);
901*86d7f5d3SJohn Marino 	/* These values must be changed at the appropriate places or race */
902*86d7f5d3SJohn Marino 	tk->sleep_interval = tk->slept_interval = 0;
903*86d7f5d3SJohn Marino 	post_sem(&s->ready);
904*86d7f5d3SJohn Marino 
905*86d7f5d3SJohn Marino 	while (1) {
906*86d7f5d3SJohn Marino 		unsigned long start_time, now;
907*86d7f5d3SJohn Marino 
908*86d7f5d3SJohn Marino 		if (!trywait_sem(&s->stop))
909*86d7f5d3SJohn Marino 			goto out;
910*86d7f5d3SJohn Marino 		wait_sem(&s->start);
911*86d7f5d3SJohn Marino 		tk->slept_interval = 0;
912*86d7f5d3SJohn Marino 		start_time = get_usecs(&myts);
913*86d7f5d3SJohn Marino 		if (!trywait_sem(&s->stop))
914*86d7f5d3SJohn Marino 			goto out;
915*86d7f5d3SJohn Marino 		if (tk->sleep_interval) {
916*86d7f5d3SJohn Marino 			unsigned long diff = 0;
917*86d7f5d3SJohn Marino 			microsleep(tk->sleep_interval);
918*86d7f5d3SJohn Marino 			now = get_usecs(&myts);
919*86d7f5d3SJohn Marino 			/* now should always be > start_time but... */
920*86d7f5d3SJohn Marino 			if (now > start_time) {
921*86d7f5d3SJohn Marino 				diff = now - start_time;
922*86d7f5d3SJohn Marino 				if (diff > tk->sleep_interval)
923*86d7f5d3SJohn Marino 					tk->slept_interval = diff -
924*86d7f5d3SJohn Marino 						tk->sleep_interval;
925*86d7f5d3SJohn Marino 			}
926*86d7f5d3SJohn Marino 		}
927*86d7f5d3SJohn Marino 		tk->sleep_interval = 0;
928*86d7f5d3SJohn Marino 		post_sem(&s->complete);
929*86d7f5d3SJohn Marino 	}
930*86d7f5d3SJohn Marino out:
931*86d7f5d3SJohn Marino 	return NULL;
932*86d7f5d3SJohn Marino }
933*86d7f5d3SJohn Marino 
934*86d7f5d3SJohn Marino /*
935*86d7f5d3SJohn Marino  * All the sleep functions such as nanosleep can only guarantee that they
936*86d7f5d3SJohn Marino  * sleep for _at least_ the time requested. We work around this by having
937*86d7f5d3SJohn Marino  * a high priority real time thread that accounts for the extra time slept
938*86d7f5d3SJohn Marino  * in nanosleep. This allows wakeup latency of the tested thread to be
939*86d7f5d3SJohn Marino  * accurate and reflect true scheduling delays.
940*86d7f5d3SJohn Marino  */
emulation_thread(void * t)941*86d7f5d3SJohn Marino void *emulation_thread(void *t)
942*86d7f5d3SJohn Marino {
943*86d7f5d3SJohn Marino 	struct thread *th;
944*86d7f5d3SJohn Marino 	struct tk_thread *tk;
945*86d7f5d3SJohn Marino 	struct sems *s, *tks;
946*86d7f5d3SJohn Marino 	long i = (long)t;
947*86d7f5d3SJohn Marino 
948*86d7f5d3SJohn Marino 	th = &threadlist[i];
949*86d7f5d3SJohn Marino 	tk = &th->tkthread;
950*86d7f5d3SJohn Marino 	s = &th->sem;
951*86d7f5d3SJohn Marino 	tks = &tk->sem;
952*86d7f5d3SJohn Marino 	init_all_sems(tks);
953*86d7f5d3SJohn Marino 
954*86d7f5d3SJohn Marino 	/* Start the timekeeping thread */
955*86d7f5d3SJohn Marino 	create_pthread(&th->tk_pthread, NULL, timekeeping_thread,
956*86d7f5d3SJohn Marino 		(void*)(long) i);
957*86d7f5d3SJohn Marino 	/* Wait for timekeeping thread to be ready */
958*86d7f5d3SJohn Marino 	wait_sem(&tks->ready);
959*86d7f5d3SJohn Marino 
960*86d7f5d3SJohn Marino 	/* Tell main we're ready to start*/
961*86d7f5d3SJohn Marino 	post_sem(&s->ready);
962*86d7f5d3SJohn Marino 
963*86d7f5d3SJohn Marino 	/* Wait for signal from main to start thread */
964*86d7f5d3SJohn Marino 	wait_sem(&s->start);
965*86d7f5d3SJohn Marino 
966*86d7f5d3SJohn Marino 	/* Start the actual function being benched/or running as load */
967*86d7f5d3SJohn Marino 	th->name(th);
968*86d7f5d3SJohn Marino 
969*86d7f5d3SJohn Marino 	/* Stop the timekeeping thread */
970*86d7f5d3SJohn Marino 	post_sem(&tks->stop);
971*86d7f5d3SJohn Marino 	post_sem(&tks->start);
972*86d7f5d3SJohn Marino 	join_pthread(th->tk_pthread, NULL);
973*86d7f5d3SJohn Marino 
974*86d7f5d3SJohn Marino 	/* Tell main we've finished */
975*86d7f5d3SJohn Marino 	post_sem(&s->complete);
976*86d7f5d3SJohn Marino 	return NULL;
977*86d7f5d3SJohn Marino }
978*86d7f5d3SJohn Marino 
979*86d7f5d3SJohn Marino /*
980*86d7f5d3SJohn Marino  * In an unoptimised loop we try to benchmark how many meaningless loops
981*86d7f5d3SJohn Marino  * per second we can perform on this hardware to fairly accurately
982*86d7f5d3SJohn Marino  * reproduce certain percentage cpu usage
983*86d7f5d3SJohn Marino  */
calibrate_loop(void)984*86d7f5d3SJohn Marino void calibrate_loop(void)
985*86d7f5d3SJohn Marino {
986*86d7f5d3SJohn Marino 	unsigned long long start_time, loops_per_msec, run_time = 0;
987*86d7f5d3SJohn Marino 	unsigned long loops;
988*86d7f5d3SJohn Marino 	struct timespec myts;
989*86d7f5d3SJohn Marino 
990*86d7f5d3SJohn Marino 	loops_per_msec = 100000;
991*86d7f5d3SJohn Marino redo:
992*86d7f5d3SJohn Marino 	/* Calibrate to within 1% accuracy */
993*86d7f5d3SJohn Marino 	while (run_time > 1010000 || run_time < 990000) {
994*86d7f5d3SJohn Marino 		loops = loops_per_msec;
995*86d7f5d3SJohn Marino 		start_time = get_nsecs(&myts);
996*86d7f5d3SJohn Marino 		burn_loops(loops);
997*86d7f5d3SJohn Marino 		run_time = get_nsecs(&myts) - start_time;
998*86d7f5d3SJohn Marino 		loops_per_msec = (1000000 * loops_per_msec / run_time ? :
999*86d7f5d3SJohn Marino 			loops_per_msec);
1000*86d7f5d3SJohn Marino 	}
1001*86d7f5d3SJohn Marino 
1002*86d7f5d3SJohn Marino 	/* Rechecking after a pause increases reproducibility */
1003*86d7f5d3SJohn Marino 	sleep(1);
1004*86d7f5d3SJohn Marino 	loops = loops_per_msec;
1005*86d7f5d3SJohn Marino 	start_time = get_nsecs(&myts);
1006*86d7f5d3SJohn Marino 	burn_loops(loops);
1007*86d7f5d3SJohn Marino 	run_time = get_nsecs(&myts) - start_time;
1008*86d7f5d3SJohn Marino 
1009*86d7f5d3SJohn Marino 	/* Tolerate 5% difference on checking */
1010*86d7f5d3SJohn Marino 	if (run_time > 1050000 || run_time < 950000)
1011*86d7f5d3SJohn Marino 		goto redo;
1012*86d7f5d3SJohn Marino 
1013*86d7f5d3SJohn Marino 	ud.loops_per_ms = loops_per_msec;
1014*86d7f5d3SJohn Marino }
1015*86d7f5d3SJohn Marino 
1016*86d7f5d3SJohn Marino void log_output(const char *format, ...) __attribute__ ((format(printf, 1, 2)));
1017*86d7f5d3SJohn Marino 
1018*86d7f5d3SJohn Marino /* Output to console +/- logfile */
log_output(const char * format,...)1019*86d7f5d3SJohn Marino void log_output(const char *format, ...)
1020*86d7f5d3SJohn Marino {
1021*86d7f5d3SJohn Marino 	va_list ap;
1022*86d7f5d3SJohn Marino 
1023*86d7f5d3SJohn Marino 	va_start(ap, format);
1024*86d7f5d3SJohn Marino 	if (vprintf(format, ap) == -1)
1025*86d7f5d3SJohn Marino 		terminal_error("vprintf");
1026*86d7f5d3SJohn Marino 	va_end(ap);
1027*86d7f5d3SJohn Marino 	if (ud.log) {
1028*86d7f5d3SJohn Marino 		va_start(ap, format);
1029*86d7f5d3SJohn Marino 		if (vfprintf(ud.logfile, format, ap) == -1)
1030*86d7f5d3SJohn Marino 			terminal_error("vpfrintf");
1031*86d7f5d3SJohn Marino 		va_end(ap);
1032*86d7f5d3SJohn Marino 	}
1033*86d7f5d3SJohn Marino 	fflush(NULL);
1034*86d7f5d3SJohn Marino }
1035*86d7f5d3SJohn Marino 
1036*86d7f5d3SJohn Marino /* Calculate statistics and output them */
show_latencies(struct thread * th)1037*86d7f5d3SJohn Marino void show_latencies(struct thread *th)
1038*86d7f5d3SJohn Marino {
1039*86d7f5d3SJohn Marino 	struct data_table *tbj;
1040*86d7f5d3SJohn Marino 	struct tk_thread *tk;
1041*86d7f5d3SJohn Marino 	double average_latency, deadlines_met, samples_met, sd, max_latency;
1042*86d7f5d3SJohn Marino 	long double variance = 0;
1043*86d7f5d3SJohn Marino 
1044*86d7f5d3SJohn Marino 	tbj = th->dt;
1045*86d7f5d3SJohn Marino 	tk = &th->tkthread;
1046*86d7f5d3SJohn Marino 
1047*86d7f5d3SJohn Marino 	if (tbj->nr_samples > 1) {
1048*86d7f5d3SJohn Marino 		average_latency = tbj->total_latency / tbj->nr_samples;
1049*86d7f5d3SJohn Marino 		variance = (tbj->sum_latency_squared - (average_latency *
1050*86d7f5d3SJohn Marino 			average_latency) / tbj->nr_samples) / (tbj->nr_samples - 1);
1051*86d7f5d3SJohn Marino 		sd = sqrt((double)variance);
1052*86d7f5d3SJohn Marino 	} else {
1053*86d7f5d3SJohn Marino 		average_latency = tbj->total_latency;
1054*86d7f5d3SJohn Marino 		sd = 0.0;
1055*86d7f5d3SJohn Marino 	}
1056*86d7f5d3SJohn Marino 
1057*86d7f5d3SJohn Marino 	/*
1058*86d7f5d3SJohn Marino 	 * Landing on the boundary of a deadline can make loaded runs appear
1059*86d7f5d3SJohn Marino 	 * to do more work than unloaded due to tiny duration differences.
1060*86d7f5d3SJohn Marino 	 */
1061*86d7f5d3SJohn Marino 	if (tbj->achieved_burns > 0)
1062*86d7f5d3SJohn Marino 		samples_met = (double)tbj->achieved_burns /
1063*86d7f5d3SJohn Marino 		    (double)(tbj->achieved_burns + tbj->missed_burns) * 100;
1064*86d7f5d3SJohn Marino 	else
1065*86d7f5d3SJohn Marino 		samples_met = 0.0;
1066*86d7f5d3SJohn Marino 	max_latency = tbj->max_latency;
1067*86d7f5d3SJohn Marino 	/* When benchmarking rt we represent the data in us */
1068*86d7f5d3SJohn Marino 	if (!ud.do_rt) {
1069*86d7f5d3SJohn Marino 		average_latency /= 1000;
1070*86d7f5d3SJohn Marino 		sd /= 1000;
1071*86d7f5d3SJohn Marino 		max_latency /= 1000;
1072*86d7f5d3SJohn Marino 	}
1073*86d7f5d3SJohn Marino 	if (tbj->deadlines_met == 0)
1074*86d7f5d3SJohn Marino 		deadlines_met = 0;
1075*86d7f5d3SJohn Marino 	else
1076*86d7f5d3SJohn Marino 		deadlines_met = (double)tbj->deadlines_met /
1077*86d7f5d3SJohn Marino 		    (double)(tbj->missed_deadlines + tbj->deadlines_met) * 100;
1078*86d7f5d3SJohn Marino 
1079*86d7f5d3SJohn Marino 	/* Messy nonsense to format the output nicely */
1080*86d7f5d3SJohn Marino 	if (average_latency >= 100)
1081*86d7f5d3SJohn Marino 		log_output("%7.0f +/- ", average_latency);
1082*86d7f5d3SJohn Marino 	else
1083*86d7f5d3SJohn Marino 		log_output("%7.3g +/- ", average_latency);
1084*86d7f5d3SJohn Marino 	if (sd >= 100)
1085*86d7f5d3SJohn Marino 		log_output("%-9.0f", sd);
1086*86d7f5d3SJohn Marino 	else
1087*86d7f5d3SJohn Marino 		log_output("%-9.3g", sd);
1088*86d7f5d3SJohn Marino 	if (max_latency >= 100)
1089*86d7f5d3SJohn Marino 		log_output("%7.0f\t", max_latency);
1090*86d7f5d3SJohn Marino 	else
1091*86d7f5d3SJohn Marino 		log_output("%7.3g\t", max_latency);
1092*86d7f5d3SJohn Marino 	log_output("\t%4.3g", samples_met);
1093*86d7f5d3SJohn Marino 	if (!th->nodeadlines)
1094*86d7f5d3SJohn Marino 		log_output("\t%11.3g", deadlines_met);
1095*86d7f5d3SJohn Marino 	log_output("\n");
1096*86d7f5d3SJohn Marino 	sync_flush();
1097*86d7f5d3SJohn Marino }
1098*86d7f5d3SJohn Marino 
create_read_file(void)1099*86d7f5d3SJohn Marino void create_read_file(void)
1100*86d7f5d3SJohn Marino {
1101*86d7f5d3SJohn Marino 	unsigned int i;
1102*86d7f5d3SJohn Marino 	FILE *fp;
1103*86d7f5d3SJohn Marino 	char *name = "interbench.read";
1104*86d7f5d3SJohn Marino 	void *buf = NULL;
1105*86d7f5d3SJohn Marino 	struct stat statbuf;
1106*86d7f5d3SJohn Marino 	unsigned long mem, bsize;
1107*86d7f5d3SJohn Marino 	int tmp;
1108*86d7f5d3SJohn Marino 
1109*86d7f5d3SJohn Marino 	if ((tmp = open(name, O_RDONLY)) == -1) {
1110*86d7f5d3SJohn Marino 		if (errno != ENOENT)
1111*86d7f5d3SJohn Marino 			terminal_error("open");
1112*86d7f5d3SJohn Marino 		goto write;
1113*86d7f5d3SJohn Marino 	}
1114*86d7f5d3SJohn Marino 	if (stat(name, &statbuf) == -1)
1115*86d7f5d3SJohn Marino 		terminal_error("stat");
1116*86d7f5d3SJohn Marino 	if (statbuf.st_blksize < MIN_BLK_SIZE)
1117*86d7f5d3SJohn Marino 		statbuf.st_blksize = MIN_BLK_SIZE;
1118*86d7f5d3SJohn Marino 	bsize = statbuf.st_blksize;
1119*86d7f5d3SJohn Marino 	if (statbuf.st_size / 1024 / bsize == ud.ram / bsize)
1120*86d7f5d3SJohn Marino 		return;
1121*86d7f5d3SJohn Marino 	if (remove(name) == -1)
1122*86d7f5d3SJohn Marino 		terminal_error("remove");
1123*86d7f5d3SJohn Marino write:
1124*86d7f5d3SJohn Marino 	fprintf(stderr,"Creating file for read load...\n");
1125*86d7f5d3SJohn Marino 	if (!(fp = fopen(name, "w")))
1126*86d7f5d3SJohn Marino 		terminal_error("fopen");
1127*86d7f5d3SJohn Marino 	if (stat(name, &statbuf) == -1)
1128*86d7f5d3SJohn Marino 		terminal_fileopen_error(fp, "stat");
1129*86d7f5d3SJohn Marino 	if (statbuf.st_blksize < MIN_BLK_SIZE)
1130*86d7f5d3SJohn Marino 		statbuf.st_blksize = MIN_BLK_SIZE;
1131*86d7f5d3SJohn Marino 	bsize = statbuf.st_blksize;
1132*86d7f5d3SJohn Marino 	if (!(buf = calloc(1, bsize)))
1133*86d7f5d3SJohn Marino 		terminal_fileopen_error(fp, "calloc");
1134*86d7f5d3SJohn Marino 	mem = ud.ram / (bsize / 1024);	/* kilobytes to blocks */
1135*86d7f5d3SJohn Marino 
1136*86d7f5d3SJohn Marino 	for (i = 0 ; i < mem; i++) {
1137*86d7f5d3SJohn Marino 		if (fwrite(buf, bsize, 1, fp) != 1)
1138*86d7f5d3SJohn Marino 			terminal_fileopen_error(fp, "fwrite");
1139*86d7f5d3SJohn Marino 	}
1140*86d7f5d3SJohn Marino 	if (fclose(fp) == -1)
1141*86d7f5d3SJohn Marino 		terminal_error("fclose");
1142*86d7f5d3SJohn Marino 	sync_flush();
1143*86d7f5d3SJohn Marino }
1144*86d7f5d3SJohn Marino 
get_ram(void)1145*86d7f5d3SJohn Marino void get_ram(void)
1146*86d7f5d3SJohn Marino {
1147*86d7f5d3SJohn Marino         struct vmstats vms;
1148*86d7f5d3SJohn Marino         size_t vms_size = sizeof(vms);
1149*86d7f5d3SJohn Marino 
1150*86d7f5d3SJohn Marino         if (sysctlbyname("vm.vmstats", &vms, &vms_size, NULL, 0))
1151*86d7f5d3SJohn Marino                 terminal_error("sysctlbyname: vm.vmstats");
1152*86d7f5d3SJohn Marino 
1153*86d7f5d3SJohn Marino 	ud.ram = vms.v_page_count * vms.v_page_size;
1154*86d7f5d3SJohn Marino 	ud.ram /= 1024; /* linux size is in kB */
1155*86d7f5d3SJohn Marino 	ud.swap = ud.ram; /* XXX: swap doesn't have to be the same as RAM */
1156*86d7f5d3SJohn Marino 
1157*86d7f5d3SJohn Marino 	if( !ud.ram || !ud.swap ) {
1158*86d7f5d3SJohn Marino 		unsigned long i;
1159*86d7f5d3SJohn Marino 		fprintf(stderr, "\nCould not get memory or swap size. ");
1160*86d7f5d3SJohn Marino 		fprintf(stderr, "Will not perform mem_load\n");
1161*86d7f5d3SJohn Marino 		for (i = 0 ; i < THREADS ; i++) {
1162*86d7f5d3SJohn Marino 			if (strcmp(threadlist[i].label, "Memload") == 0) {
1163*86d7f5d3SJohn Marino 				threadlist[i].load = 0;
1164*86d7f5d3SJohn Marino 				threadlist[i].rtload = 0;
1165*86d7f5d3SJohn Marino 			}
1166*86d7f5d3SJohn Marino 		}
1167*86d7f5d3SJohn Marino 	}
1168*86d7f5d3SJohn Marino }
1169*86d7f5d3SJohn Marino 
get_logfilename(void)1170*86d7f5d3SJohn Marino void get_logfilename(void)
1171*86d7f5d3SJohn Marino {
1172*86d7f5d3SJohn Marino 	struct tm *mytm;
1173*86d7f5d3SJohn Marino 	struct utsname buf;
1174*86d7f5d3SJohn Marino 	time_t t;
1175*86d7f5d3SJohn Marino 	int year, month, day, hours, minutes;
1176*86d7f5d3SJohn Marino 
1177*86d7f5d3SJohn Marino 	time(&t);
1178*86d7f5d3SJohn Marino 	if (uname(&buf) == -1)
1179*86d7f5d3SJohn Marino 		terminal_error("uname");
1180*86d7f5d3SJohn Marino 	if (!(mytm = localtime(&t)))
1181*86d7f5d3SJohn Marino 		terminal_error("localtime");
1182*86d7f5d3SJohn Marino 	year = mytm->tm_year + 1900;
1183*86d7f5d3SJohn Marino 	month = mytm->tm_mon + 1;
1184*86d7f5d3SJohn Marino 	day = mytm->tm_mday;
1185*86d7f5d3SJohn Marino 	hours = mytm->tm_hour;
1186*86d7f5d3SJohn Marino 	minutes = mytm->tm_min;
1187*86d7f5d3SJohn Marino 	strncpy(ud.unamer, buf.release, MAX_UNAME_LENGTH);
1188*86d7f5d3SJohn Marino 
1189*86d7f5d3SJohn Marino 	sprintf(ud.datestamp, "%2d%02d%02d%02d%02d",
1190*86d7f5d3SJohn Marino 		year, month, day, hours, minutes);
1191*86d7f5d3SJohn Marino 	snprintf(ud.logfilename, MAX_LOG_LENGTH, "%s.log", ud.unamer);
1192*86d7f5d3SJohn Marino }
1193*86d7f5d3SJohn Marino 
start_thread(struct thread * th)1194*86d7f5d3SJohn Marino void start_thread(struct thread *th)
1195*86d7f5d3SJohn Marino {
1196*86d7f5d3SJohn Marino 	post_sem(&th->sem.start);
1197*86d7f5d3SJohn Marino }
1198*86d7f5d3SJohn Marino 
stop_thread(struct thread * th)1199*86d7f5d3SJohn Marino void stop_thread(struct thread *th)
1200*86d7f5d3SJohn Marino {
1201*86d7f5d3SJohn Marino 	post_sem(&th->sem.stop);
1202*86d7f5d3SJohn Marino 	wait_sem(&th->sem.complete);
1203*86d7f5d3SJohn Marino 
1204*86d7f5d3SJohn Marino 	/* Kill the thread */
1205*86d7f5d3SJohn Marino 	join_pthread(th->pthread, NULL);
1206*86d7f5d3SJohn Marino }
1207*86d7f5d3SJohn Marino 
init_sem(sem_t * sem)1208*86d7f5d3SJohn Marino void init_sem(sem_t *sem)
1209*86d7f5d3SJohn Marino {
1210*86d7f5d3SJohn Marino 	if (sem_init(sem, 0, 0))
1211*86d7f5d3SJohn Marino 		terminal_error("sem_init");
1212*86d7f5d3SJohn Marino }
1213*86d7f5d3SJohn Marino 
init_all_sems(struct sems * s)1214*86d7f5d3SJohn Marino void init_all_sems(struct sems *s)
1215*86d7f5d3SJohn Marino {
1216*86d7f5d3SJohn Marino 	/* Initialise the semaphores */
1217*86d7f5d3SJohn Marino 	init_sem(&s->ready);
1218*86d7f5d3SJohn Marino 	init_sem(&s->start);
1219*86d7f5d3SJohn Marino 	init_sem(&s->stop);
1220*86d7f5d3SJohn Marino 	init_sem(&s->complete);
1221*86d7f5d3SJohn Marino 	init_sem(&s->stopchild);
1222*86d7f5d3SJohn Marino }
1223*86d7f5d3SJohn Marino 
initialise_thread(int i)1224*86d7f5d3SJohn Marino void initialise_thread(int i)
1225*86d7f5d3SJohn Marino {
1226*86d7f5d3SJohn Marino 	struct thread *th = &threadlist[i];
1227*86d7f5d3SJohn Marino 
1228*86d7f5d3SJohn Marino 	init_all_sems(&th->sem);
1229*86d7f5d3SJohn Marino 	/* Create the threads. Yes, the (long) cast is fugly but it's safe*/
1230*86d7f5d3SJohn Marino 	create_pthread(&th->pthread, NULL, emulation_thread, (void*)(long)i);
1231*86d7f5d3SJohn Marino 
1232*86d7f5d3SJohn Marino 	wait_sem(&th->sem.ready);
1233*86d7f5d3SJohn Marino 	/*
1234*86d7f5d3SJohn Marino 	 * We set this pointer generically to NOT_BENCHING and set it to the
1235*86d7f5d3SJohn Marino 	 * benchmarked array entry only on benched threads.
1236*86d7f5d3SJohn Marino 	 */
1237*86d7f5d3SJohn Marino 	th->dt = &th->benchmarks[NOT_BENCHING];
1238*86d7f5d3SJohn Marino 	initialise_thread_data(th->dt);
1239*86d7f5d3SJohn Marino 
1240*86d7f5d3SJohn Marino }
1241*86d7f5d3SJohn Marino 
1242*86d7f5d3SJohn Marino /* A pseudo-semaphore for processes using a pipe */
wait_on(int pype)1243*86d7f5d3SJohn Marino void wait_on(int pype)
1244*86d7f5d3SJohn Marino {
1245*86d7f5d3SJohn Marino 	int retval, buf = 0;
1246*86d7f5d3SJohn Marino 
1247*86d7f5d3SJohn Marino 	retval = Read(pype, &buf, sizeof(buf));
1248*86d7f5d3SJohn Marino 	if (retval == 0) {
1249*86d7f5d3SJohn Marino 		fprintf(stderr, "\nread returned 0\n");
1250*86d7f5d3SJohn Marino 		exit (1);
1251*86d7f5d3SJohn Marino 	}
1252*86d7f5d3SJohn Marino }
1253*86d7f5d3SJohn Marino 
wakeup_with(int pype)1254*86d7f5d3SJohn Marino void wakeup_with(int pype)
1255*86d7f5d3SJohn Marino {
1256*86d7f5d3SJohn Marino 	int retval, buf = 1;
1257*86d7f5d3SJohn Marino 
1258*86d7f5d3SJohn Marino 	retval = Write(pype, &buf, sizeof(buf));
1259*86d7f5d3SJohn Marino 	if (retval == 0) {
1260*86d7f5d3SJohn Marino 		fprintf(stderr, "\nwrite returned 0\n");
1261*86d7f5d3SJohn Marino 		exit (1);
1262*86d7f5d3SJohn Marino 	}
1263*86d7f5d3SJohn Marino }
1264*86d7f5d3SJohn Marino 
run_loadchild(int j)1265*86d7f5d3SJohn Marino void run_loadchild(int j)
1266*86d7f5d3SJohn Marino {
1267*86d7f5d3SJohn Marino 	struct thread *thj;
1268*86d7f5d3SJohn Marino 	thj = &threadlist[j];
1269*86d7f5d3SJohn Marino 
1270*86d7f5d3SJohn Marino 	set_nice(ud.load_nice);
1271*86d7f5d3SJohn Marino 	initialise_thread(j);
1272*86d7f5d3SJohn Marino 
1273*86d7f5d3SJohn Marino 	/* Tell main we're ready */
1274*86d7f5d3SJohn Marino 	wakeup_with(l2m[1]);
1275*86d7f5d3SJohn Marino 
1276*86d7f5d3SJohn Marino 	/* Main tells us we're ready */
1277*86d7f5d3SJohn Marino 	wait_on(m2l[0]);
1278*86d7f5d3SJohn Marino 	start_thread(thj);
1279*86d7f5d3SJohn Marino 
1280*86d7f5d3SJohn Marino 	/* Tell main we received the start and are running */
1281*86d7f5d3SJohn Marino 	wakeup_with(l2m[1]);
1282*86d7f5d3SJohn Marino 
1283*86d7f5d3SJohn Marino 	/* Main tells us to stop */
1284*86d7f5d3SJohn Marino 	wait_on(m2l[0]);
1285*86d7f5d3SJohn Marino 	stop_thread(thj);
1286*86d7f5d3SJohn Marino 
1287*86d7f5d3SJohn Marino 	/* Tell main we've finished */
1288*86d7f5d3SJohn Marino 	wakeup_with(l2m[1]);
1289*86d7f5d3SJohn Marino 	exit (0);
1290*86d7f5d3SJohn Marino }
1291*86d7f5d3SJohn Marino 
run_benchchild(int i,int j)1292*86d7f5d3SJohn Marino void run_benchchild(int i, int j)
1293*86d7f5d3SJohn Marino {
1294*86d7f5d3SJohn Marino 	struct thread *thi;
1295*86d7f5d3SJohn Marino 
1296*86d7f5d3SJohn Marino 	thi = &threadlist[i];
1297*86d7f5d3SJohn Marino 
1298*86d7f5d3SJohn Marino 	set_nice(ud.bench_nice);
1299*86d7f5d3SJohn Marino 	if (ud.do_rt)
1300*86d7f5d3SJohn Marino 		set_mlock();
1301*86d7f5d3SJohn Marino 	initialise_thread(i);
1302*86d7f5d3SJohn Marino 	/* Point the data table to the appropriate load being tested */
1303*86d7f5d3SJohn Marino 	thi->dt = &thi->benchmarks[j];
1304*86d7f5d3SJohn Marino 	initialise_thread_data(thi->dt);
1305*86d7f5d3SJohn Marino 	if (ud.do_rt)
1306*86d7f5d3SJohn Marino 		set_thread_fifo(thi->pthread, 95);
1307*86d7f5d3SJohn Marino 
1308*86d7f5d3SJohn Marino 	/* Tell main we're ready */
1309*86d7f5d3SJohn Marino 	wakeup_with(b2m[1]);
1310*86d7f5d3SJohn Marino 
1311*86d7f5d3SJohn Marino 	/* Main tells us we're ready */
1312*86d7f5d3SJohn Marino 	wait_on(m2b[0]);
1313*86d7f5d3SJohn Marino 	start_thread(thi);
1314*86d7f5d3SJohn Marino 
1315*86d7f5d3SJohn Marino 	/* Tell main we have started */
1316*86d7f5d3SJohn Marino 	wakeup_with(b2m[1]);
1317*86d7f5d3SJohn Marino 
1318*86d7f5d3SJohn Marino 	/* Main tells us to stop */
1319*86d7f5d3SJohn Marino 	wait_on(m2b[0]);
1320*86d7f5d3SJohn Marino 	stop_thread(thi);
1321*86d7f5d3SJohn Marino 
1322*86d7f5d3SJohn Marino 	if (ud.do_rt) {
1323*86d7f5d3SJohn Marino 		set_thread_normal(thi->pthread);
1324*86d7f5d3SJohn Marino 		set_munlock();
1325*86d7f5d3SJohn Marino 	}
1326*86d7f5d3SJohn Marino 	show_latencies(thi);
1327*86d7f5d3SJohn Marino 
1328*86d7f5d3SJohn Marino 	/* Tell main we've finished */
1329*86d7f5d3SJohn Marino 	wakeup_with(b2m[1]);
1330*86d7f5d3SJohn Marino 	exit(0);
1331*86d7f5d3SJohn Marino }
1332*86d7f5d3SJohn Marino 
bench(int i,int j)1333*86d7f5d3SJohn Marino void bench(int i, int j)
1334*86d7f5d3SJohn Marino {
1335*86d7f5d3SJohn Marino 	pid_t bench_pid, load_pid;
1336*86d7f5d3SJohn Marino 
1337*86d7f5d3SJohn Marino 	if ((load_pid = fork()) == -1)
1338*86d7f5d3SJohn Marino 		terminal_error("fork");
1339*86d7f5d3SJohn Marino 	if (!load_pid)
1340*86d7f5d3SJohn Marino 		run_loadchild(j);
1341*86d7f5d3SJohn Marino 
1342*86d7f5d3SJohn Marino 	/* Wait for load process to be ready */
1343*86d7f5d3SJohn Marino 
1344*86d7f5d3SJohn Marino 	wait_on(l2m[0]);
1345*86d7f5d3SJohn Marino 	if ((bench_pid = fork()) == -1)
1346*86d7f5d3SJohn Marino 		terminal_error("fork");
1347*86d7f5d3SJohn Marino 	if (!bench_pid)
1348*86d7f5d3SJohn Marino 		run_benchchild(i, j);
1349*86d7f5d3SJohn Marino 
1350*86d7f5d3SJohn Marino 	/* Wait for bench process to be ready */
1351*86d7f5d3SJohn Marino 	wait_on(b2m[0]);
1352*86d7f5d3SJohn Marino 
1353*86d7f5d3SJohn Marino 	/*
1354*86d7f5d3SJohn Marino 	 * We want to be higher priority than everything to signal them to
1355*86d7f5d3SJohn Marino 	 * stop and we lock our memory if we can as well
1356*86d7f5d3SJohn Marino 	 */
1357*86d7f5d3SJohn Marino 	set_fifo(99);
1358*86d7f5d3SJohn Marino 	set_mlock();
1359*86d7f5d3SJohn Marino 
1360*86d7f5d3SJohn Marino 	/* Wakeup the load process */
1361*86d7f5d3SJohn Marino 	wakeup_with(m2l[1]);
1362*86d7f5d3SJohn Marino 	/* Load tells it has received the first message and is running */
1363*86d7f5d3SJohn Marino 	wait_on(l2m[0]);
1364*86d7f5d3SJohn Marino 
1365*86d7f5d3SJohn Marino 	/* After a small delay, wake up the benched process */
1366*86d7f5d3SJohn Marino 	sleep(1);
1367*86d7f5d3SJohn Marino 	wakeup_with(m2b[1]);
1368*86d7f5d3SJohn Marino 
1369*86d7f5d3SJohn Marino 	/* Bench tells it has received the first message and is running */
1370*86d7f5d3SJohn Marino 	wait_on(b2m[0]);
1371*86d7f5d3SJohn Marino 	microsleep(ud.duration * 1000000);
1372*86d7f5d3SJohn Marino 
1373*86d7f5d3SJohn Marino 	/* Tell the benched process to stop its threads and output results */
1374*86d7f5d3SJohn Marino 	wakeup_with(m2b[1]);
1375*86d7f5d3SJohn Marino 
1376*86d7f5d3SJohn Marino 	/* Tell the load process to stop its threads */
1377*86d7f5d3SJohn Marino 	wakeup_with(m2l[1]);
1378*86d7f5d3SJohn Marino 
1379*86d7f5d3SJohn Marino 	/* Return to SCHED_NORMAL */
1380*86d7f5d3SJohn Marino 	set_normal();
1381*86d7f5d3SJohn Marino 	set_munlock();
1382*86d7f5d3SJohn Marino 
1383*86d7f5d3SJohn Marino 	/* Wait for load and bench processes to terminate */
1384*86d7f5d3SJohn Marino 	wait_on(l2m[0]);
1385*86d7f5d3SJohn Marino 	wait_on(b2m[0]);
1386*86d7f5d3SJohn Marino }
1387*86d7f5d3SJohn Marino 
init_pipe(int * pype)1388*86d7f5d3SJohn Marino void init_pipe(int *pype)
1389*86d7f5d3SJohn Marino {
1390*86d7f5d3SJohn Marino 	if (pipe(pype) == -1)
1391*86d7f5d3SJohn Marino 		terminal_error("pipe");
1392*86d7f5d3SJohn Marino }
1393*86d7f5d3SJohn Marino 
init_pipes(void)1394*86d7f5d3SJohn Marino void init_pipes(void)
1395*86d7f5d3SJohn Marino {
1396*86d7f5d3SJohn Marino 	init_pipe(m2l);
1397*86d7f5d3SJohn Marino 	init_pipe(l2m);
1398*86d7f5d3SJohn Marino 	init_pipe(m2b);
1399*86d7f5d3SJohn Marino 	init_pipe(b2m);
1400*86d7f5d3SJohn Marino }
1401*86d7f5d3SJohn Marino 
usage(void)1402*86d7f5d3SJohn Marino void usage(void)
1403*86d7f5d3SJohn Marino {
1404*86d7f5d3SJohn Marino 	/* Affinity commented out till working on all architectures */
1405*86d7f5d3SJohn Marino 	fprintf(stderr, "interbench v " INTERBENCH_VERSION " by Con Kolivas\n");
1406*86d7f5d3SJohn Marino 	fprintf(stderr, "interbench [-l <int>] [-L <int>] [-t <int] [-B <int>] [-N <int>]\n");
1407*86d7f5d3SJohn Marino 	fprintf(stderr, "\t[-b] [-c] [-r] [-C <int> -I <int>] [-m <comment>]\n");
1408*86d7f5d3SJohn Marino 	fprintf(stderr, "\t[-w <load type>] [-x <load type>] [-W <bench>] [-X <bench>]\n");
1409*86d7f5d3SJohn Marino 	fprintf(stderr, "\t[-h]\n\n");
1410*86d7f5d3SJohn Marino 	fprintf(stderr, " -l\tUse <int> loops per sec (default: use saved benchmark)\n");
1411*86d7f5d3SJohn Marino 	fprintf(stderr, " -L\tUse cpu load of <int> with burn load (default: 4)\n");
1412*86d7f5d3SJohn Marino 	fprintf(stderr, " -t\tSeconds to run each benchmark (default: 30)\n");
1413*86d7f5d3SJohn Marino 	fprintf(stderr, " -B\tNice the benchmarked thread to <int> (default: 0)\n");
1414*86d7f5d3SJohn Marino 	fprintf(stderr, " -N\tNice the load thread to <int> (default: 0)\n");
1415*86d7f5d3SJohn Marino 	//fprintf(stderr, " -u\tImitate uniprocessor\n");
1416*86d7f5d3SJohn Marino 	fprintf(stderr, " -b\tBenchmark loops_per_ms even if it is already known\n");
1417*86d7f5d3SJohn Marino 	fprintf(stderr, " -c\tOutput to console only (default: use console and logfile)\n");
1418*86d7f5d3SJohn Marino 	fprintf(stderr, " -r\tPerform real time scheduling benchmarks (default: non-rt)\n");
1419*86d7f5d3SJohn Marino 	fprintf(stderr, " -C\tUse <int> percentage cpu as a custom load (default: no custom load)\n");
1420*86d7f5d3SJohn Marino 	fprintf(stderr, " -I\tUse <int> microsecond intervals for custom load (needs -C as well)\n");
1421*86d7f5d3SJohn Marino 	fprintf(stderr, " -m\tAdd <comment> to the log file as a separate line\n");
1422*86d7f5d3SJohn Marino 	fprintf(stderr, " -w\tAdd <load type> to the list of loads to be tested against\n");
1423*86d7f5d3SJohn Marino 	fprintf(stderr, " -x\tExclude <load type> from the list of loads to be tested against\n");
1424*86d7f5d3SJohn Marino 	fprintf(stderr, " -W\tAdd <bench> to the list of benchmarks to be tested\n");
1425*86d7f5d3SJohn Marino 	fprintf(stderr, " -X\tExclude <bench> from the list of benchmarks to be tested\n");
1426*86d7f5d3SJohn Marino 	fprintf(stderr, " -h\tShow this help\n");
1427*86d7f5d3SJohn Marino 	fprintf(stderr, "\nIf run without parameters interbench will run a standard benchmark\n\n");
1428*86d7f5d3SJohn Marino }
1429*86d7f5d3SJohn Marino 
1430*86d7f5d3SJohn Marino #ifdef DEBUG
deadchild(int crap)1431*86d7f5d3SJohn Marino void deadchild(int crap)
1432*86d7f5d3SJohn Marino {
1433*86d7f5d3SJohn Marino 	pid_t retval;
1434*86d7f5d3SJohn Marino 	int status;
1435*86d7f5d3SJohn Marino 
1436*86d7f5d3SJohn Marino 	crap = 0;
1437*86d7f5d3SJohn Marino 
1438*86d7f5d3SJohn Marino 	if ((retval = waitpid(-1, &status, WNOHANG)) == -1) {
1439*86d7f5d3SJohn Marino 		if (errno == ECHILD)
1440*86d7f5d3SJohn Marino 			return;
1441*86d7f5d3SJohn Marino 		terminal_error("waitpid");
1442*86d7f5d3SJohn Marino 	}
1443*86d7f5d3SJohn Marino 	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
1444*86d7f5d3SJohn Marino 		return;
1445*86d7f5d3SJohn Marino 	fprintf(stderr, "\nChild terminated abnormally ");
1446*86d7f5d3SJohn Marino 	if (WIFSIGNALED(status))
1447*86d7f5d3SJohn Marino 		fprintf(stderr, "with signal %d", WTERMSIG(status));
1448*86d7f5d3SJohn Marino 	fprintf(stderr, "\n");
1449*86d7f5d3SJohn Marino 	exit (1);
1450*86d7f5d3SJohn Marino }
1451*86d7f5d3SJohn Marino #endif
1452*86d7f5d3SJohn Marino 
load_index(const char * loadname)1453*86d7f5d3SJohn Marino int load_index(const char* loadname)
1454*86d7f5d3SJohn Marino {
1455*86d7f5d3SJohn Marino 	int i;
1456*86d7f5d3SJohn Marino 
1457*86d7f5d3SJohn Marino 	for (i = 0 ; i < THREADS ; i++)
1458*86d7f5d3SJohn Marino 		if (strcasecmp(loadname, threadlist[i].label) == 0)
1459*86d7f5d3SJohn Marino 			return i;
1460*86d7f5d3SJohn Marino 	return -1;
1461*86d7f5d3SJohn Marino }
1462*86d7f5d3SJohn Marino 
bit_is_on(const unsigned int mask,int index)1463*86d7f5d3SJohn Marino inline int bit_is_on(const unsigned int mask, int index)
1464*86d7f5d3SJohn Marino {
1465*86d7f5d3SJohn Marino 	return (mask & (1 << index)) != 0;
1466*86d7f5d3SJohn Marino }
1467*86d7f5d3SJohn Marino 
set_bit_on(unsigned int * mask,int index)1468*86d7f5d3SJohn Marino inline void set_bit_on(unsigned int *mask, int index)
1469*86d7f5d3SJohn Marino {
1470*86d7f5d3SJohn Marino 	*mask |= (1 << index);
1471*86d7f5d3SJohn Marino }
1472*86d7f5d3SJohn Marino 
main(int argc,char ** argv)1473*86d7f5d3SJohn Marino int main(int argc, char **argv)
1474*86d7f5d3SJohn Marino {
1475*86d7f5d3SJohn Marino 	unsigned long custom_cpu = 0;
1476*86d7f5d3SJohn Marino 	int q, i, j, affinity, benchmark = 0;
1477*86d7f5d3SJohn Marino 	unsigned int selected_loads = 0;
1478*86d7f5d3SJohn Marino 	unsigned int excluded_loads = 0;
1479*86d7f5d3SJohn Marino 	unsigned int selected_benches = 0;
1480*86d7f5d3SJohn Marino 	unsigned int excluded_benches = 0;
1481*86d7f5d3SJohn Marino 	FILE *fp;
1482*86d7f5d3SJohn Marino 	/*
1483*86d7f5d3SJohn Marino 	 * This file stores the loops_per_ms to be reused in a filename that
1484*86d7f5d3SJohn Marino 	 * can't be confused
1485*86d7f5d3SJohn Marino 	 */
1486*86d7f5d3SJohn Marino 	char *fname = "interbench.loops_per_ms";
1487*86d7f5d3SJohn Marino 	char *comment = NULL;
1488*86d7f5d3SJohn Marino #ifdef DEBUG
1489*86d7f5d3SJohn Marino 	feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
1490*86d7f5d3SJohn Marino 	if (signal(SIGCHLD, deadchild) == SIG_ERR)
1491*86d7f5d3SJohn Marino 		terminal_error("signal");
1492*86d7f5d3SJohn Marino #endif
1493*86d7f5d3SJohn Marino 
1494*86d7f5d3SJohn Marino 	while ((q = getopt(argc, argv, "hl:L:B:N:ut:bcnrC:I:m:w:x:W:X:")) != -1) {
1495*86d7f5d3SJohn Marino 		switch (q) {
1496*86d7f5d3SJohn Marino 			case 'h':
1497*86d7f5d3SJohn Marino 				usage();
1498*86d7f5d3SJohn Marino 				return (0);
1499*86d7f5d3SJohn Marino 			case 'l':
1500*86d7f5d3SJohn Marino 				ud.loops_per_ms = atoi(optarg);
1501*86d7f5d3SJohn Marino 				break;
1502*86d7f5d3SJohn Marino 			case 't':
1503*86d7f5d3SJohn Marino 				ud.duration = atoi(optarg);
1504*86d7f5d3SJohn Marino 				break;
1505*86d7f5d3SJohn Marino 			case 'L':
1506*86d7f5d3SJohn Marino 				ud.cpu_load = atoi(optarg);
1507*86d7f5d3SJohn Marino 				break;
1508*86d7f5d3SJohn Marino 			case 'B':
1509*86d7f5d3SJohn Marino 				ud.bench_nice = atoi(optarg);
1510*86d7f5d3SJohn Marino 				break;
1511*86d7f5d3SJohn Marino 			case 'N':
1512*86d7f5d3SJohn Marino 				ud.load_nice = atoi(optarg);
1513*86d7f5d3SJohn Marino 				break;
1514*86d7f5d3SJohn Marino 			case 'u':
1515*86d7f5d3SJohn Marino 				affinity = 1;
1516*86d7f5d3SJohn Marino 				break;
1517*86d7f5d3SJohn Marino 			case 'b':
1518*86d7f5d3SJohn Marino 				benchmark = 1;
1519*86d7f5d3SJohn Marino 				break;
1520*86d7f5d3SJohn Marino 			case 'c':
1521*86d7f5d3SJohn Marino 				ud.log = 0;
1522*86d7f5d3SJohn Marino 				break;
1523*86d7f5d3SJohn Marino 			case 'r':
1524*86d7f5d3SJohn Marino 				ud.do_rt = 1;
1525*86d7f5d3SJohn Marino 				break;
1526*86d7f5d3SJohn Marino 			case 'C':
1527*86d7f5d3SJohn Marino 				custom_cpu = (unsigned long)atol(optarg);
1528*86d7f5d3SJohn Marino 				break;
1529*86d7f5d3SJohn Marino 			case 'I':
1530*86d7f5d3SJohn Marino 				ud.custom_interval = atol(optarg);
1531*86d7f5d3SJohn Marino 				break;
1532*86d7f5d3SJohn Marino 			case 'm':
1533*86d7f5d3SJohn Marino 				comment = optarg;
1534*86d7f5d3SJohn Marino 				break;
1535*86d7f5d3SJohn Marino 			case 'w':
1536*86d7f5d3SJohn Marino 				i = load_index(optarg);
1537*86d7f5d3SJohn Marino 				if (i == -1) {
1538*86d7f5d3SJohn Marino 					fprintf(stderr, "Unknown load \"%s\"\n", optarg);
1539*86d7f5d3SJohn Marino 					return (-2);
1540*86d7f5d3SJohn Marino 				}
1541*86d7f5d3SJohn Marino 				set_bit_on(&selected_loads, i);
1542*86d7f5d3SJohn Marino 				break;
1543*86d7f5d3SJohn Marino 			case 'x':
1544*86d7f5d3SJohn Marino 				i = load_index(optarg);
1545*86d7f5d3SJohn Marino 				if (i == -1) {
1546*86d7f5d3SJohn Marino 					fprintf(stderr, "Unknown load \"%s\"\n", optarg);
1547*86d7f5d3SJohn Marino 					return (-2);
1548*86d7f5d3SJohn Marino 				}
1549*86d7f5d3SJohn Marino 				set_bit_on(&excluded_loads, i);
1550*86d7f5d3SJohn Marino 				break;
1551*86d7f5d3SJohn Marino 			case 'W':
1552*86d7f5d3SJohn Marino 				i = load_index(optarg);
1553*86d7f5d3SJohn Marino 				if (i == -1) {
1554*86d7f5d3SJohn Marino 					fprintf(stderr, "Unknown bench \"%s\"\n", optarg);
1555*86d7f5d3SJohn Marino 					return (-2);
1556*86d7f5d3SJohn Marino 				}
1557*86d7f5d3SJohn Marino 				set_bit_on(&selected_benches, i);
1558*86d7f5d3SJohn Marino 				break;
1559*86d7f5d3SJohn Marino 			case 'X':
1560*86d7f5d3SJohn Marino 				i = load_index(optarg);
1561*86d7f5d3SJohn Marino 				if (i == -1) {
1562*86d7f5d3SJohn Marino 					fprintf(stderr, "Unknown bench \"%s\"\n", optarg);
1563*86d7f5d3SJohn Marino 					return (-2);
1564*86d7f5d3SJohn Marino 				}
1565*86d7f5d3SJohn Marino 				set_bit_on(&excluded_benches, i);
1566*86d7f5d3SJohn Marino 				break;
1567*86d7f5d3SJohn Marino 			default:
1568*86d7f5d3SJohn Marino 				usage();
1569*86d7f5d3SJohn Marino 				return (1);
1570*86d7f5d3SJohn Marino 		}
1571*86d7f5d3SJohn Marino 	}
1572*86d7f5d3SJohn Marino 	argc -= optind;
1573*86d7f5d3SJohn Marino 	argv += optind;
1574*86d7f5d3SJohn Marino 	/* default is all loads */
1575*86d7f5d3SJohn Marino 	if (selected_loads == 0)
1576*86d7f5d3SJohn Marino 		selected_loads = (unsigned int)-1;
1577*86d7f5d3SJohn Marino 	selected_loads &= ~excluded_loads;
1578*86d7f5d3SJohn Marino 	/* default is all benches */
1579*86d7f5d3SJohn Marino 	if (selected_benches == 0)
1580*86d7f5d3SJohn Marino 		selected_benches = (unsigned int)-1;
1581*86d7f5d3SJohn Marino 	selected_benches &= ~excluded_benches;
1582*86d7f5d3SJohn Marino 
1583*86d7f5d3SJohn Marino 	if (!test_fifo()) {
1584*86d7f5d3SJohn Marino 		fprintf(stderr, "Unable to get SCHED_FIFO (real time scheduling).\n");
1585*86d7f5d3SJohn Marino 		fprintf(stderr, "You either need to run this as root user or have support for real time RLIMITS.\n");
1586*86d7f5d3SJohn Marino 		if (ud.do_rt) {
1587*86d7f5d3SJohn Marino 			fprintf(stderr, "Real time tests were requested, aborting.\n");
1588*86d7f5d3SJohn Marino 			exit (1);
1589*86d7f5d3SJohn Marino 		}
1590*86d7f5d3SJohn Marino 		fprintf(stderr, "Results will be unreliable.\n");
1591*86d7f5d3SJohn Marino 	}
1592*86d7f5d3SJohn Marino 	if (!ud.cpu_load) {
1593*86d7f5d3SJohn Marino 		fprintf(stderr, "Invalid cpu load\n");
1594*86d7f5d3SJohn Marino 		exit (1);
1595*86d7f5d3SJohn Marino 	}
1596*86d7f5d3SJohn Marino 
1597*86d7f5d3SJohn Marino 	if ((custom_cpu && !ud.custom_interval) ||
1598*86d7f5d3SJohn Marino 		(ud.custom_interval && !custom_cpu) ||
1599*86d7f5d3SJohn Marino 		custom_cpu > 100) {
1600*86d7f5d3SJohn Marino 			fprintf(stderr, "Invalid custom values, aborting.\n");
1601*86d7f5d3SJohn Marino 			exit (1);
1602*86d7f5d3SJohn Marino 	}
1603*86d7f5d3SJohn Marino 
1604*86d7f5d3SJohn Marino 	if (custom_cpu && ud.custom_interval) {
1605*86d7f5d3SJohn Marino 		ud.custom_run = ud.custom_interval * custom_cpu / 100;
1606*86d7f5d3SJohn Marino 		threadlist[CUSTOM].bench = 1;
1607*86d7f5d3SJohn Marino 		threadlist[CUSTOM].load = 1;
1608*86d7f5d3SJohn Marino 		threadlist[CUSTOM].rtbench = 1;
1609*86d7f5d3SJohn Marino 		threadlist[CUSTOM].rtload = 1;
1610*86d7f5d3SJohn Marino 	}
1611*86d7f5d3SJohn Marino 
1612*86d7f5d3SJohn Marino 	/*FIXME Affinity commented out till working on all architectures */
1613*86d7f5d3SJohn Marino #if 0
1614*86d7f5d3SJohn Marino 	if (affinity) {
1615*86d7f5d3SJohn Marino #ifdef CPU_SET	/* Current glibc expects cpu_set_t */
1616*86d7f5d3SJohn Marino 		cpu_set_t cpumask;
1617*86d7f5d3SJohn Marino 
1618*86d7f5d3SJohn Marino 		CPU_ZERO(&cpumask);
1619*86d7f5d3SJohn Marino 		CPU_SET(0, &cpumask);
1620*86d7f5d3SJohn Marino #else		/* Old glibc expects unsigned long */
1621*86d7f5d3SJohn Marino 		unsigned long cpumask = 1;
1622*86d7f5d3SJohn Marino #endif
1623*86d7f5d3SJohn Marino 		if (sched_setaffinity(0, sizeof(cpumask), &cpumask) == -1) {
1624*86d7f5d3SJohn Marino 			if (errno != EPERM)
1625*86d7f5d3SJohn Marino 				terminal_error("sched_setaffinity");
1626*86d7f5d3SJohn Marino 			fprintf(stderr, "could not set cpu affinity\n");
1627*86d7f5d3SJohn Marino 		}
1628*86d7f5d3SJohn Marino 	}
1629*86d7f5d3SJohn Marino #endif
1630*86d7f5d3SJohn Marino 
1631*86d7f5d3SJohn Marino 	/* Make benchmark a multiple of 10 seconds for proper range of X loads */
1632*86d7f5d3SJohn Marino 	if (ud.duration % 10)
1633*86d7f5d3SJohn Marino 		ud.duration += 10 - ud.duration % 10;
1634*86d7f5d3SJohn Marino 
1635*86d7f5d3SJohn Marino 	if (benchmark)
1636*86d7f5d3SJohn Marino 		ud.loops_per_ms = 0;
1637*86d7f5d3SJohn Marino 	/*
1638*86d7f5d3SJohn Marino 	 * Try to get loops_per_ms from command line first, file second, and
1639*86d7f5d3SJohn Marino 	 * benchmark if not available.
1640*86d7f5d3SJohn Marino 	 */
1641*86d7f5d3SJohn Marino 	if (!ud.loops_per_ms) {
1642*86d7f5d3SJohn Marino 		if (benchmark)
1643*86d7f5d3SJohn Marino 			goto bench;
1644*86d7f5d3SJohn Marino 		if ((fp = fopen(fname, "r"))) {
1645*86d7f5d3SJohn Marino 			fscanf(fp, "%lu", &ud.loops_per_ms);
1646*86d7f5d3SJohn Marino 			if (fclose(fp) == -1)
1647*86d7f5d3SJohn Marino 				terminal_error("fclose");
1648*86d7f5d3SJohn Marino 			if (ud.loops_per_ms) {
1649*86d7f5d3SJohn Marino 				fprintf(stderr,
1650*86d7f5d3SJohn Marino 					"%lu loops_per_ms read from file interbench.loops_per_ms\n",
1651*86d7f5d3SJohn Marino 					ud.loops_per_ms);
1652*86d7f5d3SJohn Marino 				goto loops_known;
1653*86d7f5d3SJohn Marino 			}
1654*86d7f5d3SJohn Marino 		} else
1655*86d7f5d3SJohn Marino 			if (errno != ENOENT)
1656*86d7f5d3SJohn Marino 				terminal_error("fopen");
1657*86d7f5d3SJohn Marino bench:
1658*86d7f5d3SJohn Marino 		fprintf(stderr, "loops_per_ms unknown; benchmarking...\n");
1659*86d7f5d3SJohn Marino 
1660*86d7f5d3SJohn Marino 		/*
1661*86d7f5d3SJohn Marino 		 * To get as accurate a loop as possible we time it running
1662*86d7f5d3SJohn Marino 		 * SCHED_FIFO if we can
1663*86d7f5d3SJohn Marino 		 */
1664*86d7f5d3SJohn Marino 		set_fifo(99);
1665*86d7f5d3SJohn Marino 		calibrate_loop();
1666*86d7f5d3SJohn Marino 		set_normal();
1667*86d7f5d3SJohn Marino 	} else
1668*86d7f5d3SJohn Marino 		fprintf(stderr, "loops_per_ms specified from command line\n");
1669*86d7f5d3SJohn Marino 
1670*86d7f5d3SJohn Marino 	if (!(fp = fopen(fname, "w"))) {
1671*86d7f5d3SJohn Marino 		if (errno != EACCES)	/* No write access is not terminal */
1672*86d7f5d3SJohn Marino 			terminal_error("fopen");
1673*86d7f5d3SJohn Marino 		fprintf(stderr, "Unable to write to file interbench.loops_per_ms\n");
1674*86d7f5d3SJohn Marino 		goto loops_known;
1675*86d7f5d3SJohn Marino 	}
1676*86d7f5d3SJohn Marino 	fprintf(fp, "%lu", ud.loops_per_ms);
1677*86d7f5d3SJohn Marino 	fprintf(stderr, "%lu loops_per_ms saved to file interbench.loops_per_ms\n",
1678*86d7f5d3SJohn Marino 		ud.loops_per_ms);
1679*86d7f5d3SJohn Marino 	if (fclose(fp) == -1)
1680*86d7f5d3SJohn Marino 		terminal_error("fclose");
1681*86d7f5d3SJohn Marino 
1682*86d7f5d3SJohn Marino loops_known:
1683*86d7f5d3SJohn Marino 	get_ram();
1684*86d7f5d3SJohn Marino 	get_logfilename();
1685*86d7f5d3SJohn Marino 	create_read_file();
1686*86d7f5d3SJohn Marino 	init_pipes();
1687*86d7f5d3SJohn Marino 
1688*86d7f5d3SJohn Marino 	if (ud.log && !(ud.logfile = fopen(ud.logfilename, "a"))) {
1689*86d7f5d3SJohn Marino 		if (errno != EACCES)
1690*86d7f5d3SJohn Marino 			terminal_error("fopen");
1691*86d7f5d3SJohn Marino 		fprintf(stderr, "Unable to write to logfile\n");
1692*86d7f5d3SJohn Marino 		ud.log = 0;
1693*86d7f5d3SJohn Marino 	}
1694*86d7f5d3SJohn Marino 	log_output("\n");
1695*86d7f5d3SJohn Marino 	log_output("Using %lu loops per ms, running every load for %d seconds\n",
1696*86d7f5d3SJohn Marino 		ud.loops_per_ms, ud.duration);
1697*86d7f5d3SJohn Marino 	log_output("Benchmarking kernel %s at datestamp %s\n",
1698*86d7f5d3SJohn Marino 		ud.unamer, ud.datestamp);
1699*86d7f5d3SJohn Marino 	if (comment)
1700*86d7f5d3SJohn Marino 		log_output("Comment: %s\n", comment);
1701*86d7f5d3SJohn Marino 	log_output("\n");
1702*86d7f5d3SJohn Marino 
1703*86d7f5d3SJohn Marino 	for (i = 0 ; i < THREADS ; i++)
1704*86d7f5d3SJohn Marino 		threadlist[i].threadno = i;
1705*86d7f5d3SJohn Marino 
1706*86d7f5d3SJohn Marino 	for (i = 0 ; i < THREADS ; i++) {
1707*86d7f5d3SJohn Marino 		struct thread *thi = &threadlist[i];
1708*86d7f5d3SJohn Marino 		int *benchme;
1709*86d7f5d3SJohn Marino 
1710*86d7f5d3SJohn Marino 		if (ud.do_rt)
1711*86d7f5d3SJohn Marino 			benchme = &threadlist[i].rtbench;
1712*86d7f5d3SJohn Marino 		else
1713*86d7f5d3SJohn Marino 			benchme = &threadlist[i].bench;
1714*86d7f5d3SJohn Marino 
1715*86d7f5d3SJohn Marino 		if (!*benchme || !bit_is_on(selected_benches, i))
1716*86d7f5d3SJohn Marino 			continue;
1717*86d7f5d3SJohn Marino 
1718*86d7f5d3SJohn Marino 		log_output("--- Benchmarking simulated cpu of %s ", threadlist[i].label);
1719*86d7f5d3SJohn Marino 		if (ud.do_rt)
1720*86d7f5d3SJohn Marino 			log_output("real time ");
1721*86d7f5d3SJohn Marino 		else if (ud.bench_nice)
1722*86d7f5d3SJohn Marino 			log_output("nice %d ", ud.bench_nice);
1723*86d7f5d3SJohn Marino 		log_output("in the presence of simulated ");
1724*86d7f5d3SJohn Marino 		if (ud.load_nice)
1725*86d7f5d3SJohn Marino 			log_output("nice %d ", ud.load_nice);
1726*86d7f5d3SJohn Marino 		log_output("---\n");
1727*86d7f5d3SJohn Marino 
1728*86d7f5d3SJohn Marino 		log_output("Load");
1729*86d7f5d3SJohn Marino 		if (ud.do_rt)
1730*86d7f5d3SJohn Marino 			log_output("\tLatency +/- SD (us)");
1731*86d7f5d3SJohn Marino 		else
1732*86d7f5d3SJohn Marino 			log_output("\tLatency +/- SD (ms)");
1733*86d7f5d3SJohn Marino 		log_output("  Max Latency ");
1734*86d7f5d3SJohn Marino 		log_output("  %% Desired CPU");
1735*86d7f5d3SJohn Marino 		if (!thi->nodeadlines)
1736*86d7f5d3SJohn Marino 			log_output("  %% Deadlines Met");
1737*86d7f5d3SJohn Marino 		log_output("\n");
1738*86d7f5d3SJohn Marino 
1739*86d7f5d3SJohn Marino 		for (j = 0 ; j < THREADS ; j++) {
1740*86d7f5d3SJohn Marino 			struct thread *thj = &threadlist[j];
1741*86d7f5d3SJohn Marino 
1742*86d7f5d3SJohn Marino 			if (j == i || !bit_is_on(selected_loads, j) ||
1743*86d7f5d3SJohn Marino 				(!threadlist[j].load && !ud.do_rt) ||
1744*86d7f5d3SJohn Marino 				(!threadlist[j].rtload && ud.do_rt))
1745*86d7f5d3SJohn Marino 					continue;
1746*86d7f5d3SJohn Marino 			log_output("%s\t", thj->label);
1747*86d7f5d3SJohn Marino 			sync_flush();
1748*86d7f5d3SJohn Marino 			bench(i, j);
1749*86d7f5d3SJohn Marino 		}
1750*86d7f5d3SJohn Marino 		log_output("\n");
1751*86d7f5d3SJohn Marino 	}
1752*86d7f5d3SJohn Marino 	log_output("\n");
1753*86d7f5d3SJohn Marino 	if (ud.log)
1754*86d7f5d3SJohn Marino 		fclose(ud.logfile);
1755*86d7f5d3SJohn Marino 
1756*86d7f5d3SJohn Marino 	return 0;
1757*86d7f5d3SJohn Marino }
1758