Back to index

lightning-sunbird  0.9+nobinonly
switch.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039 ** File:            switch.cpp
00040 ** Description:     trying to time context switches
00041 */
00042 
00043 #include "rccv.h"
00044 #include "rcinrval.h"
00045 #include "rclock.h"
00046 #include "rcthread.h"
00047 
00048 #include <prio.h>
00049 #include <prlog.h>
00050 #include <prprf.h>
00051 #include <plerror.h>
00052 #include <plgetopt.h>
00053 
00054 #include <stdlib.h>
00055 
00056 #define INNER_LOOPS 100
00057 #define DEFAULT_LOOPS 100
00058 #define DEFAULT_THREADS 10
00059 
00060 static PRFileDesc *debug_out = NULL;
00061 static PRBool debug_mode = PR_FALSE, verbosity = PR_FALSE, failed = PR_FALSE;
00062 
00063 class Home: public RCCondition
00064 {
00065 public:
00066     virtual ~Home();
00067     Home(Home *link, RCLock* ml);
00068 
00069 public:
00070     Home *next;
00071     RCLock* ml;
00072     PRBool twiddle;
00073 };  /* Home */
00074 
00075 Home::~Home() { }
00076 
00077 Home::Home(Home *link, RCLock* lock): RCCondition(lock)
00078 {
00079     ml = lock;
00080     next = link;
00081     twiddle = PR_FALSE;
00082 }  /* Home::Home */
00083 
00084 class Shared: public Home, public RCThread
00085 {
00086 public:
00087     Shared(RCThread::Scope scope, Home* link, RCLock* ml);
00088 
00089 private:
00090     ~Shared();
00091     void RootFunction();
00092 };  /* Shared */
00093 
00094 Shared::Shared(RCThread::Scope scope, Home* link, RCLock* lock):
00095     Home(link, lock), RCThread(scope, RCThread::joinable) { }
00096 
00097 Shared::~Shared() { }
00098 
00099 void Shared::RootFunction()
00100 {
00101     PRStatus status = PR_SUCCESS;
00102     while (PR_SUCCESS == status)
00103     {
00104         RCEnter entry(ml);
00105         while (twiddle && (PR_SUCCESS == status)) status = Wait();
00106               if (verbosity) PR_fprintf(debug_out, "+");
00107         twiddle = PR_TRUE;
00108         next->twiddle = PR_FALSE;
00109         next->Notify();
00110     }
00111 }  /* Shared::RootFunction */
00112 
00113 static void Help(void)
00114 {
00115     debug_out = PR_STDOUT;
00116 
00117     PR_fprintf(
00118               debug_out, "Usage: >./switch [-d] [-c n] [-t n] [-T n] [-G]\n");
00119     PR_fprintf(
00120               debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS);
00121     PR_fprintf(
00122               debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS);
00123     PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n");
00124     PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n");
00125     PR_fprintf(debug_out, "-G n\tglobal threads only (default: FALSE)\n");
00126     PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n");
00127 }  /* Help */
00128 
00129 PRIntn main(PRIntn argc, char **argv)
00130 {
00131        PLOptStatus os;
00132     PRStatus status;
00133     PRBool help = PR_FALSE;
00134     PRUintn concurrency = 1;
00135     RCThread::Scope thread_scope = RCThread::local;
00136     PRUintn thread_count, inner_count, loop_count, average;
00137     PRUintn thread_limit = DEFAULT_THREADS, loop_limit = DEFAULT_LOOPS;
00138        PLOptState *opt = PL_CreateOptState(argc, argv, "hdvc:t:C:G");
00139        while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
00140     {
00141               if (PL_OPT_BAD == os) continue;
00142         switch (opt->option)
00143         {
00144         case 'v':  /* verbose mode */
00145                      verbosity = PR_TRUE;
00146         case 'd':  /* debug mode */
00147                      debug_mode = PR_TRUE;
00148             break;
00149         case 'c':  /* loop counter */
00150                      loop_limit = atoi(opt->value);
00151             break;
00152         case 't':  /* thread limit */
00153                      thread_limit = atoi(opt->value);
00154             break;
00155         case 'C':  /* Concurrency limit */
00156                      concurrency = atoi(opt->value);
00157             break;
00158         case 'G':  /* global threads only */
00159                      thread_scope = RCThread::global;
00160             break;
00161         case 'h':  /* help message */
00162                      Help();
00163                      help = PR_TRUE;
00164             break;
00165          default:
00166             break;
00167         }
00168     }
00169        PL_DestroyOptState(opt);
00170 
00171     if (help) return -1;
00172 
00173        if (PR_TRUE == debug_mode)
00174        {
00175               debug_out = PR_STDOUT;
00176               PR_fprintf(debug_out, "Test parameters\n");
00177               PR_fprintf(debug_out, "\tThreads involved: %d\n", thread_limit);
00178               PR_fprintf(debug_out, "\tIteration limit: %d\n", loop_limit);
00179               PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency);
00180               PR_fprintf(
00181                      debug_out, "\tThread type: %s\n",
00182                      (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL");
00183        }
00184 
00185     /*
00186     ** The interesting part starts here
00187     */
00188     RCLock lock;
00189     Shared* shared;
00190     Home home(NULL, &lock);
00191     Home* link = &home;
00192     RCInterval timein, timeout = 0;
00193 
00194     /* Build up the string of objects */
00195     for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
00196     {
00197         shared = new Shared(thread_scope, link, &lock);
00198         shared->Start();  /* make it run */
00199         link = (Home*)shared;
00200        }
00201 
00202     /* Pass the message around the horn a few times */
00203     for (loop_count = 1; loop_count <= loop_limit; ++loop_count)
00204     {
00205               timein.SetToNow();
00206               for (inner_count = 0; inner_count < INNER_LOOPS; ++inner_count)
00207               {
00208                      RCEnter entry(&lock);
00209                      home.twiddle = PR_TRUE;
00210                      shared->twiddle = PR_FALSE;
00211                      shared->Notify();
00212                      while (home.twiddle)
00213             {
00214                             failed = (PR_FAILURE == home.Wait()) ? PR_TRUE : PR_FALSE;
00215             }
00216               }
00217               timeout += (RCInterval(RCInterval::now) - timein);
00218        }
00219 
00220     /* Figure out how well we did */
00221        if (debug_mode)
00222        {
00223               average = timeout.ToMicroseconds()
00224                      / (INNER_LOOPS * loop_limit * thread_count);
00225               PR_fprintf(
00226                      debug_out, "Average switch times %d usecs for %d threads\n",
00227             average, thread_limit);
00228        }
00229 
00230     /* Start reclamation process */
00231     link = shared;
00232     for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
00233     {
00234         if (&home == link) break;
00235         status = ((Shared*)link)->Interrupt();
00236               if (PR_SUCCESS != status)
00237         {
00238             failed = PR_TRUE;
00239             if (debug_mode)
00240                          PL_FPrintError(debug_out, "Failed to interrupt");
00241         }
00242               link = link->next; 
00243     }
00244 
00245     for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
00246     {
00247         link = shared->next;
00248         status = shared->Join();
00249               if (PR_SUCCESS != status)
00250               {
00251             failed = PR_TRUE;
00252             if (debug_mode)
00253                          PL_FPrintError(debug_out, "Failed to join");
00254         }
00255         if (&home == link) break;
00256         shared = (Shared*)link;
00257     }
00258 
00259     PR_fprintf(PR_STDOUT, ((failed) ? "FAILED\n" : "PASSED\n"));
00260 
00261     failed |= (PR_SUCCESS == RCPrimordialThread::Cleanup());
00262 
00263     return ((failed) ? 1 : 0);
00264 }  /* main */
00265 
00266 /* switch.c */