home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / tests / ranfile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  13.9 KB  |  411 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /***********************************************************************
  20. **
  21. ** Contact:     AOF<freier@netscape.com>
  22. **
  23. ** Name: ranfile.c
  24. **
  25. ** Description: Test to hammer on various components of NSPR
  26. ** Modification History:
  27. ** 20-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
  28. **             The debug mode will print all of the printfs associated with this test.
  29. **             The regress mode will be the default mode. Since the regress tool limits
  30. **           the output to a one line status:PASS or FAIL,all of the printf statements
  31. **             have been handled with an if (debug_mode) statement.
  32. ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
  33. **            recognize the return code from tha main program.
  34. ***********************************************************************/
  35.  
  36.  
  37. /***********************************************************************
  38. ** Includes
  39. ***********************************************************************/
  40. /* Used to get the command line option */
  41. #include "plgetopt.h"
  42.  
  43. #include "prinit.h"
  44. #include "prthread.h"
  45. #include "prlock.h"
  46. #include "prcvar.h"
  47. #include "prmem.h"
  48. #include "prinrval.h"
  49. #include "prio.h"
  50.  
  51. #include <string.h>
  52. #include <stdio.h>
  53.  
  54. static PRIntn debug_mode = 0;
  55. static PRIntn failed_already=0;
  56. static PRThreadScope thread_scope = PR_LOCAL_THREAD;
  57.  
  58. typedef enum {sg_go, sg_stop, sg_done} Action;
  59. typedef enum {sg_okay, sg_open, sg_close, sg_delete, sg_write, sg_seek} Problem;
  60.  
  61. typedef struct Hammer_s {
  62.     PRLock *ml;
  63.     PRCondVar *cv;
  64.     PRUint32 id;
  65.     PRUint32 limit;
  66.     PRUint32 writes;
  67.     PRThread *thread;
  68.     PRIntervalTime timein;
  69.     Action action;
  70.     Problem problem;
  71. } Hammer_t;
  72.  
  73. static PRInt32 pageSize = 1024;
  74. static const char* baseName = "./";
  75. static const char *programName = "Random File";
  76.  
  77. #ifdef XP_MAC
  78. #include "prlog.h"
  79. #define printf PR_LogPrint
  80. extern void SetupMacPrintfLog(char *logFile);
  81. #endif
  82.  
  83. /***********************************************************************
  84. ** PRIVATE FUNCTION:    Random
  85. ** DESCRIPTION:
  86. **   Generate a pseudo-random number
  87. ** INPUTS:      None
  88. ** OUTPUTS:     None
  89. ** RETURN:      A pseudo-random unsigned number, 32-bits wide
  90. ** SIDE EFFECTS:
  91. **      Updates random seed (a static)
  92. ** RESTRICTIONS:
  93. **      None
  94. ** MEMORY:      NA
  95. ** ALGORITHM:
  96. **      Uses the current interval timer value, promoted to a 64 bit
  97. **      float as a multiplier for a static residue (which begins
  98. **      as an uninitialized variable). The result is bits [16..48)
  99. **      of the product. Seed is then updated with the return value
  100. **      promoted to a float-64.
  101. ***********************************************************************/
  102. static PRUint32 Random(void)
  103. {
  104.     PRUint32 rv;
  105.     PRUint64 shift;
  106.     static PRFloat64 seed = 0x58a9382;  /* Just make sure it isn't 0! */
  107.     PRFloat64 random = seed * (PRFloat64)PR_IntervalNow();
  108.     LL_USHR(shift, *((PRUint64*)&random), 16);
  109.     LL_L2UI(rv, shift);
  110.     seed = (PRFloat64)rv;
  111.     return rv;
  112. }  /* Random */
  113.  
  114. /***********************************************************************
  115. ** PRIVATE FUNCTION:    Thread
  116. ** DESCRIPTION:
  117. **   Hammer on the file I/O system
  118. ** INPUTS:      A pointer to the thread's private data
  119. ** OUTPUTS:     None
  120. ** RETURN:      None
  121. ** SIDE EFFECTS:
  122. **      Creates, accesses and deletes a file
  123. ** RESTRICTIONS:
  124. **      (Currently) must have file create permission in "/usr/tmp".
  125. ** MEMORY:      NA
  126. ** ALGORITHM:
  127. **      This function is a root of a thread
  128. **      1) Creates a (hopefully) unique file in /usr/tmp/
  129. **      2) Writes a zero to a random number of sequential pages
  130. **      3) Closes the file
  131. **      4) Reopens the file
  132. **      5) Seeks to a random page within the file
  133. **      6) Writes a one byte on that page
  134. **      7) Repeat steps [5..6] for each page in the file
  135. **      8) Close and delete the file
  136. **      9) Repeat steps [1..8] until told to stop
  137. **     10) Notify complete and return
  138. ***********************************************************************/
  139. static void PR_CALLBACK Thread(void *arg)
  140. {
  141.     PRUint32 index;
  142.     char filename[30];
  143.     const char zero = 0;
  144.     PRFileDesc *file = NULL;
  145.     PRStatus rv = PR_SUCCESS;
  146.     Hammer_t *cd = (Hammer_t*)arg;
  147.  
  148.     (void)sprintf(filename, "%ssg%04ld.dat", baseName, cd->id);
  149.  
  150.     if (debug_mode) printf("Starting work on %s\n", filename);
  151.  
  152.     while (PR_TRUE)
  153.     {
  154.         PRUint32 bytes;
  155.         PRUint32 minor = (Random() % cd->limit) + 1;
  156.         PRUint32 random = (Random() % cd->limit) + 1;
  157.         PRUint32 pages = (Random() % cd->limit) + 10;
  158.         while (minor-- > 0)
  159.         {
  160.             cd->problem = sg_okay;
  161.             if (cd->action != sg_go) goto finished;
  162.             cd->problem = sg_open;
  163.             file = PR_Open(filename, PR_RDWR|PR_CREATE_FILE, 0666);
  164.             if (file == NULL) goto finished;
  165.             for (index = 0; index < pages; index++)
  166.             {
  167.                 cd->problem = sg_okay;
  168.                 if (cd->action != sg_go) goto close;
  169.                 cd->problem = sg_seek;
  170.                 bytes = PR_Seek(file, pageSize * index, PR_SEEK_SET);
  171.                 if (bytes != pageSize * index) goto close;
  172.                 cd->problem = sg_write;
  173.                 bytes = PR_Write(file, &zero, sizeof(zero));
  174.                 if (bytes <= 0) goto close;
  175.                 cd->writes += 1;
  176.             }
  177.             cd->problem = sg_close;
  178.             rv = PR_Close(file);
  179.             if (rv != PR_SUCCESS) goto purge;
  180.  
  181.             cd->problem = sg_okay;
  182.             if (cd->action != sg_go) goto purge;
  183.  
  184.             cd->problem = sg_open;
  185.             file = PR_Open(filename, PR_RDWR, 0666);
  186.             for (index = 0; index < pages; index++)
  187.             {
  188.                 cd->problem = sg_okay;
  189.                 if (cd->action != sg_go) goto close;
  190.                 cd->problem = sg_seek;
  191.                 bytes = PR_Seek(file, pageSize * index, PR_SEEK_SET);
  192.                 if (bytes != pageSize * index) goto close;
  193.                 cd->problem = sg_write;
  194.                 bytes = PR_Write(file, &zero, sizeof(zero));
  195.                 if (bytes <= 0) goto close;
  196.                 cd->writes += 1;
  197.                 random = (random + 511) % pages;
  198.             }
  199.             cd->problem = sg_close;
  200.             rv = PR_Close(file);
  201.             if (rv != PR_SUCCESS) goto purge;
  202.             cd->problem = sg_delete;
  203.             rv = PR_Delete(filename);
  204.             if (rv != PR_SUCCESS) goto finished;
  205.        }
  206.     }
  207.  
  208. close:
  209.     (void)PR_Close(file);
  210. purge:
  211.     (void)PR_Delete(filename);
  212. finished:
  213.     PR_Lock(cd->ml);
  214.     cd->action = sg_done;
  215.     PR_NotifyCondVar(cd->cv);
  216.     PR_Unlock(cd->ml);
  217.  
  218.     if (debug_mode) printf("Ending work on %s\n", filename);
  219.  
  220.     return;
  221. }  /* Thread */
  222.  
  223. static Hammer_t hammer[100];
  224. static PRCondVar *cv;
  225. /***********************************************************************
  226. ** PRIVATE FUNCTION:    main
  227. ** DESCRIPTION:
  228. **   Hammer on the file I/O system
  229. ** INPUTS:      The usual argc and argv
  230. **              argv[0] - program name (not used)
  231. **              argv[1] - the number of times to execute the major loop
  232. **              argv[2] - the number of threads to toss into the batch
  233. **              argv[3] - the clipping number applied to randoms
  234. **              default values: loops = 2, threads = 10, limit = 57
  235. ** OUTPUTS:     None
  236. ** RETURN:      None
  237. ** SIDE EFFECTS:
  238. **      Creates, accesses and deletes lots of files
  239. ** RESTRICTIONS:
  240. **      (Currently) must have file create permission in "/usr/tmp".
  241. ** MEMORY:      NA
  242. ** ALGORITHM:
  243. **      1) Fork a "Thread()"
  244. **      2) Wait for 'interleave' seconds
  245. **      3) For [0..'threads') repeat [1..2]
  246. **      4) Mark all objects to stop
  247. **      5) Collect the threads, accumulating the results
  248. **      6) For [0..'loops') repeat [1..5]
  249. **      7) Print accumulated results and exit
  250. **
  251. **      Characteristic output (from IRIX)
  252. **          Random File: Using loops = 2, threads = 10, limit = 57
  253. **          Random File: [min [avg] max] writes/sec average
  254. ***********************************************************************/
  255. int main (int argc,      char   *argv[])
  256. {
  257.     PRLock *ml;
  258.     PRUint32 id = 0;
  259.     int active, poll;
  260.     PRIntervalTime interleave;
  261.     PRIntervalTime duration = 0;
  262.     int limit = 0, loops = 0, threads = 0, times;
  263.     PRUint32 writes, writesMin = 0x7fffffff, writesTot = 0, durationTot = 0, writesMax = 0;
  264.  
  265.     const char *where[] = {"okay", "open", "close", "delete", "write", "seek"};
  266.  
  267.     /* The command line argument: -d is used to determine if the test is being run
  268.     in debug mode. The regress tool requires only one line output:PASS or FAIL.
  269.     All of the printfs associated with this test has been handled with a if (debug_mode)
  270.     test.
  271.     Usage: test_name -d
  272.     */
  273.     PLOptStatus os;
  274.     PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:t:i:");
  275.     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  276.     {
  277.         if (PL_OPT_BAD == os) continue;
  278.         switch (opt->option)
  279.         {
  280.         case 'G':  /* global threads */
  281.             thread_scope = PR_GLOBAL_THREAD;
  282.             break;
  283.         case 'd':  /* debug mode */
  284.             debug_mode = 1;
  285.             break;
  286.         case 'l':  /* limiting number */
  287.             limit = limit = atoi(opt->value);
  288.             break;
  289.         case 't':  /* number of threads */
  290.             threads = atoi(opt->value);
  291.             break;
  292.         case 'i':  /* iteration counter */
  293.             loops = atoi(opt->value);
  294.             break;
  295.          default:
  296.             break;
  297.         }
  298.     }
  299.     PL_DestroyOptState(opt);
  300.  
  301.  /* main test */
  302.     
  303.     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
  304.     PR_STDIO_INIT();
  305.  
  306.     interleave = PR_SecondsToInterval(10);
  307.  
  308. #ifdef XP_MAC
  309.     SetupMacPrintfLog("ranfile.log");
  310.     debug_mode = 1;
  311. #endif
  312.  
  313.     ml = PR_NewLock();
  314.     cv = PR_NewCondVar(ml);
  315.  
  316.     if (loops == 0) loops = 2;
  317.     if (limit == 0) limit = 57;
  318.     if (threads == 0) threads = 10;
  319.  
  320.     if (debug_mode) printf(
  321.         "%s: Using loops = %d, threads = %d, limit = %d and %s threads\n",
  322.         programName, loops, threads, limit,
  323.         (thread_scope == PR_LOCAL_THREAD) ? "LOCAL" : "GLOBAL");
  324.  
  325.     for (times = 0; times < loops; ++times)
  326.     {
  327.         if (debug_mode) printf("%s: Setting concurrency level to %d\n", programName, times + 1);
  328.         PR_SetConcurrency(times + 1);
  329.         for (active = 0; active < threads; active++)
  330.         {
  331.             hammer[active].ml = ml;
  332.             hammer[active].cv = cv;
  333.             hammer[active].id = id++;
  334.             hammer[active].writes = 0;
  335.             hammer[active].action = sg_go;
  336.             hammer[active].problem = sg_okay;
  337.             hammer[active].limit = (Random() % limit) + 1;
  338.             hammer[active].timein = PR_IntervalNow();
  339.             hammer[active].thread = PR_CreateThread(
  340.                 PR_USER_THREAD, Thread, &hammer[active],
  341.                 PR_GetThreadPriority(PR_GetCurrentThread()),
  342.                 thread_scope, PR_JOINABLE_THREAD, 0);
  343.  
  344.             PR_Lock(ml);
  345.             PR_WaitCondVar(cv, interleave);  /* start new ones slowly */
  346.             PR_Unlock(ml);
  347.         }
  348.  
  349.         /*
  350.          * The last thread started has had the opportunity to run for
  351.          * 'interleave' seconds. Now gather them all back in.
  352.          */
  353.         PR_Lock(ml);
  354.         for (poll = 0; poll < threads; poll++)
  355.         {
  356.             if (hammer[poll].action == sg_go)  /* don't overwrite done */
  357.                 hammer[poll].action = sg_stop;  /* ask him to stop */
  358.         }
  359.         PR_Unlock(ml);
  360.  
  361.         while (active > 0)
  362.         {
  363.             for (poll = 0; poll < threads; poll++)
  364.             {
  365.                 PR_Lock(ml);
  366.                 while (hammer[poll].action < sg_done)
  367.                     PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
  368.                 PR_Unlock(ml);
  369.  
  370.                 active -= 1;  /* this is another one down */
  371.                 (void)PR_JoinThread(hammer[poll].thread);
  372.                 hammer[poll].thread = NULL;
  373.                 if (hammer[poll].problem == sg_okay)
  374.                 {
  375.                     duration = PR_IntervalToMilliseconds(
  376.                         PR_IntervalNow() - hammer[poll].timein);
  377.                     writes = hammer[poll].writes * 1000 / duration;
  378.                     if (writes < writesMin) 
  379.                         writesMin = writes;
  380.                     if (writes > writesMax) 
  381.                         writesMax = writes;
  382.                     writesTot += hammer[poll].writes;
  383.                     durationTot += duration;
  384.                 }
  385.                 else
  386.                     if (debug_mode) printf(
  387.                         "%s: test failed %s after %ld seconds\n",
  388.                         programName, where[hammer[poll].problem], duration);
  389.                     else failed_already=1;
  390.             }
  391.         }
  392.     }
  393.     if (debug_mode) printf(
  394.         "%s: [%ld [%ld] %ld] writes/sec average\n",
  395.         programName, writesMin, writesTot * 1000 / durationTot, writesMax);
  396.  
  397.     PR_DestroyCondVar(cv);
  398.     PR_DestroyLock(ml);
  399.  
  400.     if (failed_already) 
  401.     {
  402.         printf("FAIL\n");
  403.         return 1;
  404.     }
  405.     else
  406.     {
  407.         printf("PASS\n");
  408.         return 0;
  409.     }
  410. }  /* main */
  411.