Back to index

lightning-sunbird  0.9+nobinonly
instrumt.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:    instrumt.c
00040 ** Description: This test is for the NSPR debug aids defined in
00041 ** prcountr.h, prtrace.h, prolock.h
00042 **
00043 ** The test case tests the three debug aids in NSPR:
00044 **
00045 ** Diagnostic messages can be enabled using "instrumt -v 6"
00046 ** This sets the msgLevel to something that PR_LOG() likes.
00047 ** Also define in the environment "NSPR_LOG_MODULES=Test:6"
00048 **
00049 ** CounterTest() tests the counter facility. This test
00050 ** creates 4 threads. Each thread either increments, decrements,
00051 ** adds to or subtracts from a counter, depending on an argument
00052 ** passed to the thread at thread-create time. Each of these threads
00053 ** does COUNT_LIMIT iterations doing its thing. When all 4 threads
00054 ** are done, the result of the counter is evaluated. If all was atomic,
00055 ** the the value of the counter should be zero.
00056 **
00057 ** TraceTest():
00058 ** This test mingles with the counter test. Counters trace.
00059 ** A thread to extract trace entries on the fly is started.
00060 ** A thread to dump trace entries to a file is started.
00061 **
00062 ** OrderedLockTest():
00063 **
00064 **
00065 **
00066 **
00067 **
00068 */
00069 
00070 #include <stdio.h>
00071 #include <plstr.h>
00072 #include <prclist.h>
00073 #include <prmem.h>
00074 #include <plgetopt.h> 
00075 #include <prlog.h> 
00076 #include <prmon.h> 
00077 #include <pratom.h> 
00078 #include <prtrace.h> 
00079 #include <prcountr.h> 
00080 #include <prolock.h> 
00081 
00082 #define COUNT_LIMIT  (10 * ( 1024))
00083 
00084 #define SMALL_TRACE_BUFSIZE  ( 60 * 1024 )
00085 
00086 typedef enum 
00087 {
00088     CountLoop = 1,
00089     TraceLoop = 2,
00090     TraceFlow = 3
00091 } TraceTypes;
00092 
00093 
00094 PRLogModuleLevel msgLevel = PR_LOG_ALWAYS;
00095 
00096 PRBool  help = PR_FALSE;
00097 PRBool  failed = PR_FALSE;
00098 
00099 
00100 PRLogModuleInfo *lm;
00101 PRMonitor   *mon;
00102 PRInt32     activeThreads = 0;
00103 PR_DEFINE_COUNTER( hCounter );
00104 PR_DEFINE_TRACE( hTrace );
00105 
00106 static void Help(void)
00107 {
00108     printf("Help? ... Ha!\n");
00109 }    
00110 
00111 static void ListCounters(void)
00112 {
00113     PR_DEFINE_COUNTER( qh );
00114     PR_DEFINE_COUNTER( rh );
00115     const char *qn, *rn, *dn;
00116     const char **qname = &qn, **rname = &rn, **desc = &dn;
00117     PRUint32    tCtr;
00118 
00119     PR_INIT_COUNTER_HANDLE( qh, NULL );
00120     PR_FIND_NEXT_COUNTER_QNAME(qh, qh );
00121     while ( qh != NULL )
00122     {
00123         PR_INIT_COUNTER_HANDLE( rh, NULL );
00124         PR_FIND_NEXT_COUNTER_RNAME(rh, rh, qh );
00125         while ( rh != NULL )
00126         {
00127             PR_GET_COUNTER_NAME_FROM_HANDLE( rh, qname, rname, desc );
00128             tCtr = PR_GET_COUNTER(tCtr, rh);
00129             PR_LOG( lm, msgLevel,
00130                 ( "QName: %s  RName: %s  Desc: %s  Value: %ld\n", 
00131                 qn, rn, dn, tCtr ));
00132             PR_FIND_NEXT_COUNTER_RNAME(rh, rh, qh );
00133         } 
00134         PR_FIND_NEXT_COUNTER_QNAME(qh, qh);
00135     }
00136     return;    
00137 } /* end ListCounters() */
00138 
00139 static void ListTraces(void)
00140 {
00141     PR_DEFINE_TRACE( qh );
00142     PR_DEFINE_TRACE( rh );
00143     const char *qn, *rn, *dn;
00144     const char **qname = &qn, **rname = &rn, **desc = &dn;
00145 
00146     PR_INIT_TRACE_HANDLE( qh, NULL );
00147     PR_FIND_NEXT_TRACE_QNAME(qh, qh );
00148     while ( qh != NULL )
00149     {
00150         PR_INIT_TRACE_HANDLE( rh, NULL );
00151         PR_FIND_NEXT_TRACE_RNAME(rh, rh, qh );
00152         while ( rh != NULL )
00153         {
00154             PR_GET_TRACE_NAME_FROM_HANDLE( rh, qname, rname, desc );
00155             PR_LOG( lm, msgLevel,
00156                 ( "QName: %s  RName: %s  Desc: %s", 
00157                 qn, rn, dn ));
00158             PR_FIND_NEXT_TRACE_RNAME(rh, rh, qh );
00159         } 
00160         PR_FIND_NEXT_TRACE_QNAME(qh, qh);
00161     }
00162     return;    
00163 } /* end ListCounters() */
00164 
00165 
00166 static PRInt32 one = 1;
00167 static PRInt32 two = 2;
00168 static PRInt32 three = 3;
00169 static PRInt32 four = 4;
00170 
00171 /*
00172 ** Thread to iteratively count something.
00173 */
00174 static void PR_CALLBACK CountSomething( void *arg )
00175 {
00176     PRInt32 switchVar = *((PRInt32 *)arg);
00177     PRInt32 i;
00178 
00179     PR_LOG( lm, msgLevel,
00180         ("CountSomething: begin thread %ld", switchVar ));
00181     
00182     for ( i = 0; i < COUNT_LIMIT ; i++)
00183     {
00184         switch ( switchVar )
00185         {
00186         case 1 :
00187             PR_INCREMENT_COUNTER( hCounter );
00188             break;
00189         case 2 :
00190             PR_DECREMENT_COUNTER( hCounter );
00191             break;
00192         case 3 :
00193             PR_ADD_TO_COUNTER( hCounter, 1 );
00194             break;
00195         case 4 :
00196             PR_SUBTRACT_FROM_COUNTER( hCounter, 1 );
00197             break;
00198         default :
00199             PR_ASSERT( 0 );
00200             break;
00201         }
00202         PR_TRACE( hTrace, CountLoop, switchVar, i, 0, 0, 0, 0, 0 );
00203     } /* end for() */
00204 
00205     PR_LOG( lm, msgLevel,
00206         ("CounterSomething: end thread %ld", switchVar ));
00207     
00208     PR_EnterMonitor(mon);
00209     --activeThreads;
00210     PR_Notify( mon );
00211     PR_ExitMonitor(mon);
00212 
00213     return;    
00214 } /* end CountSomething() */
00215 
00216 /*
00217 ** Create the counter threads.
00218 */
00219 static void CounterTest( void )
00220 {
00221     PRThread *t1, *t2, *t3, *t4;
00222     PRIntn i = 0;
00223     PR_DEFINE_COUNTER( tc );
00224     PR_DEFINE_COUNTER( zCounter );
00225 
00226     PR_LOG( lm, msgLevel,
00227         ("Begin CounterTest"));
00228     
00229     /*
00230     ** Test Get and Set of a counter.
00231     **
00232     */
00233     PR_CREATE_COUNTER( zCounter, "Atomic", "get/set test", "test get and set of counter" );
00234     PR_SET_COUNTER( zCounter, 9 );
00235     PR_GET_COUNTER( i, zCounter );
00236     if ( i != 9 )
00237     {
00238         failed = PR_TRUE;
00239         PR_LOG( lm, msgLevel,
00240             ("Counter set/get failed"));
00241     }
00242 
00243     activeThreads += 4;
00244     PR_CREATE_COUNTER( hCounter, "Atomic", "SMP Tests", "test atomic nature of counter" );
00245 
00246     PR_GET_COUNTER_HANDLE_FROM_NAME( tc, "Atomic", "SMP Tests" );
00247     PR_ASSERT( tc == hCounter );
00248 
00249        t1 = PR_CreateThread(PR_USER_THREAD,
00250                CountSomething, &one, 
00251                      PR_PRIORITY_NORMAL,
00252                      PR_GLOBAL_THREAD,
00253               PR_UNJOINABLE_THREAD,
00254                      0);
00255        PR_ASSERT(t1);
00256 
00257        t2 = PR_CreateThread(PR_USER_THREAD,
00258                      CountSomething, &two, 
00259                      PR_PRIORITY_NORMAL,
00260                      PR_GLOBAL_THREAD,
00261               PR_UNJOINABLE_THREAD,
00262                      0);
00263        PR_ASSERT(t2);
00264         
00265        t3 = PR_CreateThread(PR_USER_THREAD,
00266                      CountSomething, &three, 
00267                      PR_PRIORITY_NORMAL,
00268                      PR_GLOBAL_THREAD,
00269               PR_UNJOINABLE_THREAD,
00270                      0);
00271        PR_ASSERT(t3);
00272         
00273        t4 = PR_CreateThread(PR_USER_THREAD,
00274                      CountSomething, &four, 
00275                      PR_PRIORITY_NORMAL,
00276                      PR_GLOBAL_THREAD,
00277               PR_UNJOINABLE_THREAD,
00278                      0);
00279        PR_ASSERT(t4);
00280 
00281     PR_LOG( lm, msgLevel,
00282         ("Counter Threads started"));
00283 
00284     ListCounters();
00285     return;
00286 } /* end CounterTest() */
00287 
00288 /*
00289 ** Thread to dump trace buffer to a file.
00290 */
00291 static void PR_CALLBACK RecordTrace(void *arg )
00292 {
00293     PR_RECORD_TRACE_ENTRIES();
00294 
00295     PR_EnterMonitor(mon);
00296     --activeThreads;
00297     PR_Notify( mon );
00298     PR_ExitMonitor(mon);
00299 
00300     return;    
00301 } /* end RecordTrace() */
00302 
00303 
00304 
00305 #define NUM_TRACE_RECORDS ( 10000 )
00306 /*
00307 ** Thread to extract and print trace entries from the buffer.
00308 */
00309 static void PR_CALLBACK SampleTrace( void *arg )
00310 {
00311 #if defined(DEBUG) || defined(FORCE_NSPR_TRACE)
00312     PRInt32 found, rc;
00313     PRTraceEntry    *foundEntries;
00314     PRInt32 i;
00315     
00316     foundEntries = (PRTraceEntry *)PR_Malloc( NUM_TRACE_RECORDS * sizeof(PRTraceEntry));
00317     PR_ASSERT(foundEntries != NULL );
00318 
00319     do
00320     {
00321         rc = PR_GetTraceEntries( foundEntries, NUM_TRACE_RECORDS, &found);
00322         PR_LOG( lm, msgLevel,
00323             ("SampleTrace: Lost Data: %ld found: %ld", rc, found ));
00324 
00325         if ( found != 0)
00326         {
00327             for ( i = 0 ; i < found; i++ )
00328             {
00329                 PR_LOG( lm, msgLevel,
00330                     ("SampleTrace, detail: Thread: %p, Time: %llX, UD0: %ld, UD1: %ld, UD2: %8.8ld",
00331                         (foundEntries +i)->thread,
00332                         (foundEntries +i)->time,
00333                         (foundEntries +i)->userData[0], 
00334                         (foundEntries +i)->userData[1], 
00335                         (foundEntries +i)->userData[2] )); 
00336             }
00337         }
00338         PR_Sleep(PR_MillisecondsToInterval(50));
00339     }
00340     while( found != 0 && activeThreads >= 1 );
00341 
00342     PR_Free( foundEntries );
00343 
00344     PR_EnterMonitor(mon);
00345     --activeThreads;
00346     PR_Notify( mon );
00347     PR_ExitMonitor(mon);
00348 
00349     PR_LOG( lm, msgLevel,
00350         ("SampleTrace(): exiting"));
00351 
00352 #endif
00353     return;    
00354 } /* end RecordTrace() */
00355 
00356 /*
00357 ** Basic trace test.
00358 */
00359 static void TraceTest( void )
00360 {
00361     PRInt32 i;
00362     PRInt32 size;
00363     PR_DEFINE_TRACE( th );
00364     PRThread *t1, *t2;
00365     
00366     PR_LOG( lm, msgLevel,
00367         ("Begin TraceTest"));    
00368 
00369     size = SMALL_TRACE_BUFSIZE;
00370     PR_SET_TRACE_OPTION( PRTraceBufSize, &size );
00371     PR_GET_TRACE_OPTION( PRTraceBufSize, &i );
00372     
00373     PR_CREATE_TRACE( th, "TraceTest", "tt2", "A description for the trace test" );
00374     PR_CREATE_TRACE( th, "TraceTest", "tt3", "A description for the trace test" );
00375     PR_CREATE_TRACE( th, "TraceTest", "tt4", "A description for the trace test" );
00376     PR_CREATE_TRACE( th, "TraceTest", "tt5", "A description for the trace test" );
00377     PR_CREATE_TRACE( th, "TraceTest", "tt6", "A description for the trace test" );
00378     PR_CREATE_TRACE( th, "TraceTest", "tt7", "A description for the trace test" );
00379     PR_CREATE_TRACE( th, "TraceTest", "tt8", "A description for the trace test" );
00380 
00381     PR_CREATE_TRACE( th, "Trace Test", "tt0", "QName is Trace Test, not TraceTest" );
00382     PR_CREATE_TRACE( th, "Trace Test", "tt1", "QName is Trace Test, not TraceTest" );
00383     PR_CREATE_TRACE( th, "Trace Test", "tt2", "QName is Trace Test, not TraceTest" );
00384     PR_CREATE_TRACE( th, "Trace Test", "tt3", "QName is Trace Test, not TraceTest" );
00385     PR_CREATE_TRACE( th, "Trace Test", "tt4", "QName is Trace Test, not TraceTest" );
00386     PR_CREATE_TRACE( th, "Trace Test", "tt5", "QName is Trace Test, not TraceTest" );
00387     PR_CREATE_TRACE( th, "Trace Test", "tt6", "QName is Trace Test, not TraceTest" );
00388     PR_CREATE_TRACE( th, "Trace Test", "tt7", "QName is Trace Test, not TraceTest" );
00389     PR_CREATE_TRACE( th, "Trace Test", "tt8", "QName is Trace Test, not TraceTest" );
00390     PR_CREATE_TRACE( th, "Trace Test", "tt9", "QName is Trace Test, not TraceTest" );
00391     PR_CREATE_TRACE( th, "Trace Test", "tt10", "QName is Trace Test, not TraceTest" );
00392 
00393 
00394 
00395     activeThreads += 2;
00396        t1 = PR_CreateThread(PR_USER_THREAD,
00397                      RecordTrace, NULL, 
00398                      PR_PRIORITY_NORMAL,
00399                      PR_GLOBAL_THREAD,
00400               PR_UNJOINABLE_THREAD,
00401                      0);
00402        PR_ASSERT(t1);
00403 
00404        t2 = PR_CreateThread(PR_USER_THREAD,
00405                      SampleTrace, 0, 
00406                      PR_PRIORITY_NORMAL,
00407                      PR_GLOBAL_THREAD,
00408               PR_UNJOINABLE_THREAD,
00409                      0);
00410        PR_ASSERT(t2);
00411         
00412     ListTraces();
00413 
00414     PR_GET_TRACE_HANDLE_FROM_NAME( th, "TraceTest","tt1" );
00415     PR_ASSERT( th == hTrace );
00416 
00417     PR_LOG( lm, msgLevel,
00418         ("End TraceTest"));    
00419     return;
00420 } /* end TraceTest() */
00421 
00422 
00423 /*
00424 ** Ordered lock test.
00425 */
00426 static void OrderedLockTest( void )
00427 {
00428     PR_LOG( lm, msgLevel,
00429         ("Begin OrderedLockTest"));    
00430 
00431     
00432 } /* end OrderedLockTest() */
00433 
00434 
00435 PRIntn main(PRIntn argc, char *argv[])
00436 {
00437 #if defined(DEBUG) || defined(FORCE_NSPR_TRACE)
00438     PRUint32    counter;
00439     PLOptStatus os;
00440     PLOptState *opt = PL_CreateOptState(argc, argv, "hdv:");
00441     lm = PR_NewLogModule("Test");
00442 
00443        while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
00444     {
00445               if (PL_OPT_BAD == os) continue;
00446         switch (opt->option)
00447         {
00448         case 'v':  /* verbose mode */
00449                      msgLevel = (PRLogModuleLevel)atol( opt->value);
00450             break;
00451         case 'h':  /* help message */
00452                      Help();
00453                      help = PR_TRUE;
00454             break;
00455          default:
00456             break;
00457         }
00458     }
00459        PL_DestroyOptState(opt);
00460 
00461     PR_CREATE_TRACE( hTrace, "TraceTest", "tt1", "A description for the trace test" );
00462     mon = PR_NewMonitor();
00463     PR_EnterMonitor( mon );
00464 
00465     TraceTest();
00466     CounterTest();
00467     OrderedLockTest();
00468 
00469     /* Wait for all threads to exit */
00470     while ( activeThreads > 0 ) {
00471         if ( activeThreads == 1 )
00472             PR_SET_TRACE_OPTION( PRTraceStopRecording, NULL );
00473        PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
00474         PR_GET_COUNTER( counter, hCounter );
00475     }
00476     PR_ExitMonitor( mon );
00477 
00478     /*
00479     ** Evaluate results
00480     */
00481     PR_GET_COUNTER( counter, hCounter );
00482     if ( counter != 0 )
00483     {
00484         failed = PR_TRUE;
00485         PR_LOG( lm, msgLevel,
00486             ("Expected counter == 0, found: %ld", counter));
00487         printf("FAIL\n");
00488     }
00489     else
00490     {
00491         printf("PASS\n");
00492     }
00493 
00494 
00495     PR_DESTROY_COUNTER( hCounter );
00496 
00497     PR_DestroyMonitor( mon );
00498 
00499     PR_TRACE( hTrace, TraceFlow, 0xfff,0,0,0,0,0,0);
00500     PR_DESTROY_TRACE( hTrace );
00501 #else
00502     printf("Test not defined\n");
00503 #endif
00504     return 0;
00505 }  /* main() */
00506 /* end instrumt.c */
00507