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