tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

instrumt.c (11618B)


      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/. */
      5 
      6 /*
      7 ** File:    instrumt.c
      8 ** Description: This test is for the NSPR debug aids defined in
      9 ** prcountr.h, prtrace.h, prolock.h
     10 **
     11 ** The test case tests the three debug aids in NSPR:
     12 **
     13 ** Diagnostic messages can be enabled using "instrumt -v 6"
     14 ** This sets the msgLevel to something that PR_LOG() likes.
     15 ** Also define in the environment "NSPR_LOG_MODULES=Test:6"
     16 **
     17 ** CounterTest() tests the counter facility. This test
     18 ** creates 4 threads. Each thread either increments, decrements,
     19 ** adds to or subtracts from a counter, depending on an argument
     20 ** passed to the thread at thread-create time. Each of these threads
     21 ** does COUNT_LIMIT iterations doing its thing. When all 4 threads
     22 ** are done, the result of the counter is evaluated. If all was atomic,
     23 ** the the value of the counter should be zero.
     24 **
     25 ** TraceTest():
     26 ** This test mingles with the counter test. Counters trace.
     27 ** A thread to extract trace entries on the fly is started.
     28 ** A thread to dump trace entries to a file is started.
     29 **
     30 ** OrderedLockTest():
     31 **
     32 **
     33 **
     34 **
     35 **
     36 */
     37 
     38 #include <stdio.h>
     39 #include <plstr.h>
     40 #include <prclist.h>
     41 #include <prmem.h>
     42 #include <plgetopt.h>
     43 #include <prlog.h>
     44 #include <prmon.h>
     45 #include <pratom.h>
     46 #include <prtrace.h>
     47 #include <prcountr.h>
     48 #include <prolock.h>
     49 
     50 #define COUNT_LIMIT (10 * (1024))
     51 
     52 #define SMALL_TRACE_BUFSIZE (60 * 1024)
     53 
     54 typedef enum { CountLoop = 1, TraceLoop = 2, TraceFlow = 3 } TraceTypes;
     55 
     56 PRLogModuleLevel msgLevel = PR_LOG_ALWAYS;
     57 
     58 PRBool help = PR_FALSE;
     59 PRBool failed = PR_FALSE;
     60 
     61 PRLogModuleInfo* lm;
     62 PRMonitor* mon;
     63 PRInt32 activeThreads = 0;
     64 PR_DEFINE_COUNTER(hCounter);
     65 PR_DEFINE_TRACE(hTrace);
     66 
     67 static void Help(void) { printf("Help? ... Ha!\n"); }
     68 
     69 static void ListCounters(void) {
     70  PR_DEFINE_COUNTER(qh);
     71  PR_DEFINE_COUNTER(rh);
     72  const char *qn, *rn, *dn;
     73  const char **qname = &qn, **rname = &rn, **desc = &dn;
     74  PRUint32 tCtr;
     75 
     76  PR_INIT_COUNTER_HANDLE(qh, NULL);
     77  PR_FIND_NEXT_COUNTER_QNAME(qh, qh);
     78  while (qh != NULL) {
     79    PR_INIT_COUNTER_HANDLE(rh, NULL);
     80    PR_FIND_NEXT_COUNTER_RNAME(rh, rh, qh);
     81    while (rh != NULL) {
     82      PR_GET_COUNTER_NAME_FROM_HANDLE(rh, qname, rname, desc);
     83      PR_GET_COUNTER(tCtr, rh);
     84      PR_LOG(
     85          lm, msgLevel,
     86          ("QName: %s  RName: %s  Desc: %s  Value: %ld\n", qn, rn, dn, tCtr));
     87      PR_FIND_NEXT_COUNTER_RNAME(rh, rh, qh);
     88    }
     89    PR_FIND_NEXT_COUNTER_QNAME(qh, qh);
     90  }
     91  return;
     92 } /* end ListCounters() */
     93 
     94 static void ListTraces(void) {
     95  PR_DEFINE_TRACE(qh);
     96  PR_DEFINE_TRACE(rh);
     97  const char *qn, *rn, *dn;
     98  const char **qname = &qn, **rname = &rn, **desc = &dn;
     99 
    100  PR_INIT_TRACE_HANDLE(qh, NULL);
    101  PR_FIND_NEXT_TRACE_QNAME(qh, qh);
    102  while (qh != NULL) {
    103    PR_INIT_TRACE_HANDLE(rh, NULL);
    104    PR_FIND_NEXT_TRACE_RNAME(rh, rh, qh);
    105    while (rh != NULL) {
    106      PR_GET_TRACE_NAME_FROM_HANDLE(rh, qname, rname, desc);
    107      PR_LOG(lm, msgLevel, ("QName: %s  RName: %s  Desc: %s", qn, rn, dn));
    108      PR_FIND_NEXT_TRACE_RNAME(rh, rh, qh);
    109    }
    110    PR_FIND_NEXT_TRACE_QNAME(qh, qh);
    111  }
    112  return;
    113 } /* end ListCounters() */
    114 
    115 static PRInt32 one = 1;
    116 static PRInt32 two = 2;
    117 static PRInt32 three = 3;
    118 static PRInt32 four = 4;
    119 
    120 /*
    121 ** Thread to iteratively count something.
    122 */
    123 static void PR_CALLBACK CountSomething(void* arg) {
    124  PRInt32 switchVar = *((PRInt32*)arg);
    125  PRInt32 i;
    126 
    127  PR_LOG(lm, msgLevel, ("CountSomething: begin thread %ld", switchVar));
    128 
    129  for (i = 0; i < COUNT_LIMIT; i++) {
    130    switch (switchVar) {
    131      case 1:
    132        PR_INCREMENT_COUNTER(hCounter);
    133        break;
    134      case 2:
    135        PR_DECREMENT_COUNTER(hCounter);
    136        break;
    137      case 3:
    138        PR_ADD_TO_COUNTER(hCounter, 1);
    139        break;
    140      case 4:
    141        PR_SUBTRACT_FROM_COUNTER(hCounter, 1);
    142        break;
    143      default:
    144        PR_ASSERT(0);
    145        break;
    146    }
    147    PR_TRACE(hTrace, CountLoop, switchVar, i, 0, 0, 0, 0, 0);
    148  } /* end for() */
    149 
    150  PR_LOG(lm, msgLevel, ("CounterSomething: end thread %ld", switchVar));
    151 
    152  PR_EnterMonitor(mon);
    153  --activeThreads;
    154  PR_Notify(mon);
    155  PR_ExitMonitor(mon);
    156 
    157  return;
    158 } /* end CountSomething() */
    159 
    160 /*
    161 ** Create the counter threads.
    162 */
    163 static void CounterTest(void) {
    164  PRThread *t1, *t2, *t3, *t4;
    165  PRIntn i = 0;
    166  PR_DEFINE_COUNTER(tc);
    167  PR_DEFINE_COUNTER(zCounter);
    168 
    169  PR_LOG(lm, msgLevel, ("Begin CounterTest"));
    170 
    171  /*
    172  ** Test Get and Set of a counter.
    173  **
    174  */
    175  PR_CREATE_COUNTER(zCounter, "Atomic", "get/set test",
    176                    "test get and set of counter");
    177  PR_SET_COUNTER(zCounter, 9);
    178  PR_GET_COUNTER(i, zCounter);
    179  if (i != 9) {
    180    failed = PR_TRUE;
    181    PR_LOG(lm, msgLevel, ("Counter set/get failed"));
    182  }
    183 
    184  activeThreads += 4;
    185  PR_CREATE_COUNTER(hCounter, "Atomic", "SMP Tests",
    186                    "test atomic nature of counter");
    187 
    188  PR_GET_COUNTER_HANDLE_FROM_NAME(tc, "Atomic", "SMP Tests");
    189  PR_ASSERT(tc == hCounter);
    190 
    191  t1 = PR_CreateThread(PR_USER_THREAD, CountSomething, &one, PR_PRIORITY_NORMAL,
    192                       PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
    193  PR_ASSERT(t1);
    194 
    195  t2 = PR_CreateThread(PR_USER_THREAD, CountSomething, &two, PR_PRIORITY_NORMAL,
    196                       PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
    197  PR_ASSERT(t2);
    198 
    199  t3 = PR_CreateThread(PR_USER_THREAD, CountSomething, &three,
    200                       PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
    201                       PR_UNJOINABLE_THREAD, 0);
    202  PR_ASSERT(t3);
    203 
    204  t4 =
    205      PR_CreateThread(PR_USER_THREAD, CountSomething, &four, PR_PRIORITY_NORMAL,
    206                      PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
    207  PR_ASSERT(t4);
    208 
    209  PR_LOG(lm, msgLevel, ("Counter Threads started"));
    210 
    211  ListCounters();
    212  return;
    213 } /* end CounterTest() */
    214 
    215 /*
    216 ** Thread to dump trace buffer to a file.
    217 */
    218 static void PR_CALLBACK RecordTrace(void* arg) {
    219  PR_RECORD_TRACE_ENTRIES();
    220 
    221  PR_EnterMonitor(mon);
    222  --activeThreads;
    223  PR_Notify(mon);
    224  PR_ExitMonitor(mon);
    225 
    226  return;
    227 } /* end RecordTrace() */
    228 
    229 #define NUM_TRACE_RECORDS (10000)
    230 /*
    231 ** Thread to extract and print trace entries from the buffer.
    232 */
    233 static void PR_CALLBACK SampleTrace(void* arg) {
    234 #if defined(DEBUG) || defined(FORCE_NSPR_TRACE)
    235  PRInt32 found, rc;
    236  PRTraceEntry* foundEntries;
    237  PRInt32 i;
    238 
    239  foundEntries =
    240      (PRTraceEntry*)PR_Malloc(NUM_TRACE_RECORDS * sizeof(PRTraceEntry));
    241  PR_ASSERT(foundEntries != NULL);
    242 
    243  do {
    244    rc = PR_GetTraceEntries(foundEntries, NUM_TRACE_RECORDS, &found);
    245    PR_LOG(lm, msgLevel, ("SampleTrace: Lost Data: %ld found: %ld", rc, found));
    246 
    247    if (found != 0) {
    248      for (i = 0; i < found; i++) {
    249        PR_LOG(
    250            lm, msgLevel,
    251            ("SampleTrace, detail: Thread: %p, Time: %llX, UD0: %ld, UD1: %ld, "
    252             "UD2: %8.8ld",
    253             (foundEntries + i)->thread, (foundEntries + i)->time,
    254             (foundEntries + i)->userData[0], (foundEntries + i)->userData[1],
    255             (foundEntries + i)->userData[2]));
    256      }
    257    }
    258    PR_Sleep(PR_MillisecondsToInterval(50));
    259  } while (found != 0 && activeThreads >= 1);
    260 
    261  PR_Free(foundEntries);
    262 
    263  PR_EnterMonitor(mon);
    264  --activeThreads;
    265  PR_Notify(mon);
    266  PR_ExitMonitor(mon);
    267 
    268  PR_LOG(lm, msgLevel, ("SampleTrace(): exiting"));
    269 
    270 #endif
    271  return;
    272 } /* end RecordTrace() */
    273 
    274 /*
    275 ** Basic trace test.
    276 */
    277 static void TraceTest(void) {
    278  PRInt32 i;
    279  PRInt32 size;
    280  PR_DEFINE_TRACE(th);
    281  PRThread *t1, *t2;
    282 
    283  PR_LOG(lm, msgLevel, ("Begin TraceTest"));
    284 
    285  size = SMALL_TRACE_BUFSIZE;
    286  PR_SET_TRACE_OPTION(PRTraceBufSize, &size);
    287  PR_GET_TRACE_OPTION(PRTraceBufSize, &i);
    288 
    289  PR_CREATE_TRACE(th, "TraceTest", "tt2", "A description for the trace test");
    290  PR_CREATE_TRACE(th, "TraceTest", "tt3", "A description for the trace test");
    291  PR_CREATE_TRACE(th, "TraceTest", "tt4", "A description for the trace test");
    292  PR_CREATE_TRACE(th, "TraceTest", "tt5", "A description for the trace test");
    293  PR_CREATE_TRACE(th, "TraceTest", "tt6", "A description for the trace test");
    294  PR_CREATE_TRACE(th, "TraceTest", "tt7", "A description for the trace test");
    295  PR_CREATE_TRACE(th, "TraceTest", "tt8", "A description for the trace test");
    296 
    297  PR_CREATE_TRACE(th, "Trace Test", "tt0",
    298                  "QName is Trace Test, not TraceTest");
    299  PR_CREATE_TRACE(th, "Trace Test", "tt1",
    300                  "QName is Trace Test, not TraceTest");
    301  PR_CREATE_TRACE(th, "Trace Test", "tt2",
    302                  "QName is Trace Test, not TraceTest");
    303  PR_CREATE_TRACE(th, "Trace Test", "tt3",
    304                  "QName is Trace Test, not TraceTest");
    305  PR_CREATE_TRACE(th, "Trace Test", "tt4",
    306                  "QName is Trace Test, not TraceTest");
    307  PR_CREATE_TRACE(th, "Trace Test", "tt5",
    308                  "QName is Trace Test, not TraceTest");
    309  PR_CREATE_TRACE(th, "Trace Test", "tt6",
    310                  "QName is Trace Test, not TraceTest");
    311  PR_CREATE_TRACE(th, "Trace Test", "tt7",
    312                  "QName is Trace Test, not TraceTest");
    313  PR_CREATE_TRACE(th, "Trace Test", "tt8",
    314                  "QName is Trace Test, not TraceTest");
    315  PR_CREATE_TRACE(th, "Trace Test", "tt9",
    316                  "QName is Trace Test, not TraceTest");
    317  PR_CREATE_TRACE(th, "Trace Test", "tt10",
    318                  "QName is Trace Test, not TraceTest");
    319 
    320  activeThreads += 2;
    321  t1 = PR_CreateThread(PR_USER_THREAD, RecordTrace, NULL, PR_PRIORITY_NORMAL,
    322                       PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
    323  PR_ASSERT(t1);
    324 
    325  t2 = PR_CreateThread(PR_USER_THREAD, SampleTrace, 0, PR_PRIORITY_NORMAL,
    326                       PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
    327  PR_ASSERT(t2);
    328 
    329  ListTraces();
    330 
    331  PR_GET_TRACE_HANDLE_FROM_NAME(th, "TraceTest", "tt1");
    332  PR_ASSERT(th == hTrace);
    333 
    334  PR_LOG(lm, msgLevel, ("End TraceTest"));
    335  return;
    336 } /* end TraceTest() */
    337 
    338 /*
    339 ** Ordered lock test.
    340 */
    341 static void OrderedLockTest(void) {
    342  PR_LOG(lm, msgLevel, ("Begin OrderedLockTest"));
    343 
    344 } /* end OrderedLockTest() */
    345 
    346 int main(int argc, char** argv) {
    347 #if defined(DEBUG) || defined(FORCE_NSPR_TRACE)
    348  PRUint32 counter;
    349  PLOptStatus os;
    350  PLOptState* opt = PL_CreateOptState(argc, argv, "hdv:");
    351  lm = PR_NewLogModule("Test");
    352 
    353  while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
    354    if (PL_OPT_BAD == os) {
    355      continue;
    356    }
    357    switch (opt->option) {
    358      case 'v': /* verbose mode */
    359        msgLevel = (PRLogModuleLevel)atol(opt->value);
    360        break;
    361      case 'h': /* help message */
    362        Help();
    363        help = PR_TRUE;
    364        break;
    365      default:
    366        break;
    367    }
    368  }
    369  PL_DestroyOptState(opt);
    370 
    371  PR_CREATE_TRACE(hTrace, "TraceTest", "tt1",
    372                  "A description for the trace test");
    373  mon = PR_NewMonitor();
    374  PR_EnterMonitor(mon);
    375 
    376  TraceTest();
    377  CounterTest();
    378  OrderedLockTest();
    379 
    380  /* Wait for all threads to exit */
    381  while (activeThreads > 0) {
    382    if (activeThreads == 1) {
    383      PR_SET_TRACE_OPTION(PRTraceStopRecording, NULL);
    384    }
    385    PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
    386    PR_GET_COUNTER(counter, hCounter);
    387  }
    388  PR_ExitMonitor(mon);
    389 
    390  /*
    391  ** Evaluate results
    392  */
    393  PR_GET_COUNTER(counter, hCounter);
    394  if (counter != 0) {
    395    failed = PR_TRUE;
    396    PR_LOG(lm, msgLevel, ("Expected counter == 0, found: %ld", counter));
    397    printf("FAIL\n");
    398  } else {
    399    printf("PASS\n");
    400  }
    401 
    402  PR_DESTROY_COUNTER(hCounter);
    403 
    404  PR_DestroyMonitor(mon);
    405 
    406  PR_TRACE(hTrace, TraceFlow, 0xfff, 0, 0, 0, 0, 0, 0);
    407  PR_DESTROY_TRACE(hTrace);
    408 #else
    409  printf("Test not defined\n");
    410 #endif
    411  return 0;
    412 } /* main() */
    413 /* end instrumt.c */