nsprpub/pr/tests/ranfile.c

Wed, 31 Dec 2014 07:53:36 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:53:36 +0100
branch
TOR_BUG_3246
changeset 5
4ab42b5ab56c
permissions
-rw-r--r--

Correct small whitespace inconsistency, lost while renaming variables.

     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<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"
    30 #include "prinit.h"
    31 #include "prthread.h"
    32 #include "prlock.h"
    33 #include "prcvar.h"
    34 #include "prmem.h"
    35 #include "prinrval.h"
    36 #include "prio.h"
    38 #include <string.h>
    39 #include <stdio.h>
    41 static PRIntn debug_mode = 0;
    42 static PRIntn failed_already=0;
    43 static PRThreadScope thread_scope = PR_LOCAL_THREAD;
    45 typedef enum {sg_go, sg_stop, sg_done} Action;
    46 typedef enum {sg_okay, sg_open, sg_close, sg_delete, sg_write, sg_seek} Problem;
    48 typedef struct Hammer_s {
    49     PRLock *ml;
    50     PRCondVar *cv;
    51     PRUint32 id;
    52     PRUint32 limit;
    53     PRUint32 writes;
    54     PRThread *thread;
    55     PRIntervalTime timein;
    56     Action action;
    57     Problem problem;
    58 } Hammer_t;
    60 #define DEFAULT_LIMIT		10
    61 #define DEFAULT_THREADS		2
    62 #define DEFAULT_LOOPS		1
    64 static PRInt32 pageSize = 1024;
    65 static const char* baseName = "./";
    66 static const char *programName = "Random File";
    68 /***********************************************************************
    69 ** PRIVATE FUNCTION:    RandomNum
    70 ** DESCRIPTION:
    71 **   Generate a pseudo-random number
    72 ** INPUTS:      None
    73 ** OUTPUTS:     None
    74 ** RETURN:      A pseudo-random unsigned number, 32-bits wide
    75 ** SIDE EFFECTS:
    76 **      Updates random seed (a static)
    77 ** RESTRICTIONS:
    78 **      None
    79 ** MEMORY:      NA
    80 ** ALGORITHM:
    81 **      Uses the current interval timer value, promoted to a 64 bit
    82 **      float as a multiplier for a static residue (which begins
    83 **      as an uninitialized variable). The result is bits [16..48)
    84 **      of the product. Seed is then updated with the return value
    85 **      promoted to a float-64.
    86 ***********************************************************************/
    87 static PRUint32 RandomNum(void)
    88 {
    89     PRUint32 rv;
    90     PRUint64 shift;
    91     static PRFloat64 seed = 0x58a9382;  /* Just make sure it isn't 0! */
    92     PRFloat64 random = seed * (PRFloat64)PR_IntervalNow();
    93     LL_USHR(shift, *((PRUint64*)&random), 16);
    94     LL_L2UI(rv, shift);
    95     seed = (PRFloat64)rv;
    96     return rv;
    97 }  /* RandomNum */
    99 /***********************************************************************
   100 ** PRIVATE FUNCTION:    Thread
   101 ** DESCRIPTION:
   102 **   Hammer on the file I/O system
   103 ** INPUTS:      A pointer to the thread's private data
   104 ** OUTPUTS:     None
   105 ** RETURN:      None
   106 ** SIDE EFFECTS:
   107 **      Creates, accesses and deletes a file
   108 ** RESTRICTIONS:
   109 **      (Currently) must have file create permission in "/usr/tmp".
   110 ** MEMORY:      NA
   111 ** ALGORITHM:
   112 **      This function is a root of a thread
   113 **      1) Creates a (hopefully) unique file in /usr/tmp/
   114 **      2) Writes a zero to a random number of sequential pages
   115 **      3) Closes the file
   116 **      4) Reopens the file
   117 **      5) Seeks to a random page within the file
   118 **      6) Writes a one byte on that page
   119 **      7) Repeat steps [5..6] for each page in the file
   120 **      8) Close and delete the file
   121 **      9) Repeat steps [1..8] until told to stop
   122 **     10) Notify complete and return
   123 ***********************************************************************/
   124 static void PR_CALLBACK Thread(void *arg)
   125 {
   126     PRUint32 index;
   127     char filename[30];
   128     const char zero = 0;
   129     PRFileDesc *file = NULL;
   130     PRStatus rv = PR_SUCCESS;
   131     Hammer_t *cd = (Hammer_t*)arg;
   133     (void)sprintf(filename, "%ssg%04ld.dat", baseName, cd->id);
   135     if (debug_mode) printf("Starting work on %s\n", filename);
   137     while (PR_TRUE)
   138     {
   139         PRUint32 bytes;
   140         PRUint32 minor = (RandomNum() % cd->limit) + 1;
   141         PRUint32 random = (RandomNum() % cd->limit) + 1;
   142         PRUint32 pages = (RandomNum() % cd->limit) + 10;
   143         while (minor-- > 0)
   144         {
   145             cd->problem = sg_okay;
   146             if (cd->action != sg_go) goto finished;
   147             cd->problem = sg_open;
   148             file = PR_Open(filename, PR_RDWR|PR_CREATE_FILE, 0666);
   149             if (file == NULL) goto finished;
   150             for (index = 0; index < pages; index++)
   151             {
   152                 cd->problem = sg_okay;
   153                 if (cd->action != sg_go) goto close;
   154                 cd->problem = sg_seek;
   155                 bytes = PR_Seek(file, pageSize * index, PR_SEEK_SET);
   156                 if (bytes != pageSize * index) goto close;
   157                 cd->problem = sg_write;
   158                 bytes = PR_Write(file, &zero, sizeof(zero));
   159                 if (bytes <= 0) goto close;
   160                 cd->writes += 1;
   161             }
   162             cd->problem = sg_close;
   163             rv = PR_Close(file);
   164             if (rv != PR_SUCCESS) goto purge;
   166             cd->problem = sg_okay;
   167             if (cd->action != sg_go) goto purge;
   169             cd->problem = sg_open;
   170             file = PR_Open(filename, PR_RDWR, 0666);
   171             for (index = 0; index < pages; index++)
   172             {
   173                 cd->problem = sg_okay;
   174                 if (cd->action != sg_go) goto close;
   175                 cd->problem = sg_seek;
   176                 bytes = PR_Seek(file, pageSize * index, PR_SEEK_SET);
   177                 if (bytes != pageSize * index) goto close;
   178                 cd->problem = sg_write;
   179                 bytes = PR_Write(file, &zero, sizeof(zero));
   180                 if (bytes <= 0) goto close;
   181                 cd->writes += 1;
   182                 random = (random + 511) % pages;
   183             }
   184             cd->problem = sg_close;
   185             rv = PR_Close(file);
   186             if (rv != PR_SUCCESS) goto purge;
   187             cd->problem = sg_delete;
   188             rv = PR_Delete(filename);
   189             if (rv != PR_SUCCESS) goto finished;
   190        }
   191     }
   193 close:
   194     (void)PR_Close(file);
   195 purge:
   196     (void)PR_Delete(filename);
   197 finished:
   198     PR_Lock(cd->ml);
   199     cd->action = sg_done;
   200     PR_NotifyCondVar(cd->cv);
   201     PR_Unlock(cd->ml);
   203     if (debug_mode) printf("Ending work on %s\n", filename);
   205     return;
   206 }  /* Thread */
   208 static Hammer_t hammer[100];
   209 static PRCondVar *cv;
   210 /***********************************************************************
   211 ** PRIVATE FUNCTION:    main
   212 ** DESCRIPTION:
   213 **   Hammer on the file I/O system
   214 ** INPUTS:      The usual argc and argv
   215 **              argv[0] - program name (not used)
   216 **              argv[1] - the number of times to execute the major loop
   217 **              argv[2] - the number of threads to toss into the batch
   218 **              argv[3] - the clipping number applied to randoms
   219 **              default values: loops = 2, threads = 10, limit = 57
   220 ** OUTPUTS:     None
   221 ** RETURN:      None
   222 ** SIDE EFFECTS:
   223 **      Creates, accesses and deletes lots of files
   224 ** RESTRICTIONS:
   225 **      (Currently) must have file create permission in "/usr/tmp".
   226 ** MEMORY:      NA
   227 ** ALGORITHM:
   228 **      1) Fork a "Thread()"
   229 **      2) Wait for 'interleave' seconds
   230 **      3) For [0..'threads') repeat [1..2]
   231 **      4) Mark all objects to stop
   232 **      5) Collect the threads, accumulating the results
   233 **      6) For [0..'loops') repeat [1..5]
   234 **      7) Print accumulated results and exit
   235 **
   236 **      Characteristic output (from IRIX)
   237 **          Random File: Using loops = 2, threads = 10, limit = 57
   238 **          Random File: [min [avg] max] writes/sec average
   239 ***********************************************************************/
   240 int main(int argc, char **argv)
   241 {
   242     PRLock *ml;
   243     PRUint32 id = 0;
   244     int active, poll;
   245     PRIntervalTime interleave;
   246     PRIntervalTime duration = 0;
   247     int limit = 0, loops = 0, threads = 0, times;
   248     PRUint32 writes, writesMin = 0x7fffffff, writesTot = 0, durationTot = 0, writesMax = 0;
   250     const char *where[] = {"okay", "open", "close", "delete", "write", "seek"};
   252 	/* The command line argument: -d is used to determine if the test is being run
   253 	in debug mode. The regress tool requires only one line output:PASS or FAIL.
   254 	All of the printfs associated with this test has been handled with a if (debug_mode)
   255 	test.
   256 	Usage: test_name -d
   257 	*/
   258 	PLOptStatus os;
   259 	PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:t:i:");
   260 	while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
   261     {
   262 		if (PL_OPT_BAD == os) continue;
   263         switch (opt->option)
   264         {
   265         case 'G':  /* global threads */
   266 			thread_scope = PR_GLOBAL_THREAD;
   267             break;
   268         case 'd':  /* debug mode */
   269 			debug_mode = 1;
   270             break;
   271         case 'l':  /* limiting number */
   272 			limit = atoi(opt->value);
   273             break;
   274         case 't':  /* number of threads */
   275 			threads = atoi(opt->value);
   276             break;
   277         case 'i':  /* iteration counter */
   278 			loops = atoi(opt->value);
   279             break;
   280          default:
   281             break;
   282         }
   283     }
   284 	PL_DestroyOptState(opt);
   286  /* main test */
   288     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
   289     PR_STDIO_INIT();
   291     interleave = PR_SecondsToInterval(10);
   293     ml = PR_NewLock();
   294     cv = PR_NewCondVar(ml);
   296     if (loops == 0) loops = DEFAULT_LOOPS;
   297     if (limit == 0) limit = DEFAULT_LIMIT;
   298     if (threads == 0) threads = DEFAULT_THREADS;
   300     if (debug_mode) printf(
   301         "%s: Using loops = %d, threads = %d, limit = %d and %s threads\n",
   302         programName, loops, threads, limit,
   303         (thread_scope == PR_LOCAL_THREAD) ? "LOCAL" : "GLOBAL");
   305     for (times = 0; times < loops; ++times)
   306     {
   307         if (debug_mode) printf("%s: Setting concurrency level to %d\n", programName, times + 1);
   308         PR_SetConcurrency(times + 1);
   309         for (active = 0; active < threads; active++)
   310         {
   311             hammer[active].ml = ml;
   312             hammer[active].cv = cv;
   313             hammer[active].id = id++;
   314             hammer[active].writes = 0;
   315             hammer[active].action = sg_go;
   316             hammer[active].problem = sg_okay;
   317             hammer[active].limit = (RandomNum() % limit) + 1;
   318             hammer[active].timein = PR_IntervalNow();
   319             hammer[active].thread = PR_CreateThread(
   320                 PR_USER_THREAD, Thread, &hammer[active],
   321                 PR_GetThreadPriority(PR_GetCurrentThread()),
   322                 thread_scope, PR_JOINABLE_THREAD, 0);
   324             PR_Lock(ml);
   325             PR_WaitCondVar(cv, interleave);  /* start new ones slowly */
   326             PR_Unlock(ml);
   327         }
   329         /*
   330          * The last thread started has had the opportunity to run for
   331          * 'interleave' seconds. Now gather them all back in.
   332          */
   333         PR_Lock(ml);
   334         for (poll = 0; poll < threads; poll++)
   335         {
   336             if (hammer[poll].action == sg_go)  /* don't overwrite done */
   337                 hammer[poll].action = sg_stop;  /* ask him to stop */
   338         }
   339         PR_Unlock(ml);
   341         while (active > 0)
   342         {
   343             for (poll = 0; poll < threads; poll++)
   344             {
   345                 PR_Lock(ml);
   346                 while (hammer[poll].action < sg_done)
   347                     PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
   348                 PR_Unlock(ml);
   350                 active -= 1;  /* this is another one down */
   351                 (void)PR_JoinThread(hammer[poll].thread);
   352                 hammer[poll].thread = NULL;
   353                 if (hammer[poll].problem == sg_okay)
   354                 {
   355                     duration = PR_IntervalToMilliseconds(
   356                         PR_IntervalNow() - hammer[poll].timein);
   357                     writes = hammer[poll].writes * 1000 / duration;
   358                     if (writes < writesMin) 
   359                         writesMin = writes;
   360                     if (writes > writesMax) 
   361                         writesMax = writes;
   362                     writesTot += hammer[poll].writes;
   363                     durationTot += duration;
   364                 }
   365                 else
   366                     if (debug_mode) printf(
   367                         "%s: test failed %s after %ld seconds\n",
   368                         programName, where[hammer[poll].problem], duration);
   369 					else failed_already=1;
   370             }
   371         }
   372     }
   373     if (debug_mode) printf(
   374         "%s: [%ld [%ld] %ld] writes/sec average\n",
   375         programName, writesMin, writesTot * 1000 / durationTot, writesMax);
   377     PR_DestroyCondVar(cv);
   378     PR_DestroyLock(ml);
   380 	if (failed_already) 
   381 	{
   382 	    printf("FAIL\n");
   383 		return 1;
   384 	}
   385     else
   386     {
   387         printf("PASS\n");
   388 		return 0;
   389     }
   390 }  /* main */

mercurial