Wed, 31 Dec 2014 06:09:35 +0100
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 */