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