tor-browser

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

switch.cpp (6834B)


      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.cpp
      8 ** Description:     trying to time context switches
      9 */
     10 
     11 #include "rccv.h"
     12 #include "rcinrval.h"
     13 #include "rclock.h"
     14 #include "rcthread.h"
     15 
     16 #include <prio.h>
     17 #include <prlog.h>
     18 #include <prprf.h>
     19 #include <plerror.h>
     20 #include <plgetopt.h>
     21 
     22 #include <stdlib.h>
     23 
     24 #define INNER_LOOPS 100
     25 #define DEFAULT_LOOPS 100
     26 #define DEFAULT_THREADS 10
     27 
     28 static PRFileDesc *debug_out = NULL;
     29 static PRBool debug_mode = PR_FALSE, verbosity = PR_FALSE, failed = PR_FALSE;
     30 
     31 class Home: public RCCondition
     32 {
     33 public:
     34    virtual ~Home();
     35    Home(Home *link, RCLock* ml);
     36 
     37 public:
     38    Home *next;
     39    RCLock* ml;
     40    PRBool twiddle;
     41 };  /* Home */
     42 
     43 Home::~Home() { }
     44 
     45 Home::Home(Home *link, RCLock* lock): RCCondition(lock)
     46 {
     47    ml = lock;
     48    next = link;
     49    twiddle = PR_FALSE;
     50 }  /* Home::Home */
     51 
     52 class Shared: public Home, public RCThread
     53 {
     54 public:
     55    Shared(RCThread::Scope scope, Home* link, RCLock* ml);
     56 
     57 private:
     58    ~Shared();
     59    void RootFunction();
     60 };  /* Shared */
     61 
     62 Shared::Shared(RCThread::Scope scope, Home* link, RCLock* lock):
     63    Home(link, lock), RCThread(scope, RCThread::joinable) { }
     64 
     65 Shared::~Shared() { }
     66 
     67 void Shared::RootFunction()
     68 {
     69    PRStatus status = PR_SUCCESS;
     70    while (PR_SUCCESS == status)
     71    {
     72        RCEnter entry(ml);
     73        while (twiddle && (PR_SUCCESS == status)) {
     74            status = Wait();
     75        }
     76        if (verbosity) {
     77            PR_fprintf(debug_out, "+");
     78        }
     79        twiddle = PR_TRUE;
     80        next->twiddle = PR_FALSE;
     81        next->Notify();
     82    }
     83 }  /* Shared::RootFunction */
     84 
     85 static void Help(void)
     86 {
     87    debug_out = PR_STDOUT;
     88 
     89    PR_fprintf(
     90        debug_out, "Usage: >./switch [-d] [-c n] [-t n] [-T n] [-G]\n");
     91    PR_fprintf(
     92        debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS);
     93    PR_fprintf(
     94        debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS);
     95    PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n");
     96    PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n");
     97    PR_fprintf(debug_out, "-G n\tglobal threads only (default: FALSE)\n");
     98    PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n");
     99 }  /* Help */
    100 
    101 PRIntn main(PRIntn argc, char **argv)
    102 {
    103    PLOptStatus os;
    104    PRStatus status;
    105    PRBool help = PR_FALSE;
    106    PRUintn concurrency = 1;
    107    RCThread::Scope thread_scope = RCThread::local;
    108    PRUintn thread_count, inner_count, loop_count, average;
    109    PRUintn thread_limit = DEFAULT_THREADS, loop_limit = DEFAULT_LOOPS;
    110    PLOptState *opt = PL_CreateOptState(argc, argv, "hdvc:t:C:G");
    111    while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
    112    {
    113        if (PL_OPT_BAD == os) {
    114            continue;
    115        }
    116        switch (opt->option)
    117        {
    118            case 'v':  /* verbose mode */
    119                verbosity = PR_TRUE;
    120            case 'd':  /* debug mode */
    121                debug_mode = PR_TRUE;
    122                break;
    123            case 'c':  /* loop counter */
    124                loop_limit = atoi(opt->value);
    125                break;
    126            case 't':  /* thread limit */
    127                thread_limit = atoi(opt->value);
    128                break;
    129            case 'C':  /* Concurrency limit */
    130                concurrency = atoi(opt->value);
    131                break;
    132            case 'G':  /* global threads only */
    133                thread_scope = RCThread::global;
    134                break;
    135            case 'h':  /* help message */
    136                Help();
    137                help = PR_TRUE;
    138                break;
    139            default:
    140                break;
    141        }
    142    }
    143    PL_DestroyOptState(opt);
    144 
    145    if (help) {
    146        return -1;
    147    }
    148 
    149    if (PR_TRUE == debug_mode)
    150    {
    151        debug_out = PR_STDOUT;
    152        PR_fprintf(debug_out, "Test parameters\n");
    153        PR_fprintf(debug_out, "\tThreads involved: %d\n", thread_limit);
    154        PR_fprintf(debug_out, "\tIteration limit: %d\n", loop_limit);
    155        PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency);
    156        PR_fprintf(
    157            debug_out, "\tThread type: %s\n",
    158            (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL");
    159    }
    160 
    161    /*
    162    ** The interesting part starts here
    163    */
    164    RCLock lock;
    165    Shared* shared;
    166    Home home(NULL, &lock);
    167    Home* link = &home;
    168    RCInterval timein, timeout = 0;
    169 
    170    /* Build up the string of objects */
    171    for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
    172    {
    173        shared = new Shared(thread_scope, link, &lock);
    174        shared->Start();  /* make it run */
    175        link = (Home*)shared;
    176    }
    177 
    178    /* Pass the message around the horn a few times */
    179    for (loop_count = 1; loop_count <= loop_limit; ++loop_count)
    180    {
    181        timein.SetToNow();
    182        for (inner_count = 0; inner_count < INNER_LOOPS; ++inner_count)
    183        {
    184            RCEnter entry(&lock);
    185            home.twiddle = PR_TRUE;
    186            shared->twiddle = PR_FALSE;
    187            shared->Notify();
    188            while (home.twiddle)
    189            {
    190                failed = (PR_FAILURE == home.Wait()) ? PR_TRUE : PR_FALSE;
    191            }
    192        }
    193        timeout += (RCInterval(RCInterval::now) - timein);
    194    }
    195 
    196    /* Figure out how well we did */
    197    if (debug_mode)
    198    {
    199        average = timeout.ToMicroseconds()
    200                  / (INNER_LOOPS * loop_limit * thread_count);
    201        PR_fprintf(
    202            debug_out, "Average switch times %d usecs for %d threads\n",
    203            average, thread_limit);
    204    }
    205 
    206    /* Start reclamation process */
    207    link = shared;
    208    for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
    209    {
    210        if (&home == link) {
    211            break;
    212        }
    213        status = ((Shared*)link)->Interrupt();
    214        if (PR_SUCCESS != status)
    215        {
    216            failed = PR_TRUE;
    217            if (debug_mode) {
    218                PL_FPrintError(debug_out, "Failed to interrupt");
    219            }
    220        }
    221        link = link->next;
    222    }
    223 
    224    for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
    225    {
    226        link = shared->next;
    227        status = shared->Join();
    228        if (PR_SUCCESS != status)
    229        {
    230            failed = PR_TRUE;
    231            if (debug_mode) {
    232                PL_FPrintError(debug_out, "Failed to join");
    233            }
    234        }
    235        if (&home == link) {
    236            break;
    237        }
    238        shared = (Shared*)link;
    239    }
    240 
    241    PR_fprintf(PR_STDOUT, ((failed) ? "FAILED\n" : "PASSED\n"));
    242 
    243    failed |= (PR_SUCCESS == RCPrimordialThread::Cleanup());
    244 
    245    return ((failed) ? 1 : 0);
    246 }  /* main */
    247 
    248 /* switch.c */