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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial