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

Thu, 15 Jan 2015 21:13:52 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:13:52 +0100
branch
TOR_BUG_9701
changeset 12
7540298fafa1
permissions
-rw-r--r--

Remove forgotten relic of ABI crash risk averse overloaded method change.

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

mercurial