nsprpub/pr/src/cplus/tests/ranfile.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/pr/src/cplus/tests/ranfile.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,400 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/***********************************************************************
    1.10 +**
    1.11 +** Contact:     AOF<mailto:freier@netscape.com>
    1.12 +**
    1.13 +** Name: ranfile.c
    1.14 +**
    1.15 +** Description: Test to hammer on various components of NSPR
    1.16 +** Modification History:
    1.17 +** 20-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
    1.18 +**	         The debug mode will print all of the printfs associated with this test.
    1.19 +**			 The regress mode will be the default mode. Since the regress tool limits
    1.20 +**           the output to a one line status:PASS or FAIL,all of the printf statements
    1.21 +**			 have been handled with an if (debug_mode) statement.
    1.22 +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
    1.23 +**			recognize the return code from tha main program.
    1.24 +***********************************************************************/
    1.25 +
    1.26 +
    1.27 +/***********************************************************************
    1.28 +** Includes
    1.29 +***********************************************************************/
    1.30 +/* Used to get the command line option */
    1.31 +#include <plgetopt.h>
    1.32 +#include <prprf.h>
    1.33 +#include <prio.h>
    1.34 +
    1.35 +#include "rccv.h"
    1.36 +#include "rcthread.h"
    1.37 +#include "rcfileio.h"
    1.38 +#include "rclock.h"
    1.39 +
    1.40 +#include <string.h>
    1.41 +#include <stdio.h>
    1.42 +#include <stdlib.h>
    1.43 +
    1.44 +static PRFileDesc *output;
    1.45 +static PRIntn debug_mode = 0;
    1.46 +static PRIntn failed_already = 0;
    1.47 +
    1.48 +class HammerData
    1.49 +{
    1.50 +public:
    1.51 +    typedef enum {
    1.52 +        sg_go, sg_stop, sg_done} Action;
    1.53 +    typedef enum {
    1.54 +        sg_okay, sg_open, sg_close, sg_delete, sg_write, sg_seek} Problem;
    1.55 +
    1.56 +	virtual ~HammerData();
    1.57 +	HammerData(RCLock* lock, RCCondition *cond, PRUint32 clip);
    1.58 +    virtual PRUint32 Random();
    1.59 +
    1.60 +    Action action;
    1.61 +    Problem problem;
    1.62 +    PRUint32 writes;
    1.63 +    RCInterval timein;
    1.64 +friend class Hammer;
    1.65 +private:
    1.66 +    RCLock *ml;
    1.67 +    RCCondition *cv;
    1.68 +    PRUint32 limit;
    1.69 +
    1.70 +    PRFloat64 seed;
    1.71 +};  /* HammerData */
    1.72 +
    1.73 +class Hammer: public HammerData, public RCThread
    1.74 +{
    1.75 +public:
    1.76 +    virtual ~Hammer();
    1.77 +    Hammer(RCThread::Scope scope, RCLock* lock, RCCondition *cond, PRUint32 clip);
    1.78 +
    1.79 +private:
    1.80 +    void RootFunction();
    1.81 +
    1.82 +};
    1.83 +
    1.84 +static PRInt32 pageSize = 1024;
    1.85 +static const char* baseName = "./";
    1.86 +static const char *programName = "Random File";
    1.87 +
    1.88 +/***********************************************************************
    1.89 +** PRIVATE FUNCTION:    Random
    1.90 +** DESCRIPTION:
    1.91 +**   Generate a pseudo-random number
    1.92 +** INPUTS:      None
    1.93 +** OUTPUTS:     None
    1.94 +** RETURN:      A pseudo-random unsigned number, 32-bits wide
    1.95 +** SIDE EFFECTS:
    1.96 +**      Updates random seed (a static)
    1.97 +** RESTRICTIONS:
    1.98 +**      None
    1.99 +** MEMORY:      NA
   1.100 +** ALGORITHM:
   1.101 +**      Uses the current interval timer value, promoted to a 64 bit
   1.102 +**      float as a multiplier for a static residue (which begins
   1.103 +**      as an uninitialized variable). The result is bits [16..48)
   1.104 +**      of the product. Seed is then updated with the return value
   1.105 +**      promoted to a float-64.
   1.106 +***********************************************************************/
   1.107 +PRUint32 HammerData::Random()
   1.108 +{
   1.109 +    PRUint32 rv;
   1.110 +    PRUint64 shift;
   1.111 +    RCInterval now = RCInterval(RCInterval::now);
   1.112 +    PRFloat64 random = seed * (PRFloat64)((PRIntervalTime)now);
   1.113 +    LL_USHR(shift, *((PRUint64*)&random), 16);
   1.114 +    LL_L2UI(rv, shift);
   1.115 +    seed = (PRFloat64)rv;
   1.116 +    return rv;
   1.117 +}  /* HammerData::Random */
   1.118 +
   1.119 +Hammer::~Hammer() { }
   1.120 +
   1.121 +Hammer::Hammer(
   1.122 +    RCThread::Scope scope, RCLock* lock, RCCondition *cond, PRUint32 clip):
   1.123 +	HammerData(lock, cond, clip), RCThread(scope, RCThread::joinable, 0) { }
   1.124 +
   1.125 +HammerData::~HammerData() { }
   1.126 +
   1.127 +HammerData::HammerData(RCLock* lock, RCCondition *cond, PRUint32 clip)
   1.128 +{
   1.129 +    ml = lock;
   1.130 +    cv = cond;
   1.131 +    writes = 0;
   1.132 +    limit = clip;
   1.133 +    seed = 0x58a9382;
   1.134 +    action = HammerData::sg_go;
   1.135 +    problem = HammerData::sg_okay;
   1.136 +    timein = RCInterval(RCInterval::now);
   1.137 +}  /* HammerData::HammerData */
   1.138 +
   1.139 +
   1.140 +/***********************************************************************
   1.141 +** PRIVATE FUNCTION:    Hammer::RootFunction
   1.142 +** DESCRIPTION:
   1.143 +**   Hammer on the file I/O system
   1.144 +** INPUTS:      A pointer to the thread's private data
   1.145 +** OUTPUTS:     None
   1.146 +** RETURN:      None
   1.147 +** SIDE EFFECTS:
   1.148 +**      Creates, accesses and deletes a file
   1.149 +** RESTRICTIONS:
   1.150 +**      (Currently) must have file create permission in "/usr/tmp".
   1.151 +** MEMORY:      NA
   1.152 +** ALGORITHM:
   1.153 +**      This function is a root of a thread
   1.154 +**      1) Creates a (hopefully) unique file in /usr/tmp/
   1.155 +**      2) Writes a zero to a random number of sequential pages
   1.156 +**      3) Closes the file
   1.157 +**      4) Reopens the file
   1.158 +**      5) Seeks to a random page within the file
   1.159 +**      6) Writes a one byte on that page
   1.160 +**      7) Repeat steps [5..6] for each page in the file
   1.161 +**      8) Close and delete the file
   1.162 +**      9) Repeat steps [1..8] until told to stop
   1.163 +**     10) Notify complete and return
   1.164 +***********************************************************************/
   1.165 +void Hammer::RootFunction()
   1.166 +{
   1.167 +    PRUint32 index;
   1.168 +    RCFileIO file;
   1.169 +    char filename[30];
   1.170 +    const char zero = 0;
   1.171 +    PRStatus rv = PR_SUCCESS;
   1.172 +
   1.173 +    limit = (Random() % limit) + 1;
   1.174 +
   1.175 +    (void)sprintf(filename, "%ssg%04p.dat", baseName, this);
   1.176 +
   1.177 +    if (debug_mode) PR_fprintf(output, "Starting work on %s\n", filename);
   1.178 +
   1.179 +    while (PR_TRUE)
   1.180 +    {
   1.181 +        PRUint64 bytes;
   1.182 +        PRUint32 minor = (Random() % limit) + 1;
   1.183 +        PRUint32 random = (Random() % limit) + 1;
   1.184 +        PRUint32 pages = (Random() % limit) + 10;
   1.185 +        while (minor-- > 0)
   1.186 +        {
   1.187 +            problem = sg_okay;
   1.188 +            if (action != sg_go) goto finished;
   1.189 +            problem = sg_open;
   1.190 +            rv = file.Open(filename, PR_RDWR|PR_CREATE_FILE, 0666);
   1.191 +            if (PR_FAILURE == rv) goto finished;
   1.192 +            for (index = 0; index < pages; index++)
   1.193 +            {
   1.194 +                problem = sg_okay;
   1.195 +                if (action != sg_go) goto close;
   1.196 +                problem = sg_seek;
   1.197 +                bytes = file.Seek(pageSize * index, RCFileIO::set);
   1.198 +                if (bytes != pageSize * index) goto close;
   1.199 +                problem = sg_write;
   1.200 +                bytes = file.Write(&zero, sizeof(zero));
   1.201 +                if (bytes <= 0) goto close;
   1.202 +                writes += 1;
   1.203 +            }
   1.204 +            problem = sg_close;
   1.205 +            rv = file.Close();
   1.206 +            if (rv != PR_SUCCESS) goto purge;
   1.207 +
   1.208 +            problem = sg_okay;
   1.209 +            if (action != sg_go) goto purge;
   1.210 +
   1.211 +            problem = sg_open;
   1.212 +            rv = file.Open(filename, PR_RDWR, 0666);
   1.213 +            if (PR_FAILURE == rv) goto finished;
   1.214 +            for (index = 0; index < pages; index++)
   1.215 +            {
   1.216 +                problem = sg_okay;
   1.217 +                if (action != sg_go) goto close;
   1.218 +                problem = sg_seek;
   1.219 +                bytes = file.Seek(pageSize * index, RCFileIO::set);
   1.220 +                if (bytes != pageSize * index) goto close;
   1.221 +                problem = sg_write;
   1.222 +                bytes = file.Write(&zero, sizeof(zero));
   1.223 +                if (bytes <= 0) goto close;
   1.224 +                writes += 1;
   1.225 +                random = (random + 511) % pages;
   1.226 +            }
   1.227 +            problem = sg_close;
   1.228 +            rv = file.Close();
   1.229 +            if (rv != PR_SUCCESS) goto purge;
   1.230 +            problem = sg_delete;
   1.231 +            rv = file.Delete(filename);
   1.232 +            if (rv != PR_SUCCESS) goto finished;
   1.233 +       }
   1.234 +    }
   1.235 +
   1.236 +close:
   1.237 +    (void)file.Close();
   1.238 +purge:
   1.239 +    (void)file.Delete(filename);
   1.240 +finished:
   1.241 +    RCEnter scope(ml);
   1.242 +    action = HammerData::sg_done;
   1.243 +    cv->Notify();
   1.244 +
   1.245 +    if (debug_mode) PR_fprintf(output, "Ending work on %s\n", filename);
   1.246 +
   1.247 +    return;
   1.248 +}  /* Hammer::RootFunction */
   1.249 +
   1.250 +static Hammer* hammer[100];
   1.251 +/***********************************************************************
   1.252 +** PRIVATE FUNCTION:    main
   1.253 +** DESCRIPTION:
   1.254 +**   Hammer on the file I/O system
   1.255 +** INPUTS:      The usual argc and argv
   1.256 +**              argv[0] - program name (not used)
   1.257 +**              argv[1] - the number of virtual_procs to execute the major loop
   1.258 +**              argv[2] - the number of threads to toss into the batch
   1.259 +**              argv[3] - the clipping number applied to randoms
   1.260 +**              default values: max_virtual_procs = 2, threads = 10, limit = 57
   1.261 +** OUTPUTS:     None
   1.262 +** RETURN:      None
   1.263 +** SIDE EFFECTS:
   1.264 +**      Creates, accesses and deletes lots of files
   1.265 +** RESTRICTIONS:
   1.266 +**      (Currently) must have file create permission in "/usr/tmp".
   1.267 +** MEMORY:      NA
   1.268 +** ALGORITHM:
   1.269 +**      1) Fork a "Thread()"
   1.270 +**      2) Wait for 'interleave' seconds
   1.271 +**      3) For [0..'threads') repeat [1..2]
   1.272 +**      4) Mark all objects to stop
   1.273 +**      5) Collect the threads, accumulating the results
   1.274 +**      6) For [0..'max_virtual_procs') repeat [1..5]
   1.275 +**      7) Print accumulated results and exit
   1.276 +**
   1.277 +**      Characteristic output (from IRIX)
   1.278 +**          Random File: Using max_virtual_procs = 2, threads = 10, limit = 57
   1.279 +**          Random File: [min [avg] max] writes/sec average
   1.280 +***********************************************************************/
   1.281 +PRIntn main (PRIntn argc, char *argv[])
   1.282 +{
   1.283 +    RCLock ml;
   1.284 +	PLOptStatus os;
   1.285 +    RCCondition cv(&ml);
   1.286 +    PRUint32 writesMax = 0, durationTot = 0;
   1.287 +    RCThread::Scope thread_scope = RCThread::local;
   1.288 +    PRUint32 writes, writesMin = 0x7fffffff, writesTot = 0;
   1.289 +    PRIntn active, poll, limit = 0, max_virtual_procs = 0, threads = 0, virtual_procs;
   1.290 +    RCInterval interleave(RCInterval::FromMilliseconds(10000)), duration(0);
   1.291 +
   1.292 +    const char *where[] = {"okay", "open", "close", "delete", "write", "seek"};
   1.293 +
   1.294 +	PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:t:i:");
   1.295 +	while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
   1.296 +    {
   1.297 +		if (PL_OPT_BAD == os) continue;
   1.298 +        switch (opt->option)
   1.299 +        {
   1.300 +	case 0:
   1.301 +		baseName = opt->value;
   1.302 +		break;
   1.303 +        case 'G':  /* global threads */
   1.304 +		thread_scope = RCThread::global;
   1.305 +            break;
   1.306 +        case 'd':  /* debug mode */
   1.307 +			debug_mode = 1;
   1.308 +            break;
   1.309 +        case 'l':  /* limiting number */
   1.310 +			limit = atoi(opt->value);
   1.311 +            break;
   1.312 +        case 't':  /* number of threads */
   1.313 +			threads = atoi(opt->value);
   1.314 +            break;
   1.315 +        case 'i':  /* iteration counter */
   1.316 +			max_virtual_procs = atoi(opt->value);
   1.317 +            break;
   1.318 +         default:
   1.319 +            break;
   1.320 +        }
   1.321 +    }
   1.322 +	PL_DestroyOptState(opt);
   1.323 +    output = PR_GetSpecialFD(PR_StandardOutput);
   1.324 +
   1.325 + /* main test */
   1.326 + 
   1.327 +    cv.SetTimeout(interleave);
   1.328 +	
   1.329 +    if (max_virtual_procs == 0) max_virtual_procs = 2;
   1.330 +    if (limit == 0) limit = 57;
   1.331 +    if (threads == 0) threads = 10;
   1.332 +
   1.333 +    if (debug_mode) PR_fprintf(output,
   1.334 +        "%s: Using %d virtual processors, %d threads, limit = %d and %s threads\n",
   1.335 +        programName, max_virtual_procs, threads, limit,
   1.336 +        (thread_scope == RCThread::local) ? "LOCAL" : "GLOBAL");
   1.337 +
   1.338 +    for (virtual_procs = 0; virtual_procs < max_virtual_procs; ++virtual_procs)
   1.339 +    {
   1.340 +        if (debug_mode)
   1.341 +			PR_fprintf(output,
   1.342 +				"%s: Setting number of virtual processors to %d\n",
   1.343 +				programName, virtual_procs + 1);
   1.344 +		RCPrimordialThread::SetVirtualProcessors(virtual_procs + 1);
   1.345 +        for (active = 0; active < threads; active++)
   1.346 +        {
   1.347 +            hammer[active] = new Hammer(thread_scope, &ml, &cv, limit);
   1.348 +            hammer[active]->Start();  /* then make it roll */
   1.349 +            RCThread::Sleep(interleave);  /* start them slowly */
   1.350 +        }
   1.351 +
   1.352 +        /*
   1.353 +         * The last thread started has had the opportunity to run for
   1.354 +         * 'interleave' seconds. Now gather them all back in.
   1.355 +         */
   1.356 +        {
   1.357 +            RCEnter scope(&ml);
   1.358 +            for (poll = 0; poll < threads; poll++)
   1.359 +            {
   1.360 +                if (hammer[poll]->action == HammerData::sg_go)  /* don't overwrite done */
   1.361 +                    hammer[poll]->action = HammerData::sg_stop;  /* ask him to stop */
   1.362 +            }
   1.363 +        }
   1.364 +
   1.365 +        while (active > 0)
   1.366 +        {
   1.367 +            for (poll = 0; poll < threads; poll++)
   1.368 +            {
   1.369 +                ml.Acquire();
   1.370 +                while (hammer[poll]->action < HammerData::sg_done) cv.Wait();
   1.371 +                ml.Release();
   1.372 +
   1.373 +                if (hammer[poll]->problem == HammerData::sg_okay)
   1.374 +                {
   1.375 +                    duration = RCInterval(RCInterval::now) - hammer[poll]->timein;
   1.376 +                    writes = hammer[poll]->writes * 1000 / duration;
   1.377 +                    if (writes < writesMin)  writesMin = writes;
   1.378 +                    if (writes > writesMax) writesMax = writes;
   1.379 +                    writesTot += hammer[poll]->writes;
   1.380 +                    durationTot += duration;
   1.381 +                }
   1.382 +                else
   1.383 +                {
   1.384 +                    if (debug_mode) PR_fprintf(output,
   1.385 +                        "%s: test failed %s after %ld seconds\n",
   1.386 +                        programName, where[hammer[poll]->problem], duration);
   1.387 +					else failed_already=1;
   1.388 +                }
   1.389 +                active -= 1;  /* this is another one down */
   1.390 +                (void)hammer[poll]->Join();
   1.391 +                hammer[poll] = NULL;
   1.392 +            }
   1.393 +        }
   1.394 +        if (debug_mode) PR_fprintf(output,
   1.395 +            "%s: [%ld [%ld] %ld] writes/sec average\n",
   1.396 +            programName, writesMin,
   1.397 +            writesTot * 1000 / durationTot, writesMax);
   1.398 +    }
   1.399 +
   1.400 +        failed_already |= (PR_FAILURE == RCPrimordialThread::Cleanup());
   1.401 +	    PR_fprintf(output, "%s\n", (failed_already) ? "FAIL\n" : "PASS\n");
   1.402 +		return failed_already;
   1.403 +}  /* main */

mercurial