1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/tests/switch.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,237 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 +** File: switch.c 1.11 +** Description: trying to time context switches 1.12 +*/ 1.13 + 1.14 +#include "prinit.h" 1.15 +#include "prcvar.h" 1.16 +#include "prmem.h" 1.17 +#include "prinrval.h" 1.18 +#include "prlock.h" 1.19 +#include "prlog.h" 1.20 +#include "prthread.h" 1.21 +#include "prprf.h" 1.22 + 1.23 +#include "plerror.h" 1.24 +#include "plgetopt.h" 1.25 + 1.26 +#include "private/pprio.h" 1.27 + 1.28 +#include <stdlib.h> 1.29 + 1.30 +#define INNER_LOOPS 100 1.31 +#define DEFAULT_LOOPS 100 1.32 +#define DEFAULT_THREADS 10 1.33 + 1.34 +static PRFileDesc *debug_out = NULL; 1.35 +static PRBool debug_mode = PR_FALSE, verbosity = PR_FALSE, failed = PR_FALSE; 1.36 + 1.37 +typedef struct Shared 1.38 +{ 1.39 + PRLock *ml; 1.40 + PRCondVar *cv; 1.41 + PRBool twiddle; 1.42 + PRThread *thread; 1.43 + struct Shared *next; 1.44 +} Shared; 1.45 + 1.46 +static void Help(void) 1.47 +{ 1.48 + debug_out = PR_STDOUT; 1.49 + 1.50 + PR_fprintf( 1.51 + debug_out, "Usage: >./switch [-c n] [-t n] [-d] [-v] [-G] [-C n]\n"); 1.52 + PR_fprintf( 1.53 + debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS); 1.54 + PR_fprintf( 1.55 + debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS); 1.56 + PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n"); 1.57 + PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n"); 1.58 + PR_fprintf(debug_out, "-G\tglobal threads only (default: FALSE)\n"); 1.59 + PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n"); 1.60 +} /* Help */ 1.61 + 1.62 +static void PR_CALLBACK Notified(void *arg) 1.63 +{ 1.64 + Shared *shared = (Shared*)arg; 1.65 + PRStatus status = PR_SUCCESS; 1.66 + while (PR_SUCCESS == status) 1.67 + { 1.68 + PR_Lock(shared->ml); 1.69 + while (shared->twiddle && (PR_SUCCESS == status)) 1.70 + status = PR_WaitCondVar(shared->cv, PR_INTERVAL_NO_TIMEOUT); 1.71 + if (verbosity) PR_fprintf(debug_out, "+"); 1.72 + shared->twiddle = PR_TRUE; 1.73 + shared->next->twiddle = PR_FALSE; 1.74 + PR_NotifyCondVar(shared->next->cv); 1.75 + PR_Unlock(shared->ml); 1.76 + } 1.77 +} /* Notified */ 1.78 + 1.79 +static Shared home; 1.80 +PRIntn PR_CALLBACK Switch(PRIntn argc, char **argv) 1.81 +{ 1.82 + PLOptStatus os; 1.83 + PRStatus status; 1.84 + PRBool help = PR_FALSE; 1.85 + PRUintn concurrency = 1; 1.86 + Shared *shared, *link; 1.87 + PRIntervalTime timein, timeout; 1.88 + PRThreadScope thread_scope = PR_LOCAL_THREAD; 1.89 + PRUintn thread_count, inner_count, loop_count, average; 1.90 + PRUintn thread_limit = DEFAULT_THREADS, loop_limit = DEFAULT_LOOPS; 1.91 + PLOptState *opt = PL_CreateOptState(argc, argv, "hdvc:t:C:G"); 1.92 + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) 1.93 + { 1.94 + if (PL_OPT_BAD == os) continue; 1.95 + switch (opt->option) 1.96 + { 1.97 + case 'v': /* verbose mode */ 1.98 + verbosity = PR_TRUE; 1.99 + case 'd': /* debug mode */ 1.100 + debug_mode = PR_TRUE; 1.101 + break; 1.102 + case 'c': /* loop counter */ 1.103 + loop_limit = atoi(opt->value); 1.104 + break; 1.105 + case 't': /* thread limit */ 1.106 + thread_limit = atoi(opt->value); 1.107 + break; 1.108 + case 'C': /* Concurrency limit */ 1.109 + concurrency = atoi(opt->value); 1.110 + break; 1.111 + case 'G': /* global threads only */ 1.112 + thread_scope = PR_GLOBAL_THREAD; 1.113 + break; 1.114 + case 'h': /* help message */ 1.115 + Help(); 1.116 + help = PR_TRUE; 1.117 + break; 1.118 + default: 1.119 + break; 1.120 + } 1.121 + } 1.122 + PL_DestroyOptState(opt); 1.123 + 1.124 + if (help) return -1; 1.125 + 1.126 + if (PR_TRUE == debug_mode) 1.127 + { 1.128 + debug_out = PR_STDOUT; 1.129 + PR_fprintf(debug_out, "Test parameters\n"); 1.130 + PR_fprintf(debug_out, "\tThreads involved: %d\n", thread_limit); 1.131 + PR_fprintf(debug_out, "\tIteration limit: %d\n", loop_limit); 1.132 + PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency); 1.133 + PR_fprintf( 1.134 + debug_out, "\tThread type: %s\n", 1.135 + (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL"); 1.136 + } 1.137 + 1.138 + PR_SetConcurrency(concurrency); 1.139 + 1.140 + link = &home; 1.141 + home.ml = PR_NewLock(); 1.142 + home.cv = PR_NewCondVar(home.ml); 1.143 + home.twiddle = PR_FALSE; 1.144 + home.next = NULL; 1.145 + 1.146 + timeout = 0; 1.147 + 1.148 + for (thread_count = 1; thread_count <= thread_limit; ++thread_count) 1.149 + { 1.150 + shared = PR_NEWZAP(Shared); 1.151 + 1.152 + shared->ml = home.ml; 1.153 + shared->cv = PR_NewCondVar(home.ml); 1.154 + shared->twiddle = PR_TRUE; 1.155 + shared->next = link; 1.156 + link = shared; 1.157 + 1.158 + shared->thread = PR_CreateThread( 1.159 + PR_USER_THREAD, Notified, shared, 1.160 + PR_PRIORITY_HIGH, thread_scope, 1.161 + PR_JOINABLE_THREAD, 0); 1.162 + PR_ASSERT(shared->thread != NULL); 1.163 + if (NULL == shared->thread) 1.164 + failed = PR_TRUE; 1.165 + } 1.166 + 1.167 + for (loop_count = 1; loop_count <= loop_limit; ++loop_count) 1.168 + { 1.169 + timein = PR_IntervalNow(); 1.170 + for (inner_count = 0; inner_count < INNER_LOOPS; ++inner_count) 1.171 + { 1.172 + PR_Lock(home.ml); 1.173 + home.twiddle = PR_TRUE; 1.174 + shared->twiddle = PR_FALSE; 1.175 + PR_NotifyCondVar(shared->cv); 1.176 + while (home.twiddle) 1.177 + { 1.178 + status = PR_WaitCondVar(home.cv, PR_INTERVAL_NO_TIMEOUT); 1.179 + if (PR_FAILURE == status) 1.180 + failed = PR_TRUE; 1.181 + } 1.182 + PR_Unlock(home.ml); 1.183 + } 1.184 + timeout += (PR_IntervalNow() - timein); 1.185 + } 1.186 + 1.187 + if (debug_mode) 1.188 + { 1.189 + average = PR_IntervalToMicroseconds(timeout) 1.190 + / (INNER_LOOPS * loop_limit * thread_count); 1.191 + PR_fprintf( 1.192 + debug_out, "Average switch times %d usecs for %d threads\n", 1.193 + average, thread_limit); 1.194 + } 1.195 + 1.196 + link = shared; 1.197 + for (thread_count = 1; thread_count <= thread_limit; ++thread_count) 1.198 + { 1.199 + if (&home == link) break; 1.200 + status = PR_Interrupt(link->thread); 1.201 + if (PR_SUCCESS != status) 1.202 + { 1.203 + failed = PR_TRUE; 1.204 + if (debug_mode) 1.205 + PL_FPrintError(debug_out, "Failed to interrupt"); 1.206 + } 1.207 + link = link->next; 1.208 + } 1.209 + 1.210 + for (thread_count = 1; thread_count <= thread_limit; ++thread_count) 1.211 + { 1.212 + link = shared->next; 1.213 + status = PR_JoinThread(shared->thread); 1.214 + if (PR_SUCCESS != status) 1.215 + { 1.216 + failed = PR_TRUE; 1.217 + if (debug_mode) 1.218 + PL_FPrintError(debug_out, "Failed to join"); 1.219 + } 1.220 + PR_DestroyCondVar(shared->cv); 1.221 + PR_DELETE(shared); 1.222 + if (&home == link) break; 1.223 + shared = link; 1.224 + } 1.225 + PR_DestroyCondVar(home.cv); 1.226 + PR_DestroyLock(home.ml); 1.227 + 1.228 + PR_fprintf(PR_STDOUT, ((failed) ? "FAILED\n" : "PASSED\n")); 1.229 + return ((failed) ? 1 : 0); 1.230 +} /* Switch */ 1.231 + 1.232 +int main(int argc, char **argv) 1.233 +{ 1.234 + PRIntn result; 1.235 + PR_STDIO_INIT(); 1.236 + result = PR_Initialize(Switch, argc, argv, 0); 1.237 + return result; 1.238 +} /* main */ 1.239 + 1.240 +/* switch.c */