tor-browser

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

ranfile.cpp (14680B)


      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 **
      8 ** Contact:     AOF<mailto:freier@netscape.com>
      9 **
     10 ** Name: ranfile.c
     11 **
     12 ** Description: Test to hammer on various components of NSPR
     13 ** Modification History:
     14 ** 20-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
     15 **           The debug mode will print all of the printfs associated with this test.
     16 **           The regress mode will be the default mode. Since the regress tool limits
     17 **           the output to a one line status:PASS or FAIL,all of the printf statements
     18 **           have been handled with an if (debug_mode) statement.
     19 ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
     20 **          recognize the return code from tha main program.
     21 ***********************************************************************/
     22 
     23 
     24 /***********************************************************************
     25 ** Includes
     26 ***********************************************************************/
     27 /* Used to get the command line option */
     28 #include <plgetopt.h>
     29 #include <prprf.h>
     30 #include <prio.h>
     31 
     32 #include "rccv.h"
     33 #include "rcthread.h"
     34 #include "rcfileio.h"
     35 #include "rclock.h"
     36 
     37 #include <string.h>
     38 #include <stdio.h>
     39 #include <stdlib.h>
     40 
     41 static PRFileDesc *output;
     42 static PRIntn debug_mode = 0;
     43 static PRIntn failed_already = 0;
     44 
     45 class HammerData
     46 {
     47 public:
     48    typedef enum {
     49        sg_go, sg_stop, sg_done
     50    } Action;
     51    typedef enum {
     52        sg_okay, sg_open, sg_close, sg_delete, sg_write, sg_seek
     53    } Problem;
     54 
     55    virtual ~HammerData();
     56    HammerData(RCLock* lock, RCCondition *cond, PRUint32 clip);
     57    virtual PRUint32 Random();
     58 
     59    Action action;
     60    Problem problem;
     61    PRUint32 writes;
     62    RCInterval timein;
     63    friend class Hammer;
     64 private:
     65    RCLock *ml;
     66    RCCondition *cv;
     67    PRUint32 limit;
     68 
     69    PRFloat64 seed;
     70 };  /* HammerData */
     71 
     72 class Hammer: public HammerData, public RCThread
     73 {
     74 public:
     75    virtual ~Hammer();
     76    Hammer(RCThread::Scope scope, RCLock* lock, RCCondition *cond, PRUint32 clip);
     77 
     78 private:
     79    void RootFunction();
     80 
     81 };
     82 
     83 static PRInt32 pageSize = 1024;
     84 static const char* baseName = "./";
     85 static const char *programName = "Random File";
     86 
     87 /***********************************************************************
     88 ** PRIVATE FUNCTION:    Random
     89 ** DESCRIPTION:
     90 **   Generate a pseudo-random number
     91 ** INPUTS:      None
     92 ** OUTPUTS:     None
     93 ** RETURN:      A pseudo-random unsigned number, 32-bits wide
     94 ** SIDE EFFECTS:
     95 **      Updates random seed (a static)
     96 ** RESTRICTIONS:
     97 **      None
     98 ** MEMORY:      NA
     99 ** ALGORITHM:
    100 **      Uses the current interval timer value, promoted to a 64 bit
    101 **      float as a multiplier for a static residue (which begins
    102 **      as an uninitialized variable). The result is bits [16..48)
    103 **      of the product. Seed is then updated with the return value
    104 **      promoted to a float-64.
    105 ***********************************************************************/
    106 PRUint32 HammerData::Random()
    107 {
    108    PRUint32 rv;
    109    PRUint64 shift;
    110    RCInterval now = RCInterval(RCInterval::now);
    111    PRFloat64 random = seed * (PRFloat64)((PRIntervalTime)now);
    112    LL_USHR(shift, *((PRUint64*)&random), 16);
    113    LL_L2UI(rv, shift);
    114    seed = (PRFloat64)rv;
    115    return rv;
    116 }  /* HammerData::Random */
    117 
    118 Hammer::~Hammer() { }
    119 
    120 Hammer::Hammer(
    121    RCThread::Scope scope, RCLock* lock, RCCondition *cond, PRUint32 clip):
    122    HammerData(lock, cond, clip), RCThread(scope, RCThread::joinable, 0) { }
    123 
    124 HammerData::~HammerData() { }
    125 
    126 HammerData::HammerData(RCLock* lock, RCCondition *cond, PRUint32 clip)
    127 {
    128    ml = lock;
    129    cv = cond;
    130    writes = 0;
    131    limit = clip;
    132    seed = 0x58a9382;
    133    action = HammerData::sg_go;
    134    problem = HammerData::sg_okay;
    135    timein = RCInterval(RCInterval::now);
    136 }  /* HammerData::HammerData */
    137 
    138 
    139 /***********************************************************************
    140 ** PRIVATE FUNCTION:    Hammer::RootFunction
    141 ** DESCRIPTION:
    142 **   Hammer on the file I/O system
    143 ** INPUTS:      A pointer to the thread's private data
    144 ** OUTPUTS:     None
    145 ** RETURN:      None
    146 ** SIDE EFFECTS:
    147 **      Creates, accesses and deletes a file
    148 ** RESTRICTIONS:
    149 **      (Currently) must have file create permission in "/usr/tmp".
    150 ** MEMORY:      NA
    151 ** ALGORITHM:
    152 **      This function is a root of a thread
    153 **      1) Creates a (hopefully) unique file in /usr/tmp/
    154 **      2) Writes a zero to a random number of sequential pages
    155 **      3) Closes the file
    156 **      4) Reopens the file
    157 **      5) Seeks to a random page within the file
    158 **      6) Writes a one byte on that page
    159 **      7) Repeat steps [5..6] for each page in the file
    160 **      8) Close and delete the file
    161 **      9) Repeat steps [1..8] until told to stop
    162 **     10) Notify complete and return
    163 ***********************************************************************/
    164 void Hammer::RootFunction()
    165 {
    166    PRUint32 index;
    167    RCFileIO file;
    168    char filename[30];
    169    const char zero = 0;
    170    PRStatus rv = PR_SUCCESS;
    171 
    172    limit = (Random() % limit) + 1;
    173 
    174    (void)sprintf(filename, "%ssg%04p.dat", baseName, this);
    175 
    176    if (debug_mode) {
    177        PR_fprintf(output, "Starting work on %s\n", filename);
    178    }
    179 
    180    while (PR_TRUE)
    181    {
    182        PRUint64 bytes;
    183        PRUint32 minor = (Random() % limit) + 1;
    184        PRUint32 random = (Random() % limit) + 1;
    185        PRUint32 pages = (Random() % limit) + 10;
    186        while (minor-- > 0)
    187        {
    188            problem = sg_okay;
    189            if (action != sg_go) {
    190                goto finished;
    191            }
    192            problem = sg_open;
    193            rv = file.Open(filename, PR_RDWR|PR_CREATE_FILE, 0666);
    194            if (PR_FAILURE == rv) {
    195                goto finished;
    196            }
    197            for (index = 0; index < pages; index++)
    198            {
    199                problem = sg_okay;
    200                if (action != sg_go) {
    201                    goto close;
    202                }
    203                problem = sg_seek;
    204                bytes = file.Seek(pageSize * index, RCFileIO::set);
    205                if (bytes != pageSize * index) {
    206                    goto close;
    207                }
    208                problem = sg_write;
    209                bytes = file.Write(&zero, sizeof(zero));
    210                if (bytes <= 0) {
    211                    goto close;
    212                }
    213                writes += 1;
    214            }
    215            problem = sg_close;
    216            rv = file.Close();
    217            if (rv != PR_SUCCESS) {
    218                goto purge;
    219            }
    220 
    221            problem = sg_okay;
    222            if (action != sg_go) {
    223                goto purge;
    224            }
    225 
    226            problem = sg_open;
    227            rv = file.Open(filename, PR_RDWR, 0666);
    228            if (PR_FAILURE == rv) {
    229                goto finished;
    230            }
    231            for (index = 0; index < pages; index++)
    232            {
    233                problem = sg_okay;
    234                if (action != sg_go) {
    235                    goto close;
    236                }
    237                problem = sg_seek;
    238                bytes = file.Seek(pageSize * index, RCFileIO::set);
    239                if (bytes != pageSize * index) {
    240                    goto close;
    241                }
    242                problem = sg_write;
    243                bytes = file.Write(&zero, sizeof(zero));
    244                if (bytes <= 0) {
    245                    goto close;
    246                }
    247                writes += 1;
    248                random = (random + 511) % pages;
    249            }
    250            problem = sg_close;
    251            rv = file.Close();
    252            if (rv != PR_SUCCESS) {
    253                goto purge;
    254            }
    255            problem = sg_delete;
    256            rv = file.Delete(filename);
    257            if (rv != PR_SUCCESS) {
    258                goto finished;
    259            }
    260        }
    261    }
    262 
    263 close:
    264    (void)file.Close();
    265 purge:
    266    (void)file.Delete(filename);
    267 finished:
    268    RCEnter scope(ml);
    269    action = HammerData::sg_done;
    270    cv->Notify();
    271 
    272    if (debug_mode) {
    273        PR_fprintf(output, "Ending work on %s\n", filename);
    274    }
    275 
    276    return;
    277 }  /* Hammer::RootFunction */
    278 
    279 static Hammer* hammer[100];
    280 /***********************************************************************
    281 ** PRIVATE FUNCTION:    main
    282 ** DESCRIPTION:
    283 **   Hammer on the file I/O system
    284 ** INPUTS:      The usual argc and argv
    285 **              argv[0] - program name (not used)
    286 **              argv[1] - the number of virtual_procs to execute the major loop
    287 **              argv[2] - the number of threads to toss into the batch
    288 **              argv[3] - the clipping number applied to randoms
    289 **              default values: max_virtual_procs = 2, threads = 10, limit = 57
    290 ** OUTPUTS:     None
    291 ** RETURN:      None
    292 ** SIDE EFFECTS:
    293 **      Creates, accesses and deletes lots of files
    294 ** RESTRICTIONS:
    295 **      (Currently) must have file create permission in "/usr/tmp".
    296 ** MEMORY:      NA
    297 ** ALGORITHM:
    298 **      1) Fork a "Thread()"
    299 **      2) Wait for 'interleave' seconds
    300 **      3) For [0..'threads') repeat [1..2]
    301 **      4) Mark all objects to stop
    302 **      5) Collect the threads, accumulating the results
    303 **      6) For [0..'max_virtual_procs') repeat [1..5]
    304 **      7) Print accumulated results and exit
    305 **
    306 **      Characteristic output (from IRIX)
    307 **          Random File: Using max_virtual_procs = 2, threads = 10, limit = 57
    308 **          Random File: [min [avg] max] writes/sec average
    309 ***********************************************************************/
    310 PRIntn main (PRIntn argc, char *argv[])
    311 {
    312    RCLock ml;
    313    PLOptStatus os;
    314    RCCondition cv(&ml);
    315    PRUint32 writesMax = 0, durationTot = 0;
    316    RCThread::Scope thread_scope = RCThread::local;
    317    PRUint32 writes, writesMin = 0x7fffffff, writesTot = 0;
    318    PRIntn active, poll, limit = 0, max_virtual_procs = 0, threads = 0, virtual_procs;
    319    RCInterval interleave(RCInterval::FromMilliseconds(10000)), duration(0);
    320 
    321    const char *where[] = {"okay", "open", "close", "delete", "write", "seek"};
    322 
    323    PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:t:i:");
    324    while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
    325    {
    326        if (PL_OPT_BAD == os) {
    327            continue;
    328        }
    329        switch (opt->option)
    330        {
    331            case 0:
    332                baseName = opt->value;
    333                break;
    334            case 'G':  /* global threads */
    335                thread_scope = RCThread::global;
    336                break;
    337            case 'd':  /* debug mode */
    338                debug_mode = 1;
    339                break;
    340            case 'l':  /* limiting number */
    341                limit = atoi(opt->value);
    342                break;
    343            case 't':  /* number of threads */
    344                threads = atoi(opt->value);
    345                break;
    346            case 'i':  /* iteration counter */
    347                max_virtual_procs = atoi(opt->value);
    348                break;
    349            default:
    350                break;
    351        }
    352    }
    353    PL_DestroyOptState(opt);
    354    output = PR_GetSpecialFD(PR_StandardOutput);
    355 
    356    /* main test */
    357 
    358    cv.SetTimeout(interleave);
    359 
    360    if (max_virtual_procs == 0) {
    361        max_virtual_procs = 2;
    362    }
    363    if (limit == 0) {
    364        limit = 57;
    365    }
    366    if (threads == 0) {
    367        threads = 10;
    368    }
    369 
    370    if (debug_mode) PR_fprintf(output,
    371                                   "%s: Using %d virtual processors, %d threads, limit = %d and %s threads\n",
    372                                   programName, max_virtual_procs, threads, limit,
    373                                   (thread_scope == RCThread::local) ? "LOCAL" : "GLOBAL");
    374 
    375    for (virtual_procs = 0; virtual_procs < max_virtual_procs; ++virtual_procs)
    376    {
    377        if (debug_mode)
    378            PR_fprintf(output,
    379                       "%s: Setting number of virtual processors to %d\n",
    380                       programName, virtual_procs + 1);
    381        RCPrimordialThread::SetVirtualProcessors(virtual_procs + 1);
    382        for (active = 0; active < threads; active++)
    383        {
    384            hammer[active] = new Hammer(thread_scope, &ml, &cv, limit);
    385            hammer[active]->Start();  /* then make it roll */
    386            RCThread::Sleep(interleave);  /* start them slowly */
    387        }
    388 
    389        /*
    390         * The last thread started has had the opportunity to run for
    391         * 'interleave' seconds. Now gather them all back in.
    392         */
    393        {
    394            RCEnter scope(&ml);
    395            for (poll = 0; poll < threads; poll++)
    396            {
    397                if (hammer[poll]->action == HammerData::sg_go) { /* don't overwrite done */
    398                    hammer[poll]->action = HammerData::sg_stop;    /* ask him to stop */
    399                }
    400            }
    401        }
    402 
    403        while (active > 0)
    404        {
    405            for (poll = 0; poll < threads; poll++)
    406            {
    407                ml.Acquire();
    408                while (hammer[poll]->action < HammerData::sg_done) {
    409                    cv.Wait();
    410                }
    411                ml.Release();
    412 
    413                if (hammer[poll]->problem == HammerData::sg_okay)
    414                {
    415                    duration = RCInterval(RCInterval::now) - hammer[poll]->timein;
    416                    writes = hammer[poll]->writes * 1000 / duration;
    417                    if (writes < writesMin) {
    418                        writesMin = writes;
    419                    }
    420                    if (writes > writesMax) {
    421                        writesMax = writes;
    422                    }
    423                    writesTot += hammer[poll]->writes;
    424                    durationTot += duration;
    425                }
    426                else
    427                {
    428                    if (debug_mode) PR_fprintf(output,
    429                                                   "%s: test failed %s after %ld seconds\n",
    430                                                   programName, where[hammer[poll]->problem], duration);
    431                    else {
    432                        failed_already=1;
    433                    }
    434                }
    435                active -= 1;  /* this is another one down */
    436                (void)hammer[poll]->Join();
    437                hammer[poll] = NULL;
    438            }
    439        }
    440        if (debug_mode) PR_fprintf(output,
    441                                       "%s: [%ld [%ld] %ld] writes/sec average\n",
    442                                       programName, writesMin,
    443                                       writesTot * 1000 / durationTot, writesMax);
    444    }
    445 
    446    failed_already |= (PR_FAILURE == RCPrimordialThread::Cleanup());
    447    PR_fprintf(output, "%s\n", (failed_already) ? "FAIL\n" : "PASS\n");
    448    return failed_already;
    449 }  /* main */