switch.c (6417B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /* 7 ** File: switch.c 8 ** Description: trying to time context switches 9 */ 10 11 #include "prinit.h" 12 #include "prcvar.h" 13 #include "prmem.h" 14 #include "prinrval.h" 15 #include "prlock.h" 16 #include "prlog.h" 17 #include "prthread.h" 18 #include "prprf.h" 19 20 #include "plerror.h" 21 #include "plgetopt.h" 22 23 #include "private/pprio.h" 24 25 #include <stdlib.h> 26 27 #define INNER_LOOPS 100 28 #define DEFAULT_LOOPS 100 29 #define DEFAULT_THREADS 10 30 31 static PRFileDesc* debug_out = NULL; 32 static PRBool debug_mode = PR_FALSE, verbosity = PR_FALSE, failed = PR_FALSE; 33 34 typedef struct Shared { 35 PRLock* ml; 36 PRCondVar* cv; 37 PRBool twiddle; 38 PRThread* thread; 39 struct Shared* next; 40 } Shared; 41 42 static void Help(void) { 43 debug_out = PR_STDOUT; 44 45 PR_fprintf(debug_out, 46 "Usage: >./switch [-c n] [-t n] [-d] [-v] [-G] [-C n]\n"); 47 PR_fprintf(debug_out, "-c n\tloops at thread level (default: %d)\n", 48 DEFAULT_LOOPS); 49 PR_fprintf(debug_out, "-t n\tnumber of threads (default: %d)\n", 50 DEFAULT_THREADS); 51 PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n"); 52 PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n"); 53 PR_fprintf(debug_out, "-G\tglobal threads only (default: FALSE)\n"); 54 PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n"); 55 } /* Help */ 56 57 static void PR_CALLBACK Notified(void* arg) { 58 Shared* shared = (Shared*)arg; 59 PRStatus status = PR_SUCCESS; 60 while (PR_SUCCESS == status) { 61 PR_Lock(shared->ml); 62 while (shared->twiddle && (PR_SUCCESS == status)) { 63 status = PR_WaitCondVar(shared->cv, PR_INTERVAL_NO_TIMEOUT); 64 } 65 if (verbosity) { 66 PR_fprintf(debug_out, "+"); 67 } 68 shared->twiddle = PR_TRUE; 69 shared->next->twiddle = PR_FALSE; 70 PR_NotifyCondVar(shared->next->cv); 71 PR_Unlock(shared->ml); 72 } 73 } /* Notified */ 74 75 static Shared home; 76 PRIntn PR_CALLBACK Switch(PRIntn argc, char** argv) { 77 PLOptStatus os; 78 PRStatus status; 79 PRBool help = PR_FALSE; 80 PRUintn concurrency = 1; 81 Shared *shared, *link; 82 PRIntervalTime timein, timeout; 83 PRThreadScope thread_scope = PR_LOCAL_THREAD; 84 PRUintn thread_count, inner_count, loop_count, average; 85 PRUintn thread_limit = DEFAULT_THREADS, loop_limit = DEFAULT_LOOPS; 86 PLOptState* opt = PL_CreateOptState(argc, argv, "hdvc:t:C:G"); 87 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 88 if (PL_OPT_BAD == os) { 89 continue; 90 } 91 switch (opt->option) { 92 case 'v': /* verbose mode */ 93 verbosity = PR_TRUE; 94 case 'd': /* debug mode */ 95 debug_mode = PR_TRUE; 96 break; 97 case 'c': /* loop counter */ 98 loop_limit = atoi(opt->value); 99 break; 100 case 't': /* thread limit */ 101 thread_limit = atoi(opt->value); 102 break; 103 case 'C': /* Concurrency limit */ 104 concurrency = atoi(opt->value); 105 break; 106 case 'G': /* global threads only */ 107 thread_scope = PR_GLOBAL_THREAD; 108 break; 109 case 'h': /* help message */ 110 Help(); 111 help = PR_TRUE; 112 break; 113 default: 114 break; 115 } 116 } 117 PL_DestroyOptState(opt); 118 119 if (help) { 120 return -1; 121 } 122 123 if (PR_TRUE == debug_mode) { 124 debug_out = PR_STDOUT; 125 PR_fprintf(debug_out, "Test parameters\n"); 126 PR_fprintf(debug_out, "\tThreads involved: %d\n", thread_limit); 127 PR_fprintf(debug_out, "\tIteration limit: %d\n", loop_limit); 128 PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency); 129 PR_fprintf(debug_out, "\tThread type: %s\n", 130 (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL"); 131 } 132 133 PR_SetConcurrency(concurrency); 134 135 link = &home; 136 home.ml = PR_NewLock(); 137 home.cv = PR_NewCondVar(home.ml); 138 home.twiddle = PR_FALSE; 139 home.next = NULL; 140 141 timeout = 0; 142 143 for (thread_count = 1; thread_count <= thread_limit; ++thread_count) { 144 shared = PR_NEWZAP(Shared); 145 146 shared->ml = home.ml; 147 shared->cv = PR_NewCondVar(home.ml); 148 shared->twiddle = PR_TRUE; 149 shared->next = link; 150 link = shared; 151 152 shared->thread = 153 PR_CreateThread(PR_USER_THREAD, Notified, shared, PR_PRIORITY_HIGH, 154 thread_scope, PR_JOINABLE_THREAD, 0); 155 PR_ASSERT(shared->thread != NULL); 156 if (NULL == shared->thread) { 157 failed = PR_TRUE; 158 } 159 } 160 161 for (loop_count = 1; loop_count <= loop_limit; ++loop_count) { 162 timein = PR_IntervalNow(); 163 for (inner_count = 0; inner_count < INNER_LOOPS; ++inner_count) { 164 PR_Lock(home.ml); 165 home.twiddle = PR_TRUE; 166 shared->twiddle = PR_FALSE; 167 PR_NotifyCondVar(shared->cv); 168 while (home.twiddle) { 169 status = PR_WaitCondVar(home.cv, PR_INTERVAL_NO_TIMEOUT); 170 if (PR_FAILURE == status) { 171 failed = PR_TRUE; 172 } 173 } 174 PR_Unlock(home.ml); 175 } 176 timeout += (PR_IntervalNow() - timein); 177 } 178 179 if (debug_mode) { 180 average = PR_IntervalToMicroseconds(timeout) / 181 (INNER_LOOPS * loop_limit * thread_count); 182 PR_fprintf(debug_out, "Average switch times %d usecs for %d threads\n", 183 average, thread_limit); 184 } 185 186 link = shared; 187 for (thread_count = 1; thread_count <= thread_limit; ++thread_count) { 188 if (&home == link) { 189 break; 190 } 191 status = PR_Interrupt(link->thread); 192 if (PR_SUCCESS != status) { 193 failed = PR_TRUE; 194 if (debug_mode) { 195 PL_FPrintError(debug_out, "Failed to interrupt"); 196 } 197 } 198 link = link->next; 199 } 200 201 for (thread_count = 1; thread_count <= thread_limit; ++thread_count) { 202 link = shared->next; 203 status = PR_JoinThread(shared->thread); 204 if (PR_SUCCESS != status) { 205 failed = PR_TRUE; 206 if (debug_mode) { 207 PL_FPrintError(debug_out, "Failed to join"); 208 } 209 } 210 PR_DestroyCondVar(shared->cv); 211 PR_DELETE(shared); 212 if (&home == link) { 213 break; 214 } 215 shared = link; 216 } 217 PR_DestroyCondVar(home.cv); 218 PR_DestroyLock(home.ml); 219 220 PR_fprintf(PR_STDOUT, ((failed) ? "FAILED\n" : "PASSED\n")); 221 return ((failed) ? 1 : 0); 222 } /* Switch */ 223 224 int main(int argc, char** argv) { 225 PRIntn result; 226 result = PR_Initialize(Switch, argc, argv, 0); 227 return result; 228 } /* main */ 229 230 /* switch.c */