xref: /aosp_15_r20/external/ltp/testcases/kernel/sched/tool/time-schedule.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker /*  time-schedule.c
2*49cdfc7eSAndroid Build Coastguard Worker 
3*49cdfc7eSAndroid Build Coastguard Worker     Programme to test how long a context switch takes.
4*49cdfc7eSAndroid Build Coastguard Worker 
5*49cdfc7eSAndroid Build Coastguard Worker     Copyright (C) 1998  Richard Gooch
6*49cdfc7eSAndroid Build Coastguard Worker 
7*49cdfc7eSAndroid Build Coastguard Worker     This program is free software; you can redistribute it and/or modify
8*49cdfc7eSAndroid Build Coastguard Worker     it under the terms of the GNU General Public License as published by
9*49cdfc7eSAndroid Build Coastguard Worker     the Free Software Foundation; either version 2 of the License, or
10*49cdfc7eSAndroid Build Coastguard Worker     (at your option) any later version.
11*49cdfc7eSAndroid Build Coastguard Worker 
12*49cdfc7eSAndroid Build Coastguard Worker     This program is distributed in the hope that it will be useful,
13*49cdfc7eSAndroid Build Coastguard Worker     but WITHOUT ANY WARRANTY; without even the implied warranty of
14*49cdfc7eSAndroid Build Coastguard Worker     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*49cdfc7eSAndroid Build Coastguard Worker     GNU General Public License for more details.
16*49cdfc7eSAndroid Build Coastguard Worker 
17*49cdfc7eSAndroid Build Coastguard Worker     You should have received a copy of the GNU General Public License
18*49cdfc7eSAndroid Build Coastguard Worker     along with this program; if not, write to the Free Software
19*49cdfc7eSAndroid Build Coastguard Worker     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20*49cdfc7eSAndroid Build Coastguard Worker 
21*49cdfc7eSAndroid Build Coastguard Worker     Richard Gooch may be reached by email at  [email protected]
22*49cdfc7eSAndroid Build Coastguard Worker     The postal address is:
23*49cdfc7eSAndroid Build Coastguard Worker       Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
24*49cdfc7eSAndroid Build Coastguard Worker */
25*49cdfc7eSAndroid Build Coastguard Worker 
26*49cdfc7eSAndroid Build Coastguard Worker /*
27*49cdfc7eSAndroid Build Coastguard Worker     This programme will determine the context switch (scheduling) overhead on
28*49cdfc7eSAndroid Build Coastguard Worker     a system. It takes into account SMP machines. True context switches are
29*49cdfc7eSAndroid Build Coastguard Worker     measured.
30*49cdfc7eSAndroid Build Coastguard Worker 
31*49cdfc7eSAndroid Build Coastguard Worker     Written by      Richard Gooch   15-SEP-1998
32*49cdfc7eSAndroid Build Coastguard Worker 
33*49cdfc7eSAndroid Build Coastguard Worker     Last updated by Richard Gooch   25-SEP-1998
34*49cdfc7eSAndroid Build Coastguard Worker 
35*49cdfc7eSAndroid Build Coastguard Worker */
36*49cdfc7eSAndroid Build Coastguard Worker #include <unistd.h>
37*49cdfc7eSAndroid Build Coastguard Worker #ifdef _POSIX_THREADS
38*49cdfc7eSAndroid Build Coastguard Worker #ifndef _REENTRANT
39*49cdfc7eSAndroid Build Coastguard Worker #define _REENTRANT
40*49cdfc7eSAndroid Build Coastguard Worker #endif
41*49cdfc7eSAndroid Build Coastguard Worker #ifndef _POSIX_THREAD_SAFE_FUNCTIONS
42*49cdfc7eSAndroid Build Coastguard Worker #define _POSIX_THREAD_SAFE_FUNCTIONS
43*49cdfc7eSAndroid Build Coastguard Worker #endif
44*49cdfc7eSAndroid Build Coastguard Worker #include <pthread.h>
45*49cdfc7eSAndroid Build Coastguard Worker #endif
46*49cdfc7eSAndroid Build Coastguard Worker #include <stdlib.h>
47*49cdfc7eSAndroid Build Coastguard Worker #include <stdio.h>
48*49cdfc7eSAndroid Build Coastguard Worker #include <math.h>
49*49cdfc7eSAndroid Build Coastguard Worker #include <string.h>
50*49cdfc7eSAndroid Build Coastguard Worker #include <ctype.h>
51*49cdfc7eSAndroid Build Coastguard Worker #include <signal.h>
52*49cdfc7eSAndroid Build Coastguard Worker #include <sched.h>
53*49cdfc7eSAndroid Build Coastguard Worker #include <sys/time.h>
54*49cdfc7eSAndroid Build Coastguard Worker #include <sys/mman.h>
55*49cdfc7eSAndroid Build Coastguard Worker #include <sys/types.h>
56*49cdfc7eSAndroid Build Coastguard Worker #include <dirent.h>
57*49cdfc7eSAndroid Build Coastguard Worker #include <errno.h>
58*49cdfc7eSAndroid Build Coastguard Worker 
59*49cdfc7eSAndroid Build Coastguard Worker #ifndef __KARMA__
60*49cdfc7eSAndroid Build Coastguard Worker #define mt_num_processors() 1	/*  Set to the number of processors   */
61*49cdfc7eSAndroid Build Coastguard Worker #define ERRSTRING strerror(errno)
62*49cdfc7eSAndroid Build Coastguard Worker #define FALSE 0
63*49cdfc7eSAndroid Build Coastguard Worker #define TRUE  1
64*49cdfc7eSAndroid Build Coastguard Worker #else
65*49cdfc7eSAndroid Build Coastguard Worker #include <karma.h>
66*49cdfc7eSAndroid Build Coastguard Worker #include <karma_mt.h>
67*49cdfc7eSAndroid Build Coastguard Worker #endif
68*49cdfc7eSAndroid Build Coastguard Worker 
69*49cdfc7eSAndroid Build Coastguard Worker #define MAX_ITERATIONS      1000
70*49cdfc7eSAndroid Build Coastguard Worker 
71*49cdfc7eSAndroid Build Coastguard Worker static unsigned int hog_other_cpus();
72*49cdfc7eSAndroid Build Coastguard Worker static void run_yielder(int use_threads, int read_fd);
73*49cdfc7eSAndroid Build Coastguard Worker static void *yielder_main(void *arg);
74*49cdfc7eSAndroid Build Coastguard Worker static void s_term_handler();
75*49cdfc7eSAndroid Build Coastguard Worker static void run_low_priority(unsigned int num, int read_fd);
76*49cdfc7eSAndroid Build Coastguard Worker static unsigned long compute_median(unsigned long values[MAX_ITERATIONS],
77*49cdfc7eSAndroid Build Coastguard Worker 				    unsigned long max_value);
78*49cdfc7eSAndroid Build Coastguard Worker static unsigned int get_run_queue_size();
79*49cdfc7eSAndroid Build Coastguard Worker static unsigned long get_num_switches();
80*49cdfc7eSAndroid Build Coastguard Worker static void use_fpu_value(double val);
81*49cdfc7eSAndroid Build Coastguard Worker 
82*49cdfc7eSAndroid Build Coastguard Worker static volatile unsigned int sched_count = 0;
83*49cdfc7eSAndroid Build Coastguard Worker /*  For yielder  */
84*49cdfc7eSAndroid Build Coastguard Worker static int pipe_read_fd = -1;
85*49cdfc7eSAndroid Build Coastguard Worker static int pipe_write_fd = -1;
86*49cdfc7eSAndroid Build Coastguard Worker static pid_t child = -1;
87*49cdfc7eSAndroid Build Coastguard Worker 
main(int argc,char ** argv)88*49cdfc7eSAndroid Build Coastguard Worker int main(int argc, char **argv)
89*49cdfc7eSAndroid Build Coastguard Worker {
90*49cdfc7eSAndroid Build Coastguard Worker 	int use_threads = FALSE;
91*49cdfc7eSAndroid Build Coastguard Worker 	int use_pipe = FALSE;
92*49cdfc7eSAndroid Build Coastguard Worker 	int no_test = FALSE;
93*49cdfc7eSAndroid Build Coastguard Worker 	int frob_fpu = FALSE;
94*49cdfc7eSAndroid Build Coastguard Worker 	int read_fd = -1;
95*49cdfc7eSAndroid Build Coastguard Worker 	int write_fd = -1;
96*49cdfc7eSAndroid Build Coastguard Worker 	int num_low_priority = -1;
97*49cdfc7eSAndroid Build Coastguard Worker 	int i, j;
98*49cdfc7eSAndroid Build Coastguard Worker 	int fds[2];
99*49cdfc7eSAndroid Build Coastguard Worker 	unsigned int count, num_yields, run_queue_size1, run_queue_size2,
100*49cdfc7eSAndroid Build Coastguard Worker 	    num_hogs;
101*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long median, switches1, num_switches, num_overhead_switches;
102*49cdfc7eSAndroid Build Coastguard Worker 	signed long overhead, total_diffs;
103*49cdfc7eSAndroid Build Coastguard Worker 	signed long min_diff = 1000000000;
104*49cdfc7eSAndroid Build Coastguard Worker 	signed long max_diff = -1000000000;
105*49cdfc7eSAndroid Build Coastguard Worker 	double dcount = 0.0;
106*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long diffs[MAX_ITERATIONS];
107*49cdfc7eSAndroid Build Coastguard Worker 	struct timeval before, after;
108*49cdfc7eSAndroid Build Coastguard Worker 	sigset_t set;
109*49cdfc7eSAndroid Build Coastguard Worker 	static char *usage =
110*49cdfc7eSAndroid Build Coastguard Worker 	    "time-schedule [-h] [-thread] [-notest] [-pipe] [-fpu] [num_running]";
111*49cdfc7eSAndroid Build Coastguard Worker 
112*49cdfc7eSAndroid Build Coastguard Worker 	setpgrp();
113*49cdfc7eSAndroid Build Coastguard Worker 	/*  First create pipe used to sychronise low priority processes  */
114*49cdfc7eSAndroid Build Coastguard Worker 	if (pipe(fds) != 0) {
115*49cdfc7eSAndroid Build Coastguard Worker 		fprintf(stderr, "Error creating pipe\t%s\n", ERRSTRING);
116*49cdfc7eSAndroid Build Coastguard Worker 		exit(1);
117*49cdfc7eSAndroid Build Coastguard Worker 	}
118*49cdfc7eSAndroid Build Coastguard Worker 	read_fd = fds[0];
119*49cdfc7eSAndroid Build Coastguard Worker 	pipe_write_fd = fds[1];
120*49cdfc7eSAndroid Build Coastguard Worker 	for (count = 1; count < argc; ++count) {
121*49cdfc7eSAndroid Build Coastguard Worker 		if (strcmp(argv[count], "-thread") == 0) {
122*49cdfc7eSAndroid Build Coastguard Worker #ifdef _POSIX_THREADS
123*49cdfc7eSAndroid Build Coastguard Worker 			use_threads = TRUE;
124*49cdfc7eSAndroid Build Coastguard Worker #else
125*49cdfc7eSAndroid Build Coastguard Worker 			fprintf(stderr, "POSIX threads not available\n");
126*49cdfc7eSAndroid Build Coastguard Worker #endif
127*49cdfc7eSAndroid Build Coastguard Worker 		} else if (strcmp(argv[count], "-pipe") == 0)
128*49cdfc7eSAndroid Build Coastguard Worker 			use_pipe = TRUE;
129*49cdfc7eSAndroid Build Coastguard Worker 		else if (strcmp(argv[count], "-notest") == 0)
130*49cdfc7eSAndroid Build Coastguard Worker 			no_test = TRUE;
131*49cdfc7eSAndroid Build Coastguard Worker 		else if (strcmp(argv[count], "-fpu") == 0)
132*49cdfc7eSAndroid Build Coastguard Worker 			frob_fpu = TRUE;
133*49cdfc7eSAndroid Build Coastguard Worker 		else if (isdigit(argv[count][0]))
134*49cdfc7eSAndroid Build Coastguard Worker 			num_low_priority = atoi(argv[count]);
135*49cdfc7eSAndroid Build Coastguard Worker 		else {
136*49cdfc7eSAndroid Build Coastguard Worker 			fprintf(stderr,
137*49cdfc7eSAndroid Build Coastguard Worker 				"Programme to time context switches (schedules)\n");
138*49cdfc7eSAndroid Build Coastguard Worker 			fprintf(stderr,
139*49cdfc7eSAndroid Build Coastguard Worker 				"(C) 1998  Richard Gooch <[email protected]>\n");
140*49cdfc7eSAndroid Build Coastguard Worker 			fprintf(stderr, "Usage:\t%s\n", usage);
141*49cdfc7eSAndroid Build Coastguard Worker 			fprintf(stderr,
142*49cdfc7eSAndroid Build Coastguard Worker 				"\t-thread\t\tswitch threads not processes\n");
143*49cdfc7eSAndroid Build Coastguard Worker 			fprintf(stderr,
144*49cdfc7eSAndroid Build Coastguard Worker 				"\t-pipe\t\tuse pipes not sched_yield()\n");
145*49cdfc7eSAndroid Build Coastguard Worker 			fprintf(stderr,
146*49cdfc7eSAndroid Build Coastguard Worker 				"\t-fpu\t\tpollute the FPU after each switch in main\n");
147*49cdfc7eSAndroid Build Coastguard Worker 			fprintf(stderr,
148*49cdfc7eSAndroid Build Coastguard Worker 				"\tnum_running\tnumber of extra processes\n");
149*49cdfc7eSAndroid Build Coastguard Worker 			exit(0);
150*49cdfc7eSAndroid Build Coastguard Worker 		}
151*49cdfc7eSAndroid Build Coastguard Worker 	}
152*49cdfc7eSAndroid Build Coastguard Worker 	if (no_test) {
153*49cdfc7eSAndroid Build Coastguard Worker 		if (num_low_priority > 0)
154*49cdfc7eSAndroid Build Coastguard Worker 			run_low_priority(num_low_priority, read_fd);
155*49cdfc7eSAndroid Build Coastguard Worker 		while (TRUE)
156*49cdfc7eSAndroid Build Coastguard Worker 			pause();
157*49cdfc7eSAndroid Build Coastguard Worker 	}
158*49cdfc7eSAndroid Build Coastguard Worker 	if (geteuid() == 0) {
159*49cdfc7eSAndroid Build Coastguard Worker 		struct sched_param sp;
160*49cdfc7eSAndroid Build Coastguard Worker 
161*49cdfc7eSAndroid Build Coastguard Worker 		memset(&sp, 0, sizeof sp);
162*49cdfc7eSAndroid Build Coastguard Worker 		sp.sched_priority = 10;
163*49cdfc7eSAndroid Build Coastguard Worker 		if (sched_setscheduler(0, SCHED_FIFO, &sp) != 0) {
164*49cdfc7eSAndroid Build Coastguard Worker 			fprintf(stderr, "Error changing to RT class\t%s\n",
165*49cdfc7eSAndroid Build Coastguard Worker 				ERRSTRING);
166*49cdfc7eSAndroid Build Coastguard Worker 			exit(1);
167*49cdfc7eSAndroid Build Coastguard Worker 		}
168*49cdfc7eSAndroid Build Coastguard Worker 		if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0) {
169*49cdfc7eSAndroid Build Coastguard Worker 			fprintf(stderr, "Error locking pages\t%s\n", ERRSTRING);
170*49cdfc7eSAndroid Build Coastguard Worker 			exit(1);
171*49cdfc7eSAndroid Build Coastguard Worker 		}
172*49cdfc7eSAndroid Build Coastguard Worker 	} else
173*49cdfc7eSAndroid Build Coastguard Worker 		fprintf(stderr, "Not running with RT priority!\n");
174*49cdfc7eSAndroid Build Coastguard Worker 	/*  Give shell and login programme time to finish up and get off the run
175*49cdfc7eSAndroid Build Coastguard Worker 	   queue  */
176*49cdfc7eSAndroid Build Coastguard Worker 	usleep(200000);
177*49cdfc7eSAndroid Build Coastguard Worker 	if (use_pipe) {
178*49cdfc7eSAndroid Build Coastguard Worker 		if (pipe(fds) != 0) {
179*49cdfc7eSAndroid Build Coastguard Worker 			fprintf(stderr, "Error creating pipe\t%s\n", ERRSTRING);
180*49cdfc7eSAndroid Build Coastguard Worker 			exit(1);
181*49cdfc7eSAndroid Build Coastguard Worker 		}
182*49cdfc7eSAndroid Build Coastguard Worker 		pipe_read_fd = fds[0];
183*49cdfc7eSAndroid Build Coastguard Worker 		write_fd = fds[1];
184*49cdfc7eSAndroid Build Coastguard Worker 	}
185*49cdfc7eSAndroid Build Coastguard Worker 	num_hogs = hog_other_cpus();
186*49cdfc7eSAndroid Build Coastguard Worker 	/*  Determine overhead. Do it in a loop=2. The first iteration should warm
187*49cdfc7eSAndroid Build Coastguard Worker 	   the cache, the second will compute the overhead  */
188*49cdfc7eSAndroid Build Coastguard Worker 	for (j = 0; j < 2; ++j) {
189*49cdfc7eSAndroid Build Coastguard Worker 		switches1 = get_num_switches();
190*49cdfc7eSAndroid Build Coastguard Worker 		gettimeofday(&before, NULL);
191*49cdfc7eSAndroid Build Coastguard Worker 		for (i = 0; i < 20; ++i) {
192*49cdfc7eSAndroid Build Coastguard Worker 			if (use_pipe) {
193*49cdfc7eSAndroid Build Coastguard Worker 				char ch = 0;
194*49cdfc7eSAndroid Build Coastguard Worker 
195*49cdfc7eSAndroid Build Coastguard Worker 				write(pipe_write_fd, &ch, 1);
196*49cdfc7eSAndroid Build Coastguard Worker 				read(read_fd, &ch, 1);
197*49cdfc7eSAndroid Build Coastguard Worker 			} else
198*49cdfc7eSAndroid Build Coastguard Worker 				sched_yield();
199*49cdfc7eSAndroid Build Coastguard Worker 			if (frob_fpu)
200*49cdfc7eSAndroid Build Coastguard Worker 				++dcount;
201*49cdfc7eSAndroid Build Coastguard Worker 		}
202*49cdfc7eSAndroid Build Coastguard Worker 		gettimeofday(&after, NULL);
203*49cdfc7eSAndroid Build Coastguard Worker 		num_overhead_switches = get_num_switches() - switches1;
204*49cdfc7eSAndroid Build Coastguard Worker 		overhead = 1000000 * (after.tv_sec - before.tv_sec);
205*49cdfc7eSAndroid Build Coastguard Worker 		overhead += after.tv_usec - before.tv_usec;
206*49cdfc7eSAndroid Build Coastguard Worker 	}
207*49cdfc7eSAndroid Build Coastguard Worker 	use_fpu_value(dcount);
208*49cdfc7eSAndroid Build Coastguard Worker 	if (num_low_priority > 0)
209*49cdfc7eSAndroid Build Coastguard Worker 		run_low_priority(num_low_priority, read_fd);
210*49cdfc7eSAndroid Build Coastguard Worker 	/*  Set up for the benchmark  */
211*49cdfc7eSAndroid Build Coastguard Worker 	run_yielder(use_threads, read_fd);
212*49cdfc7eSAndroid Build Coastguard Worker 	memset(diffs, 0, sizeof diffs);
213*49cdfc7eSAndroid Build Coastguard Worker 	run_queue_size1 = get_run_queue_size();
214*49cdfc7eSAndroid Build Coastguard Worker 	total_diffs = 0;
215*49cdfc7eSAndroid Build Coastguard Worker 	switches1 = get_num_switches();
216*49cdfc7eSAndroid Build Coastguard Worker 	/*  Benchmark!  */
217*49cdfc7eSAndroid Build Coastguard Worker 	for (count = 0; count < MAX_ITERATIONS; ++count) {
218*49cdfc7eSAndroid Build Coastguard Worker 		signed long diff;
219*49cdfc7eSAndroid Build Coastguard Worker 
220*49cdfc7eSAndroid Build Coastguard Worker 		gettimeofday(&before, NULL);
221*49cdfc7eSAndroid Build Coastguard Worker 		/*  Generate 20 context switches  */
222*49cdfc7eSAndroid Build Coastguard Worker 		for (i = 0; i < 10; ++i) {
223*49cdfc7eSAndroid Build Coastguard Worker 			if (use_pipe) {
224*49cdfc7eSAndroid Build Coastguard Worker 				char ch = 0;
225*49cdfc7eSAndroid Build Coastguard Worker 
226*49cdfc7eSAndroid Build Coastguard Worker 				write(write_fd, &ch, 1);
227*49cdfc7eSAndroid Build Coastguard Worker 				read(read_fd, &ch, 1);
228*49cdfc7eSAndroid Build Coastguard Worker 			} else
229*49cdfc7eSAndroid Build Coastguard Worker 				sched_yield();
230*49cdfc7eSAndroid Build Coastguard Worker 			if (frob_fpu)
231*49cdfc7eSAndroid Build Coastguard Worker 				dcount += 1.0;
232*49cdfc7eSAndroid Build Coastguard Worker 		}
233*49cdfc7eSAndroid Build Coastguard Worker 		gettimeofday(&after, NULL);
234*49cdfc7eSAndroid Build Coastguard Worker 		diff = 1000000 * (after.tv_sec - before.tv_sec);
235*49cdfc7eSAndroid Build Coastguard Worker 		diff += after.tv_usec - before.tv_usec;
236*49cdfc7eSAndroid Build Coastguard Worker 		diffs[count] = diff;
237*49cdfc7eSAndroid Build Coastguard Worker 		total_diffs += diff;
238*49cdfc7eSAndroid Build Coastguard Worker 		if (diff < min_diff)
239*49cdfc7eSAndroid Build Coastguard Worker 			min_diff = diff;
240*49cdfc7eSAndroid Build Coastguard Worker 		if (diff > max_diff)
241*49cdfc7eSAndroid Build Coastguard Worker 			max_diff = diff;
242*49cdfc7eSAndroid Build Coastguard Worker 	}
243*49cdfc7eSAndroid Build Coastguard Worker 	num_yields = sched_count;
244*49cdfc7eSAndroid Build Coastguard Worker 	run_queue_size2 = get_run_queue_size();
245*49cdfc7eSAndroid Build Coastguard Worker 	num_switches = get_num_switches() - switches1;
246*49cdfc7eSAndroid Build Coastguard Worker 	if (!use_threads)
247*49cdfc7eSAndroid Build Coastguard Worker 		kill(child, SIGTERM);
248*49cdfc7eSAndroid Build Coastguard Worker 	fprintf(stderr, "Started %u hog processes\n", num_hogs);
249*49cdfc7eSAndroid Build Coastguard Worker 	fprintf(stderr, "Syscall%s overhead: %.1f us\n", frob_fpu ? "/FPU" : "",
250*49cdfc7eSAndroid Build Coastguard Worker 		(double)overhead / 20.0);
251*49cdfc7eSAndroid Build Coastguard Worker 	if (switches1 > 0)
252*49cdfc7eSAndroid Build Coastguard Worker 		fprintf(stderr, "Num switches during overhead check: %lu\n",
253*49cdfc7eSAndroid Build Coastguard Worker 			num_overhead_switches);
254*49cdfc7eSAndroid Build Coastguard Worker 	fprintf(stderr, "Minimum scheduling latency: %.1f (%.1f) us\n",
255*49cdfc7eSAndroid Build Coastguard Worker 		(double)min_diff / 20.0, (double)(min_diff - overhead) / 20.0);
256*49cdfc7eSAndroid Build Coastguard Worker 	median = compute_median(diffs, max_diff);
257*49cdfc7eSAndroid Build Coastguard Worker 	fprintf(stderr, "Median scheduling latency:  %.1f (%.1f) us\n",
258*49cdfc7eSAndroid Build Coastguard Worker 		(double)median / 20.0, (double)(median - overhead) / 20.0);
259*49cdfc7eSAndroid Build Coastguard Worker 	fprintf(stderr, "Average scheduling latency: %.1f (%.1f) us\n",
260*49cdfc7eSAndroid Build Coastguard Worker 		(double)total_diffs / (double)MAX_ITERATIONS / 20.0,
261*49cdfc7eSAndroid Build Coastguard Worker 		(double)(total_diffs - overhead * MAX_ITERATIONS) /
262*49cdfc7eSAndroid Build Coastguard Worker 		(double)MAX_ITERATIONS / 20.0);
263*49cdfc7eSAndroid Build Coastguard Worker 	fprintf(stderr, "Maximum scheduling latency: %.1f (%.1f) us\n",
264*49cdfc7eSAndroid Build Coastguard Worker 		(double)max_diff / 20.0, (double)(max_diff - overhead) / 20.0);
265*49cdfc7eSAndroid Build Coastguard Worker 	fprintf(stderr, "Run queue size: %u, %u\n",
266*49cdfc7eSAndroid Build Coastguard Worker 		run_queue_size1, run_queue_size2);
267*49cdfc7eSAndroid Build Coastguard Worker 	use_fpu_value(dcount);
268*49cdfc7eSAndroid Build Coastguard Worker 	if (use_threads)
269*49cdfc7eSAndroid Build Coastguard Worker 		fprintf(stderr, "Number of yields: %u\n", num_yields);
270*49cdfc7eSAndroid Build Coastguard Worker 	if (num_switches > 0)
271*49cdfc7eSAndroid Build Coastguard Worker 		fprintf(stderr, "Num switches: %lu\n", num_switches);
272*49cdfc7eSAndroid Build Coastguard Worker 
273*49cdfc7eSAndroid Build Coastguard Worker 	/*  Terminate all child processes  */
274*49cdfc7eSAndroid Build Coastguard Worker 	sigemptyset(&set);
275*49cdfc7eSAndroid Build Coastguard Worker 	sigaddset(&set, SIGTERM);
276*49cdfc7eSAndroid Build Coastguard Worker 	sigprocmask(SIG_BLOCK, &set, NULL);
277*49cdfc7eSAndroid Build Coastguard Worker 
278*49cdfc7eSAndroid Build Coastguard Worker 	kill(0, SIGTERM);
279*49cdfc7eSAndroid Build Coastguard Worker 	return (0);
280*49cdfc7eSAndroid Build Coastguard Worker }				/*  End Function main  */
281*49cdfc7eSAndroid Build Coastguard Worker 
hog_other_cpus()282*49cdfc7eSAndroid Build Coastguard Worker static unsigned int hog_other_cpus()
283*49cdfc7eSAndroid Build Coastguard Worker /*  [SUMMARY] Hog other CPUs with a high-priority job.
284*49cdfc7eSAndroid Build Coastguard Worker     [RETURNS] The number of hogged CPUs.
285*49cdfc7eSAndroid Build Coastguard Worker */
286*49cdfc7eSAndroid Build Coastguard Worker {
287*49cdfc7eSAndroid Build Coastguard Worker 	unsigned int count;
288*49cdfc7eSAndroid Build Coastguard Worker 
289*49cdfc7eSAndroid Build Coastguard Worker 	for (count = mt_num_processors(); count > 1; --count) {
290*49cdfc7eSAndroid Build Coastguard Worker 		switch (fork()) {
291*49cdfc7eSAndroid Build Coastguard Worker 		case 0:
292*49cdfc7eSAndroid Build Coastguard Worker 			/*  Child  */
293*49cdfc7eSAndroid Build Coastguard Worker 			while (TRUE) ;
294*49cdfc7eSAndroid Build Coastguard Worker 			break;
295*49cdfc7eSAndroid Build Coastguard Worker 		case -1:
296*49cdfc7eSAndroid Build Coastguard Worker 			/*  Error  */
297*49cdfc7eSAndroid Build Coastguard Worker 			fprintf(stderr, "Error forking\t%s\n", ERRSTRING);
298*49cdfc7eSAndroid Build Coastguard Worker 			kill(0, SIGTERM);
299*49cdfc7eSAndroid Build Coastguard Worker 			break;
300*49cdfc7eSAndroid Build Coastguard Worker 		default:
301*49cdfc7eSAndroid Build Coastguard Worker 			/*  Parent  */
302*49cdfc7eSAndroid Build Coastguard Worker 			break;
303*49cdfc7eSAndroid Build Coastguard Worker 		}
304*49cdfc7eSAndroid Build Coastguard Worker 	}
305*49cdfc7eSAndroid Build Coastguard Worker 	return mt_num_processors() - 1;
306*49cdfc7eSAndroid Build Coastguard Worker }				/*  End Function hog_other_cpus  */
307*49cdfc7eSAndroid Build Coastguard Worker 
run_yielder(int use_threads,int read_fd)308*49cdfc7eSAndroid Build Coastguard Worker static void run_yielder(int use_threads, int read_fd)
309*49cdfc7eSAndroid Build Coastguard Worker /*  [SUMMARY] Run other process which will continuously yield.
310*49cdfc7eSAndroid Build Coastguard Worker     <use_threads> If TRUE, the yielding process is just a thread.
311*49cdfc7eSAndroid Build Coastguard Worker     <read_fd> The pipe to read the synchronisation byte from.
312*49cdfc7eSAndroid Build Coastguard Worker     [RETURNS] Nothing.
313*49cdfc7eSAndroid Build Coastguard Worker */
314*49cdfc7eSAndroid Build Coastguard Worker {
315*49cdfc7eSAndroid Build Coastguard Worker 	char ch;
316*49cdfc7eSAndroid Build Coastguard Worker 	struct sigaction new_action;
317*49cdfc7eSAndroid Build Coastguard Worker #ifdef _POSIX_THREADS
318*49cdfc7eSAndroid Build Coastguard Worker 	pthread_t thread;
319*49cdfc7eSAndroid Build Coastguard Worker 
320*49cdfc7eSAndroid Build Coastguard Worker 	if (use_threads) {
321*49cdfc7eSAndroid Build Coastguard Worker 		if (pthread_create(&thread, NULL, yielder_main, NULL) != 0) {
322*49cdfc7eSAndroid Build Coastguard Worker 			fprintf(stderr, "Error creating thread\t%s\n",
323*49cdfc7eSAndroid Build Coastguard Worker 				ERRSTRING);
324*49cdfc7eSAndroid Build Coastguard Worker 			kill(0, SIGTERM);
325*49cdfc7eSAndroid Build Coastguard Worker 		}
326*49cdfc7eSAndroid Build Coastguard Worker 		read(read_fd, &ch, 1);
327*49cdfc7eSAndroid Build Coastguard Worker 		return;
328*49cdfc7eSAndroid Build Coastguard Worker 	}
329*49cdfc7eSAndroid Build Coastguard Worker #endif
330*49cdfc7eSAndroid Build Coastguard Worker 	switch (child = fork()) {
331*49cdfc7eSAndroid Build Coastguard Worker 	case 0:
332*49cdfc7eSAndroid Build Coastguard Worker 		/*  Child  */
333*49cdfc7eSAndroid Build Coastguard Worker 		break;
334*49cdfc7eSAndroid Build Coastguard Worker 	case -1:
335*49cdfc7eSAndroid Build Coastguard Worker 		/*  Error  */
336*49cdfc7eSAndroid Build Coastguard Worker 		fprintf(stderr, "Error forking\t%s\n", ERRSTRING);
337*49cdfc7eSAndroid Build Coastguard Worker 		kill(0, SIGTERM);
338*49cdfc7eSAndroid Build Coastguard Worker 		break;
339*49cdfc7eSAndroid Build Coastguard Worker 	default:
340*49cdfc7eSAndroid Build Coastguard Worker 		/*  Parent  */
341*49cdfc7eSAndroid Build Coastguard Worker 		read(read_fd, &ch, 1);
342*49cdfc7eSAndroid Build Coastguard Worker 		return;
343*49cdfc7eSAndroid Build Coastguard Worker 		/*break; */
344*49cdfc7eSAndroid Build Coastguard Worker 	}
345*49cdfc7eSAndroid Build Coastguard Worker 	memset(&new_action, 0, sizeof new_action);
346*49cdfc7eSAndroid Build Coastguard Worker 	sigemptyset(&new_action.sa_mask);
347*49cdfc7eSAndroid Build Coastguard Worker 	new_action.sa_handler = s_term_handler;
348*49cdfc7eSAndroid Build Coastguard Worker 	if (sigaction(SIGTERM, &new_action, NULL) != 0) {
349*49cdfc7eSAndroid Build Coastguard Worker 		fprintf(stderr, "Error setting SIGTERM handler\t%s\n",
350*49cdfc7eSAndroid Build Coastguard Worker 			ERRSTRING);
351*49cdfc7eSAndroid Build Coastguard Worker 		exit(1);
352*49cdfc7eSAndroid Build Coastguard Worker 	}
353*49cdfc7eSAndroid Build Coastguard Worker 	yielder_main(NULL);
354*49cdfc7eSAndroid Build Coastguard Worker }				/*  End Function run_yielder  */
355*49cdfc7eSAndroid Build Coastguard Worker 
yielder_main(void * arg)356*49cdfc7eSAndroid Build Coastguard Worker static void *yielder_main(void *arg)
357*49cdfc7eSAndroid Build Coastguard Worker /*  [SUMMARY] Yielder function.
358*49cdfc7eSAndroid Build Coastguard Worker     <arg> An arbirtrary pointer. Ignored.
359*49cdfc7eSAndroid Build Coastguard Worker     [RETURNS] NULL.
360*49cdfc7eSAndroid Build Coastguard Worker */
361*49cdfc7eSAndroid Build Coastguard Worker {
362*49cdfc7eSAndroid Build Coastguard Worker 	char ch = 0;
363*49cdfc7eSAndroid Build Coastguard Worker 
364*49cdfc7eSAndroid Build Coastguard Worker 	sched_count = 0;
365*49cdfc7eSAndroid Build Coastguard Worker 	write(pipe_write_fd, &ch, 1);
366*49cdfc7eSAndroid Build Coastguard Worker 	while (TRUE) {
367*49cdfc7eSAndroid Build Coastguard Worker 		if (pipe_read_fd >= 0) {
368*49cdfc7eSAndroid Build Coastguard Worker 			read(pipe_read_fd, &ch, 1);
369*49cdfc7eSAndroid Build Coastguard Worker 			write(pipe_write_fd, &ch, 1);
370*49cdfc7eSAndroid Build Coastguard Worker 		} else
371*49cdfc7eSAndroid Build Coastguard Worker 			sched_yield();
372*49cdfc7eSAndroid Build Coastguard Worker 		++sched_count;
373*49cdfc7eSAndroid Build Coastguard Worker 	}
374*49cdfc7eSAndroid Build Coastguard Worker 	return (NULL);
375*49cdfc7eSAndroid Build Coastguard Worker }				/*  End Function yielder_main  */
376*49cdfc7eSAndroid Build Coastguard Worker 
s_term_handler()377*49cdfc7eSAndroid Build Coastguard Worker static void s_term_handler()
378*49cdfc7eSAndroid Build Coastguard Worker {
379*49cdfc7eSAndroid Build Coastguard Worker 	fprintf(stderr, "Number of yields: %u\n", sched_count);
380*49cdfc7eSAndroid Build Coastguard Worker 	exit(0);
381*49cdfc7eSAndroid Build Coastguard Worker }				/*  End Function s_term_handler  */
382*49cdfc7eSAndroid Build Coastguard Worker 
run_low_priority(unsigned int num,int read_fd)383*49cdfc7eSAndroid Build Coastguard Worker static void run_low_priority(unsigned int num, int read_fd)
384*49cdfc7eSAndroid Build Coastguard Worker /*  [SUMMARY] Run low priority processes.
385*49cdfc7eSAndroid Build Coastguard Worker     <num> Number of processes.
386*49cdfc7eSAndroid Build Coastguard Worker     <read_fd> The pipe to read the synchronisation byte from.
387*49cdfc7eSAndroid Build Coastguard Worker     [RETURNS] Nothing.
388*49cdfc7eSAndroid Build Coastguard Worker */
389*49cdfc7eSAndroid Build Coastguard Worker {
390*49cdfc7eSAndroid Build Coastguard Worker 	char ch = 0;
391*49cdfc7eSAndroid Build Coastguard Worker 
392*49cdfc7eSAndroid Build Coastguard Worker 	for (; num > 0; --num) {
393*49cdfc7eSAndroid Build Coastguard Worker 		switch (fork()) {
394*49cdfc7eSAndroid Build Coastguard Worker 		case 0:
395*49cdfc7eSAndroid Build Coastguard Worker 			/*  Child  */
396*49cdfc7eSAndroid Build Coastguard Worker 			if (geteuid() == 0) {
397*49cdfc7eSAndroid Build Coastguard Worker 				struct sched_param sp;
398*49cdfc7eSAndroid Build Coastguard Worker 
399*49cdfc7eSAndroid Build Coastguard Worker 				memset(&sp, 0, sizeof sp);
400*49cdfc7eSAndroid Build Coastguard Worker 				sp.sched_priority = 0;
401*49cdfc7eSAndroid Build Coastguard Worker 				if (sched_setscheduler(0, SCHED_OTHER, &sp) !=
402*49cdfc7eSAndroid Build Coastguard Worker 				    0) {
403*49cdfc7eSAndroid Build Coastguard Worker 					fprintf(stderr,
404*49cdfc7eSAndroid Build Coastguard Worker 						"Error changing to SCHED_OTHER class\t%s\n",
405*49cdfc7eSAndroid Build Coastguard Worker 						ERRSTRING);
406*49cdfc7eSAndroid Build Coastguard Worker 					exit(1);
407*49cdfc7eSAndroid Build Coastguard Worker 				}
408*49cdfc7eSAndroid Build Coastguard Worker 			}
409*49cdfc7eSAndroid Build Coastguard Worker 			if (nice(20) != 0) {
410*49cdfc7eSAndroid Build Coastguard Worker 				fprintf(stderr, "Error nicing\t%s\n",
411*49cdfc7eSAndroid Build Coastguard Worker 					ERRSTRING);
412*49cdfc7eSAndroid Build Coastguard Worker 				kill(0, SIGTERM);
413*49cdfc7eSAndroid Build Coastguard Worker 			}
414*49cdfc7eSAndroid Build Coastguard Worker 			write(pipe_write_fd, &ch, 1);
415*49cdfc7eSAndroid Build Coastguard Worker 			while (TRUE)
416*49cdfc7eSAndroid Build Coastguard Worker 				sched_yield();
417*49cdfc7eSAndroid Build Coastguard Worker 			break;
418*49cdfc7eSAndroid Build Coastguard Worker 		case -1:
419*49cdfc7eSAndroid Build Coastguard Worker 			/*  Error  */
420*49cdfc7eSAndroid Build Coastguard Worker 			fprintf(stderr, "Error forking\t%s\n", ERRSTRING);
421*49cdfc7eSAndroid Build Coastguard Worker 			kill(0, SIGTERM);
422*49cdfc7eSAndroid Build Coastguard Worker 			break;
423*49cdfc7eSAndroid Build Coastguard Worker 		default:
424*49cdfc7eSAndroid Build Coastguard Worker 			/*  Parent  */
425*49cdfc7eSAndroid Build Coastguard Worker 			read(read_fd, &ch, 1);
426*49cdfc7eSAndroid Build Coastguard Worker 			break;
427*49cdfc7eSAndroid Build Coastguard Worker 		}
428*49cdfc7eSAndroid Build Coastguard Worker 	}
429*49cdfc7eSAndroid Build Coastguard Worker }				/*  End Function run_low_priority  */
430*49cdfc7eSAndroid Build Coastguard Worker 
compute_median(unsigned long values[MAX_ITERATIONS],unsigned long max_value)431*49cdfc7eSAndroid Build Coastguard Worker static unsigned long compute_median(unsigned long values[MAX_ITERATIONS],
432*49cdfc7eSAndroid Build Coastguard Worker 				    unsigned long max_value)
433*49cdfc7eSAndroid Build Coastguard Worker /*  [SUMMARY] Compute the median from an array of values.
434*49cdfc7eSAndroid Build Coastguard Worker     <values> The array of values.
435*49cdfc7eSAndroid Build Coastguard Worker     <max_value> The maximum value in the array.
436*49cdfc7eSAndroid Build Coastguard Worker     [RETURNS] The median value.
437*49cdfc7eSAndroid Build Coastguard Worker */
438*49cdfc7eSAndroid Build Coastguard Worker {
439*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long count;
440*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long median = 0;
441*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long peak = 0;
442*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long *table;
443*49cdfc7eSAndroid Build Coastguard Worker 
444*49cdfc7eSAndroid Build Coastguard Worker 	/*  Crude but effective  */
445*49cdfc7eSAndroid Build Coastguard Worker 	if ((table = calloc(max_value + 1, sizeof *table)) == NULL) {
446*49cdfc7eSAndroid Build Coastguard Worker 		fprintf(stderr, "Error allocating median table\n");
447*49cdfc7eSAndroid Build Coastguard Worker 		exit(1);
448*49cdfc7eSAndroid Build Coastguard Worker 	}
449*49cdfc7eSAndroid Build Coastguard Worker 	for (count = 0; count < MAX_ITERATIONS; ++count) {
450*49cdfc7eSAndroid Build Coastguard Worker 		++table[values[count]];
451*49cdfc7eSAndroid Build Coastguard Worker 	}
452*49cdfc7eSAndroid Build Coastguard Worker 	/*  Now search for peak. Position of peak is median  */
453*49cdfc7eSAndroid Build Coastguard Worker 	for (count = 0; count < max_value + 1; ++count) {
454*49cdfc7eSAndroid Build Coastguard Worker 		if (table[count] < peak)
455*49cdfc7eSAndroid Build Coastguard Worker 			continue;
456*49cdfc7eSAndroid Build Coastguard Worker 		peak = table[count];
457*49cdfc7eSAndroid Build Coastguard Worker 		median = count;
458*49cdfc7eSAndroid Build Coastguard Worker 	}
459*49cdfc7eSAndroid Build Coastguard Worker 	free(table);
460*49cdfc7eSAndroid Build Coastguard Worker 	return (median);
461*49cdfc7eSAndroid Build Coastguard Worker }				/*  End Function compute_median  */
462*49cdfc7eSAndroid Build Coastguard Worker 
get_run_queue_size()463*49cdfc7eSAndroid Build Coastguard Worker static unsigned int get_run_queue_size()
464*49cdfc7eSAndroid Build Coastguard Worker /*  [SUMMARY] Compute the current size of the run queue.
465*49cdfc7eSAndroid Build Coastguard Worker     [RETURNS] The length of the run queue.
466*49cdfc7eSAndroid Build Coastguard Worker */
467*49cdfc7eSAndroid Build Coastguard Worker {
468*49cdfc7eSAndroid Build Coastguard Worker 	int dummy_i;
469*49cdfc7eSAndroid Build Coastguard Worker 	unsigned int length = 0;
470*49cdfc7eSAndroid Build Coastguard Worker 	FILE *fp;
471*49cdfc7eSAndroid Build Coastguard Worker 	DIR *dp;
472*49cdfc7eSAndroid Build Coastguard Worker 	struct dirent *de;
473*49cdfc7eSAndroid Build Coastguard Worker 	char txt[64], dummy_str[64];
474*49cdfc7eSAndroid Build Coastguard Worker 
475*49cdfc7eSAndroid Build Coastguard Worker 	if ((dp = opendir("/proc")) == NULL)
476*49cdfc7eSAndroid Build Coastguard Worker 		return (0);
477*49cdfc7eSAndroid Build Coastguard Worker 	while ((de = readdir(dp)) != NULL) {
478*49cdfc7eSAndroid Build Coastguard Worker 		if (!isdigit(de->d_name[0]))
479*49cdfc7eSAndroid Build Coastguard Worker 			continue;
480*49cdfc7eSAndroid Build Coastguard Worker 		sprintf(txt, "/proc/%s/stat", de->d_name);
481*49cdfc7eSAndroid Build Coastguard Worker 		if ((fp = fopen(txt, "r")) == NULL)
482*49cdfc7eSAndroid Build Coastguard Worker 			return (length);
483*49cdfc7eSAndroid Build Coastguard Worker 		fscanf(fp, "%d %s %s", &dummy_i, dummy_str, txt);
484*49cdfc7eSAndroid Build Coastguard Worker 		if (txt[0] == 'R')
485*49cdfc7eSAndroid Build Coastguard Worker 			++length;
486*49cdfc7eSAndroid Build Coastguard Worker 		fclose(fp);
487*49cdfc7eSAndroid Build Coastguard Worker 	}
488*49cdfc7eSAndroid Build Coastguard Worker 	closedir(dp);
489*49cdfc7eSAndroid Build Coastguard Worker 	return (length);
490*49cdfc7eSAndroid Build Coastguard Worker }				/*  End Function get_run_queue_size  */
491*49cdfc7eSAndroid Build Coastguard Worker 
get_num_switches()492*49cdfc7eSAndroid Build Coastguard Worker static unsigned long get_num_switches()
493*49cdfc7eSAndroid Build Coastguard Worker /*  [SUMMARY] Get the number of context switches.
494*49cdfc7eSAndroid Build Coastguard Worker     [RETURNS] The number of context switches on success, else 0.
495*49cdfc7eSAndroid Build Coastguard Worker */
496*49cdfc7eSAndroid Build Coastguard Worker {
497*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long val;
498*49cdfc7eSAndroid Build Coastguard Worker 	FILE *fp;
499*49cdfc7eSAndroid Build Coastguard Worker 	char line[256], name[64];
500*49cdfc7eSAndroid Build Coastguard Worker 
501*49cdfc7eSAndroid Build Coastguard Worker 	if ((fp = fopen("/proc/stat", "r")) == NULL)
502*49cdfc7eSAndroid Build Coastguard Worker 		return (0);
503*49cdfc7eSAndroid Build Coastguard Worker 
504*49cdfc7eSAndroid Build Coastguard Worker 	while (fgets(line, sizeof line, fp) != NULL) {
505*49cdfc7eSAndroid Build Coastguard Worker 		if (sscanf(line, "%s %lu", name, &val) != 2)
506*49cdfc7eSAndroid Build Coastguard Worker 			continue;
507*49cdfc7eSAndroid Build Coastguard Worker 
508*49cdfc7eSAndroid Build Coastguard Worker 		if (strcasecmp(name, "ctxt") != 0)
509*49cdfc7eSAndroid Build Coastguard Worker 			continue;
510*49cdfc7eSAndroid Build Coastguard Worker 
511*49cdfc7eSAndroid Build Coastguard Worker 		fclose(fp);
512*49cdfc7eSAndroid Build Coastguard Worker 		return (val);
513*49cdfc7eSAndroid Build Coastguard Worker 	}
514*49cdfc7eSAndroid Build Coastguard Worker 	fclose(fp);
515*49cdfc7eSAndroid Build Coastguard Worker 	return (0);
516*49cdfc7eSAndroid Build Coastguard Worker }				/*  End Function get_num_switches  */
517*49cdfc7eSAndroid Build Coastguard Worker 
use_fpu_value(double val)518*49cdfc7eSAndroid Build Coastguard Worker static void use_fpu_value(double val)
519*49cdfc7eSAndroid Build Coastguard Worker /*  [SUMMARY] Dummy function to consume FPU value. Fools compiler.
520*49cdfc7eSAndroid Build Coastguard Worker     <val> The value.
521*49cdfc7eSAndroid Build Coastguard Worker     [RETURNS] Nothing.
522*49cdfc7eSAndroid Build Coastguard Worker */
523*49cdfc7eSAndroid Build Coastguard Worker {
524*49cdfc7eSAndroid Build Coastguard Worker }				/*  End Function use_fpu_value  */
525