Back to index

lightning-sunbird  0.9+nobinonly
switch.c
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.c
00040 ** Description:     trying to time context switches
00041 */
00042 
00043 #include "prinit.h"
00044 #include "prcvar.h"
00045 #include "prmem.h"
00046 #include "prinrval.h"
00047 #include "prlock.h"
00048 #include "prlog.h"
00049 #include "prthread.h"
00050 #include "prprf.h"
00051 
00052 #include "plerror.h"
00053 #include "plgetopt.h"
00054 
00055 #if defined(XP_MAC)
00056 #include "pprio.h"
00057 #define printf PR_LogPrint
00058 #else
00059 #include "private/pprio.h"
00060 #endif
00061 
00062 #include <stdlib.h>
00063 
00064 #define INNER_LOOPS 100
00065 #define DEFAULT_LOOPS 100
00066 #define DEFAULT_THREADS 10
00067 
00068 static PRFileDesc *debug_out = NULL;
00069 static PRBool debug_mode = PR_FALSE, verbosity = PR_FALSE, failed = PR_FALSE;
00070 
00071 typedef struct Shared
00072 {
00073     PRLock *ml;
00074     PRCondVar *cv;
00075     PRBool twiddle;
00076     PRThread *thread;
00077     struct Shared *next;
00078 } Shared;
00079 
00080 static void Help(void)
00081 {
00082     debug_out = PR_STDOUT;
00083 
00084     PR_fprintf(
00085               debug_out, "Usage: >./switch [-c n] [-t n] [-d] [-v] [-G] [-C n]\n");
00086     PR_fprintf(
00087               debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS);
00088     PR_fprintf(
00089               debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS);
00090     PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n");
00091     PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n");
00092     PR_fprintf(debug_out, "-G\tglobal threads only (default: FALSE)\n");
00093     PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n");
00094 }  /* Help */
00095 
00096 static void PR_CALLBACK Notified(void *arg)
00097 {
00098     Shared *shared = (Shared*)arg;
00099     PRStatus status = PR_SUCCESS;
00100     while (PR_SUCCESS == status)
00101     {
00102         PR_Lock(shared->ml);
00103         while (shared->twiddle && (PR_SUCCESS == status))
00104             status = PR_WaitCondVar(shared->cv, PR_INTERVAL_NO_TIMEOUT);
00105               if (verbosity) PR_fprintf(debug_out, "+");
00106         shared->twiddle = PR_TRUE;
00107         shared->next->twiddle = PR_FALSE;
00108         PR_NotifyCondVar(shared->next->cv);
00109         PR_Unlock(shared->ml);
00110     }
00111 }  /* Notified */
00112 
00113 static Shared home;
00114 PRIntn PR_CALLBACK Switch(PRIntn argc, char **argv)
00115 {
00116        PLOptStatus os;
00117     PRStatus status;
00118     PRBool help = PR_FALSE;
00119     PRUintn concurrency = 1;
00120     Shared *shared, *link;
00121     PRIntervalTime timein, timeout;
00122     PRThreadScope thread_scope = PR_LOCAL_THREAD;
00123     PRUintn thread_count, inner_count, loop_count, average;
00124     PRUintn thread_limit = DEFAULT_THREADS, loop_limit = DEFAULT_LOOPS;
00125        PLOptState *opt = PL_CreateOptState(argc, argv, "hdvc:t:C:G");
00126        while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
00127     {
00128               if (PL_OPT_BAD == os) continue;
00129         switch (opt->option)
00130         {
00131         case 'v':  /* verbose mode */
00132                      verbosity = PR_TRUE;
00133         case 'd':  /* debug mode */
00134                      debug_mode = PR_TRUE;
00135             break;
00136         case 'c':  /* loop counter */
00137                      loop_limit = atoi(opt->value);
00138             break;
00139         case 't':  /* thread limit */
00140                      thread_limit = atoi(opt->value);
00141             break;
00142         case 'C':  /* Concurrency limit */
00143                      concurrency = atoi(opt->value);
00144             break;
00145         case 'G':  /* global threads only */
00146                      thread_scope = PR_GLOBAL_THREAD;
00147             break;
00148         case 'h':  /* help message */
00149                      Help();
00150                      help = PR_TRUE;
00151             break;
00152          default:
00153             break;
00154         }
00155     }
00156        PL_DestroyOptState(opt);
00157 
00158     if (help) return -1;
00159 
00160        if (PR_TRUE == debug_mode)
00161        {
00162               debug_out = PR_STDOUT;
00163               PR_fprintf(debug_out, "Test parameters\n");
00164               PR_fprintf(debug_out, "\tThreads involved: %d\n", thread_limit);
00165               PR_fprintf(debug_out, "\tIteration limit: %d\n", loop_limit);
00166               PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency);
00167               PR_fprintf(
00168                      debug_out, "\tThread type: %s\n",
00169                      (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL");
00170        }
00171 
00172     PR_SetConcurrency(concurrency);
00173 
00174     link = &home;
00175     home.ml = PR_NewLock();
00176     home.cv = PR_NewCondVar(home.ml);
00177     home.twiddle = PR_FALSE;
00178     home.next = NULL;
00179 
00180     timeout = 0;
00181 
00182     for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
00183     {
00184         shared = PR_NEWZAP(Shared);
00185 
00186         shared->ml = home.ml;
00187         shared->cv = PR_NewCondVar(home.ml);
00188         shared->twiddle = PR_TRUE;
00189         shared->next = link;
00190         link = shared;
00191 
00192         shared->thread = PR_CreateThread(
00193             PR_USER_THREAD, Notified, shared,
00194             PR_PRIORITY_HIGH, thread_scope,
00195             PR_JOINABLE_THREAD, 0);
00196         PR_ASSERT(shared->thread != NULL);
00197         if (NULL == shared->thread)
00198             failed = PR_TRUE;
00199        }
00200 
00201     for (loop_count = 1; loop_count <= loop_limit; ++loop_count)
00202     {
00203               timein = PR_IntervalNow();
00204               for (inner_count = 0; inner_count < INNER_LOOPS; ++inner_count)
00205               {
00206                      PR_Lock(home.ml);
00207                      home.twiddle = PR_TRUE;
00208                      shared->twiddle = PR_FALSE;
00209                      PR_NotifyCondVar(shared->cv);
00210                      while (home.twiddle)
00211             {
00212                             status = PR_WaitCondVar(home.cv, PR_INTERVAL_NO_TIMEOUT);
00213                             if (PR_FAILURE == status)
00214                                 failed = PR_TRUE;
00215             }
00216                      PR_Unlock(home.ml);
00217               }
00218               timeout += (PR_IntervalNow() - timein);
00219        }
00220 
00221        if (debug_mode)
00222        {
00223               average = PR_IntervalToMicroseconds(timeout)
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     link = shared;
00231     for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
00232     {
00233         if (&home == link) break;
00234         status = PR_Interrupt(link->thread);
00235               if (PR_SUCCESS != status)
00236         {
00237             failed = PR_TRUE;
00238             if (debug_mode)
00239                          PL_FPrintError(debug_out, "Failed to interrupt");
00240         }
00241               link = link->next; 
00242     }
00243 
00244     for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
00245     {
00246         link = shared->next;
00247         status = PR_JoinThread(shared->thread);
00248               if (PR_SUCCESS != status)
00249               {
00250             failed = PR_TRUE;
00251             if (debug_mode)
00252                          PL_FPrintError(debug_out, "Failed to join");
00253         }
00254         PR_DestroyCondVar(shared->cv);
00255         PR_DELETE(shared);
00256         if (&home == link) break;
00257         shared = link;
00258     }
00259     PR_DestroyCondVar(home.cv);
00260     PR_DestroyLock(home.ml);
00261 
00262     PR_fprintf(PR_STDOUT, ((failed) ? "FAILED\n" : "PASSED\n"));
00263     return ((failed) ? 1 : 0);
00264 }  /* Switch */
00265 
00266 PRIntn main(PRIntn argc, char **argv)
00267 {
00268     PRIntn result;
00269     PR_STDIO_INIT();
00270     result = PR_Initialize(Switch, argc, argv, 0);
00271     return result;
00272 }  /* main */
00273 
00274 /* switch.c */