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

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

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

mercurial