nsprpub/pr/src/cplus/tests/switch.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial