switch.cpp (6834B)
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.cpp 8 ** Description: trying to time context switches 9 */ 10 11 #include "rccv.h" 12 #include "rcinrval.h" 13 #include "rclock.h" 14 #include "rcthread.h" 15 16 #include <prio.h> 17 #include <prlog.h> 18 #include <prprf.h> 19 #include <plerror.h> 20 #include <plgetopt.h> 21 22 #include <stdlib.h> 23 24 #define INNER_LOOPS 100 25 #define DEFAULT_LOOPS 100 26 #define DEFAULT_THREADS 10 27 28 static PRFileDesc *debug_out = NULL; 29 static PRBool debug_mode = PR_FALSE, verbosity = PR_FALSE, failed = PR_FALSE; 30 31 class Home: public RCCondition 32 { 33 public: 34 virtual ~Home(); 35 Home(Home *link, RCLock* ml); 36 37 public: 38 Home *next; 39 RCLock* ml; 40 PRBool twiddle; 41 }; /* Home */ 42 43 Home::~Home() { } 44 45 Home::Home(Home *link, RCLock* lock): RCCondition(lock) 46 { 47 ml = lock; 48 next = link; 49 twiddle = PR_FALSE; 50 } /* Home::Home */ 51 52 class Shared: public Home, public RCThread 53 { 54 public: 55 Shared(RCThread::Scope scope, Home* link, RCLock* ml); 56 57 private: 58 ~Shared(); 59 void RootFunction(); 60 }; /* Shared */ 61 62 Shared::Shared(RCThread::Scope scope, Home* link, RCLock* lock): 63 Home(link, lock), RCThread(scope, RCThread::joinable) { } 64 65 Shared::~Shared() { } 66 67 void Shared::RootFunction() 68 { 69 PRStatus status = PR_SUCCESS; 70 while (PR_SUCCESS == status) 71 { 72 RCEnter entry(ml); 73 while (twiddle && (PR_SUCCESS == status)) { 74 status = Wait(); 75 } 76 if (verbosity) { 77 PR_fprintf(debug_out, "+"); 78 } 79 twiddle = PR_TRUE; 80 next->twiddle = PR_FALSE; 81 next->Notify(); 82 } 83 } /* Shared::RootFunction */ 84 85 static void Help(void) 86 { 87 debug_out = PR_STDOUT; 88 89 PR_fprintf( 90 debug_out, "Usage: >./switch [-d] [-c n] [-t n] [-T n] [-G]\n"); 91 PR_fprintf( 92 debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS); 93 PR_fprintf( 94 debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS); 95 PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n"); 96 PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n"); 97 PR_fprintf(debug_out, "-G n\tglobal threads only (default: FALSE)\n"); 98 PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n"); 99 } /* Help */ 100 101 PRIntn main(PRIntn argc, char **argv) 102 { 103 PLOptStatus os; 104 PRStatus status; 105 PRBool help = PR_FALSE; 106 PRUintn concurrency = 1; 107 RCThread::Scope thread_scope = RCThread::local; 108 PRUintn thread_count, inner_count, loop_count, average; 109 PRUintn thread_limit = DEFAULT_THREADS, loop_limit = DEFAULT_LOOPS; 110 PLOptState *opt = PL_CreateOptState(argc, argv, "hdvc:t:C:G"); 111 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) 112 { 113 if (PL_OPT_BAD == os) { 114 continue; 115 } 116 switch (opt->option) 117 { 118 case 'v': /* verbose mode */ 119 verbosity = PR_TRUE; 120 case 'd': /* debug mode */ 121 debug_mode = PR_TRUE; 122 break; 123 case 'c': /* loop counter */ 124 loop_limit = atoi(opt->value); 125 break; 126 case 't': /* thread limit */ 127 thread_limit = atoi(opt->value); 128 break; 129 case 'C': /* Concurrency limit */ 130 concurrency = atoi(opt->value); 131 break; 132 case 'G': /* global threads only */ 133 thread_scope = RCThread::global; 134 break; 135 case 'h': /* help message */ 136 Help(); 137 help = PR_TRUE; 138 break; 139 default: 140 break; 141 } 142 } 143 PL_DestroyOptState(opt); 144 145 if (help) { 146 return -1; 147 } 148 149 if (PR_TRUE == debug_mode) 150 { 151 debug_out = PR_STDOUT; 152 PR_fprintf(debug_out, "Test parameters\n"); 153 PR_fprintf(debug_out, "\tThreads involved: %d\n", thread_limit); 154 PR_fprintf(debug_out, "\tIteration limit: %d\n", loop_limit); 155 PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency); 156 PR_fprintf( 157 debug_out, "\tThread type: %s\n", 158 (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL"); 159 } 160 161 /* 162 ** The interesting part starts here 163 */ 164 RCLock lock; 165 Shared* shared; 166 Home home(NULL, &lock); 167 Home* link = &home; 168 RCInterval timein, timeout = 0; 169 170 /* Build up the string of objects */ 171 for (thread_count = 1; thread_count <= thread_limit; ++thread_count) 172 { 173 shared = new Shared(thread_scope, link, &lock); 174 shared->Start(); /* make it run */ 175 link = (Home*)shared; 176 } 177 178 /* Pass the message around the horn a few times */ 179 for (loop_count = 1; loop_count <= loop_limit; ++loop_count) 180 { 181 timein.SetToNow(); 182 for (inner_count = 0; inner_count < INNER_LOOPS; ++inner_count) 183 { 184 RCEnter entry(&lock); 185 home.twiddle = PR_TRUE; 186 shared->twiddle = PR_FALSE; 187 shared->Notify(); 188 while (home.twiddle) 189 { 190 failed = (PR_FAILURE == home.Wait()) ? PR_TRUE : PR_FALSE; 191 } 192 } 193 timeout += (RCInterval(RCInterval::now) - timein); 194 } 195 196 /* Figure out how well we did */ 197 if (debug_mode) 198 { 199 average = timeout.ToMicroseconds() 200 / (INNER_LOOPS * loop_limit * thread_count); 201 PR_fprintf( 202 debug_out, "Average switch times %d usecs for %d threads\n", 203 average, thread_limit); 204 } 205 206 /* Start reclamation process */ 207 link = shared; 208 for (thread_count = 1; thread_count <= thread_limit; ++thread_count) 209 { 210 if (&home == link) { 211 break; 212 } 213 status = ((Shared*)link)->Interrupt(); 214 if (PR_SUCCESS != status) 215 { 216 failed = PR_TRUE; 217 if (debug_mode) { 218 PL_FPrintError(debug_out, "Failed to interrupt"); 219 } 220 } 221 link = link->next; 222 } 223 224 for (thread_count = 1; thread_count <= thread_limit; ++thread_count) 225 { 226 link = shared->next; 227 status = shared->Join(); 228 if (PR_SUCCESS != status) 229 { 230 failed = PR_TRUE; 231 if (debug_mode) { 232 PL_FPrintError(debug_out, "Failed to join"); 233 } 234 } 235 if (&home == link) { 236 break; 237 } 238 shared = (Shared*)link; 239 } 240 241 PR_fprintf(PR_STDOUT, ((failed) ? "FAILED\n" : "PASSED\n")); 242 243 failed |= (PR_SUCCESS == RCPrimordialThread::Cleanup()); 244 245 return ((failed) ? 1 : 0); 246 } /* main */ 247 248 /* switch.c */