tor-browser

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

switch.c (6417B)


      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:            switch.c
      8 ** Description:     trying to time context switches
      9 */
     10 
     11 #include "prinit.h"
     12 #include "prcvar.h"
     13 #include "prmem.h"
     14 #include "prinrval.h"
     15 #include "prlock.h"
     16 #include "prlog.h"
     17 #include "prthread.h"
     18 #include "prprf.h"
     19 
     20 #include "plerror.h"
     21 #include "plgetopt.h"
     22 
     23 #include "private/pprio.h"
     24 
     25 #include <stdlib.h>
     26 
     27 #define INNER_LOOPS 100
     28 #define DEFAULT_LOOPS 100
     29 #define DEFAULT_THREADS 10
     30 
     31 static PRFileDesc* debug_out = NULL;
     32 static PRBool debug_mode = PR_FALSE, verbosity = PR_FALSE, failed = PR_FALSE;
     33 
     34 typedef struct Shared {
     35  PRLock* ml;
     36  PRCondVar* cv;
     37  PRBool twiddle;
     38  PRThread* thread;
     39  struct Shared* next;
     40 } Shared;
     41 
     42 static void Help(void) {
     43  debug_out = PR_STDOUT;
     44 
     45  PR_fprintf(debug_out,
     46             "Usage: >./switch [-c n] [-t n] [-d] [-v] [-G] [-C n]\n");
     47  PR_fprintf(debug_out, "-c n\tloops at thread level (default: %d)\n",
     48             DEFAULT_LOOPS);
     49  PR_fprintf(debug_out, "-t n\tnumber of threads (default: %d)\n",
     50             DEFAULT_THREADS);
     51  PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n");
     52  PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n");
     53  PR_fprintf(debug_out, "-G\tglobal threads only (default: FALSE)\n");
     54  PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n");
     55 } /* Help */
     56 
     57 static void PR_CALLBACK Notified(void* arg) {
     58  Shared* shared = (Shared*)arg;
     59  PRStatus status = PR_SUCCESS;
     60  while (PR_SUCCESS == status) {
     61    PR_Lock(shared->ml);
     62    while (shared->twiddle && (PR_SUCCESS == status)) {
     63      status = PR_WaitCondVar(shared->cv, PR_INTERVAL_NO_TIMEOUT);
     64    }
     65    if (verbosity) {
     66      PR_fprintf(debug_out, "+");
     67    }
     68    shared->twiddle = PR_TRUE;
     69    shared->next->twiddle = PR_FALSE;
     70    PR_NotifyCondVar(shared->next->cv);
     71    PR_Unlock(shared->ml);
     72  }
     73 } /* Notified */
     74 
     75 static Shared home;
     76 PRIntn PR_CALLBACK Switch(PRIntn argc, char** argv) {
     77  PLOptStatus os;
     78  PRStatus status;
     79  PRBool help = PR_FALSE;
     80  PRUintn concurrency = 1;
     81  Shared *shared, *link;
     82  PRIntervalTime timein, timeout;
     83  PRThreadScope thread_scope = PR_LOCAL_THREAD;
     84  PRUintn thread_count, inner_count, loop_count, average;
     85  PRUintn thread_limit = DEFAULT_THREADS, loop_limit = DEFAULT_LOOPS;
     86  PLOptState* opt = PL_CreateOptState(argc, argv, "hdvc:t:C:G");
     87  while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
     88    if (PL_OPT_BAD == os) {
     89      continue;
     90    }
     91    switch (opt->option) {
     92      case 'v': /* verbose mode */
     93        verbosity = PR_TRUE;
     94      case 'd': /* debug mode */
     95        debug_mode = PR_TRUE;
     96        break;
     97      case 'c': /* loop counter */
     98        loop_limit = atoi(opt->value);
     99        break;
    100      case 't': /* thread limit */
    101        thread_limit = atoi(opt->value);
    102        break;
    103      case 'C': /* Concurrency limit */
    104        concurrency = atoi(opt->value);
    105        break;
    106      case 'G': /* global threads only */
    107        thread_scope = PR_GLOBAL_THREAD;
    108        break;
    109      case 'h': /* help message */
    110        Help();
    111        help = PR_TRUE;
    112        break;
    113      default:
    114        break;
    115    }
    116  }
    117  PL_DestroyOptState(opt);
    118 
    119  if (help) {
    120    return -1;
    121  }
    122 
    123  if (PR_TRUE == debug_mode) {
    124    debug_out = PR_STDOUT;
    125    PR_fprintf(debug_out, "Test parameters\n");
    126    PR_fprintf(debug_out, "\tThreads involved: %d\n", thread_limit);
    127    PR_fprintf(debug_out, "\tIteration limit: %d\n", loop_limit);
    128    PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency);
    129    PR_fprintf(debug_out, "\tThread type: %s\n",
    130               (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL");
    131  }
    132 
    133  PR_SetConcurrency(concurrency);
    134 
    135  link = &home;
    136  home.ml = PR_NewLock();
    137  home.cv = PR_NewCondVar(home.ml);
    138  home.twiddle = PR_FALSE;
    139  home.next = NULL;
    140 
    141  timeout = 0;
    142 
    143  for (thread_count = 1; thread_count <= thread_limit; ++thread_count) {
    144    shared = PR_NEWZAP(Shared);
    145 
    146    shared->ml = home.ml;
    147    shared->cv = PR_NewCondVar(home.ml);
    148    shared->twiddle = PR_TRUE;
    149    shared->next = link;
    150    link = shared;
    151 
    152    shared->thread =
    153        PR_CreateThread(PR_USER_THREAD, Notified, shared, PR_PRIORITY_HIGH,
    154                        thread_scope, PR_JOINABLE_THREAD, 0);
    155    PR_ASSERT(shared->thread != NULL);
    156    if (NULL == shared->thread) {
    157      failed = PR_TRUE;
    158    }
    159  }
    160 
    161  for (loop_count = 1; loop_count <= loop_limit; ++loop_count) {
    162    timein = PR_IntervalNow();
    163    for (inner_count = 0; inner_count < INNER_LOOPS; ++inner_count) {
    164      PR_Lock(home.ml);
    165      home.twiddle = PR_TRUE;
    166      shared->twiddle = PR_FALSE;
    167      PR_NotifyCondVar(shared->cv);
    168      while (home.twiddle) {
    169        status = PR_WaitCondVar(home.cv, PR_INTERVAL_NO_TIMEOUT);
    170        if (PR_FAILURE == status) {
    171          failed = PR_TRUE;
    172        }
    173      }
    174      PR_Unlock(home.ml);
    175    }
    176    timeout += (PR_IntervalNow() - timein);
    177  }
    178 
    179  if (debug_mode) {
    180    average = PR_IntervalToMicroseconds(timeout) /
    181              (INNER_LOOPS * loop_limit * thread_count);
    182    PR_fprintf(debug_out, "Average switch times %d usecs for %d threads\n",
    183               average, thread_limit);
    184  }
    185 
    186  link = shared;
    187  for (thread_count = 1; thread_count <= thread_limit; ++thread_count) {
    188    if (&home == link) {
    189      break;
    190    }
    191    status = PR_Interrupt(link->thread);
    192    if (PR_SUCCESS != status) {
    193      failed = PR_TRUE;
    194      if (debug_mode) {
    195        PL_FPrintError(debug_out, "Failed to interrupt");
    196      }
    197    }
    198    link = link->next;
    199  }
    200 
    201  for (thread_count = 1; thread_count <= thread_limit; ++thread_count) {
    202    link = shared->next;
    203    status = PR_JoinThread(shared->thread);
    204    if (PR_SUCCESS != status) {
    205      failed = PR_TRUE;
    206      if (debug_mode) {
    207        PL_FPrintError(debug_out, "Failed to join");
    208      }
    209    }
    210    PR_DestroyCondVar(shared->cv);
    211    PR_DELETE(shared);
    212    if (&home == link) {
    213      break;
    214    }
    215    shared = link;
    216  }
    217  PR_DestroyCondVar(home.cv);
    218  PR_DestroyLock(home.ml);
    219 
    220  PR_fprintf(PR_STDOUT, ((failed) ? "FAILED\n" : "PASSED\n"));
    221  return ((failed) ? 1 : 0);
    222 } /* Switch */
    223 
    224 int main(int argc, char** argv) {
    225  PRIntn result;
    226  result = PR_Initialize(Switch, argc, argv, 0);
    227  return result;
    228 } /* main */
    229 
    230 /* switch.c */