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/. */
5
6 /***********************************************************************
7 ** 1996 - Netscape Communications Corporation
8 **
9 ** Name: alarmtst.c
10 **
11 ** Description: Test alarms
12 **
13 ** Modification History:
14 ** 13-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 ***********************************************************************/
22
23 /***********************************************************************
24 ** Includes
25 ***********************************************************************/
26
27 #include "prlog.h"
28 #include "prinit.h"
29 #include "obsolete/pralarm.h"
30 #include "prlock.h"
31 #include "prlong.h"
32 #include "prcvar.h"
33 #include "prinrval.h"
34 #include "prtime.h"
35
36 /* Used to get the command line option */
37 #include "plgetopt.h"
38 #include <stdio.h>
39 #include <stdlib.h>
40
41 #if defined(XP_UNIX)
42 #include <sys/time.h>
43 #endif
44
45 static PRIntn debug_mode;
46 static PRIntn failed_already=0;
47 static PRThreadScope thread_scope = PR_LOCAL_THREAD;
48
49 typedef struct notifyData {
50 PRLock *ml;
51 PRCondVar *child;
52 PRCondVar *parent;
53 PRBool pending;
54 PRUint32 counter;
55 } NotifyData;
56
Notifier(void * arg)57 static void Notifier(void *arg)
58 {
59 NotifyData *notifyData = (NotifyData*)arg;
60 PR_Lock(notifyData->ml);
61 while (notifyData->counter > 0)
62 {
63 while (!notifyData->pending)
64 PR_WaitCondVar(notifyData->child, PR_INTERVAL_NO_TIMEOUT);
65 notifyData->counter -= 1;
66 notifyData->pending = PR_FALSE;
67 PR_NotifyCondVar(notifyData->parent);
68 }
69 PR_Unlock(notifyData->ml);
70 } /* Notifier */
71 /***********************************************************************
72 ** PRIVATE FUNCTION: ConditionNotify
73 ** DESCRIPTION:
74 **
75 ** INPUTS: loops
76 ** OUTPUTS: None
77 ** RETURN: overhead
78 ** SIDE EFFECTS:
79 **
80 ** RESTRICTIONS:
81 ** None
82 ** MEMORY: NA
83 ** ALGORITHM:
84 **
85 ***********************************************************************/
86
87
ConditionNotify(PRUint32 loops)88 static PRIntervalTime ConditionNotify(PRUint32 loops)
89 {
90 PRThread *thread;
91 NotifyData notifyData;
92 PRIntervalTime timein, overhead;
93
94 timein = PR_IntervalNow();
95
96 notifyData.counter = loops;
97 notifyData.ml = PR_NewLock();
98 notifyData.child = PR_NewCondVar(notifyData.ml);
99 notifyData.parent = PR_NewCondVar(notifyData.ml);
100 thread = PR_CreateThread(
101 PR_USER_THREAD, Notifier, ¬ifyData,
102 PR_GetThreadPriority(PR_GetCurrentThread()),
103 thread_scope, PR_JOINABLE_THREAD, 0);
104
105 overhead = PR_IntervalNow() - timein; /* elapsed so far */
106
107 PR_Lock(notifyData.ml);
108 while (notifyData.counter > 0)
109 {
110 notifyData.pending = PR_TRUE;
111 PR_NotifyCondVar(notifyData.child);
112 while (notifyData.pending)
113 PR_WaitCondVar(notifyData.parent, PR_INTERVAL_NO_TIMEOUT);
114 }
115 PR_Unlock(notifyData.ml);
116
117 timein = PR_IntervalNow();
118
119 (void)PR_JoinThread(thread);
120 PR_DestroyCondVar(notifyData.child);
121 PR_DestroyCondVar(notifyData.parent);
122 PR_DestroyLock(notifyData.ml);
123
124 overhead += (PR_IntervalNow() - timein); /* more overhead */
125
126 return overhead;
127 } /* ConditionNotify */
128
ConditionTimeout(PRUint32 loops)129 static PRIntervalTime ConditionTimeout(PRUint32 loops)
130 {
131 PRUintn count;
132 PRIntervalTime overhead, timein = PR_IntervalNow();
133
134 PRLock *ml = PR_NewLock();
135 PRCondVar *cv = PR_NewCondVar(ml);
136 PRIntervalTime interval = PR_MillisecondsToInterval(50);
137
138 overhead = PR_IntervalNow() - timein;
139
140 PR_Lock(ml);
141 for (count = 0; count < loops; ++count)
142 {
143 overhead += interval;
144 PR_ASSERT(PR_WaitCondVar(cv, interval) == PR_SUCCESS);
145 }
146 PR_Unlock(ml);
147
148 timein = PR_IntervalNow();
149 PR_DestroyCondVar(cv);
150 PR_DestroyLock(ml);
151 overhead += (PR_IntervalNow() - timein);
152
153 return overhead;
154 } /* ConditionTimeout */
155
156 typedef struct AlarmData {
157 PRLock *ml;
158 PRCondVar *cv;
159 PRUint32 rate, late, times;
160 PRIntervalTime duration, timein, period;
161 } AlarmData;
162
AlarmFn1(PRAlarmID * id,void * clientData,PRUint32 late)163 static PRBool AlarmFn1(PRAlarmID *id, void *clientData, PRUint32 late)
164 {
165 PRStatus rv = PR_SUCCESS;
166 PRBool keepGoing, resetAlarm;
167 PRIntervalTime interval, now = PR_IntervalNow();
168 AlarmData *ad = (AlarmData*)clientData;
169
170 PR_Lock(ad->ml);
171 ad->late += late;
172 ad->times += 1;
173 keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ?
174 PR_TRUE : PR_FALSE;
175 if (!keepGoing)
176 rv = PR_NotifyCondVar(ad->cv);
177 resetAlarm = ((ad->times % 31) == 0) ? PR_TRUE : PR_FALSE;
178
179 interval = (ad->period + ad->rate - 1) / ad->rate;
180 if (!late && (interval > 10))
181 {
182 interval &= (now & 0x03) + 1;
183 PR_WaitCondVar(ad->cv, interval);
184 }
185
186 PR_Unlock(ad->ml);
187
188 if (rv != PR_SUCCESS)
189 {
190 if (!debug_mode) failed_already=1;
191 else
192 printf("AlarmFn: notify status: FAIL\n");
193
194 }
195
196 if (resetAlarm)
197 {
198 ad->rate += 3;
199 ad->late = ad->times = 0;
200 if (PR_ResetAlarm(id, ad->period, ad->rate) != PR_SUCCESS)
201 {
202 if (!debug_mode)
203 failed_already=1;
204 else
205 printf("AlarmFn: Resetting alarm status: FAIL\n");
206
207 keepGoing = PR_FALSE;
208 }
209
210 }
211
212 return keepGoing;
213 } /* AlarmFn1 */
214
Alarms1(PRUint32 loops)215 static PRIntervalTime Alarms1(PRUint32 loops)
216 {
217 PRAlarm *alarm;
218 AlarmData ad;
219 PRIntervalTime overhead, timein = PR_IntervalNow();
220 PRIntervalTime duration = PR_SecondsToInterval(3);
221
222 PRLock *ml = PR_NewLock();
223 PRCondVar *cv = PR_NewCondVar(ml);
224
225 ad.ml = ml;
226 ad.cv = cv;
227 ad.rate = 1;
228 ad.times = loops;
229 ad.late = ad.times = 0;
230 ad.duration = duration;
231 ad.timein = PR_IntervalNow();
232 ad.period = PR_SecondsToInterval(1);
233
234 alarm = PR_CreateAlarm();
235
236 (void)PR_SetAlarm(
237 alarm, ad.period, ad.rate, AlarmFn1, &ad);
238
239 overhead = PR_IntervalNow() - timein;
240
241 PR_Lock(ml);
242 while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration)
243 PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
244 PR_Unlock(ml);
245
246 timein = PR_IntervalNow();
247 (void)PR_DestroyAlarm(alarm);
248 PR_DestroyCondVar(cv);
249 PR_DestroyLock(ml);
250 overhead += (PR_IntervalNow() - timein);
251
252 return duration + overhead;
253 } /* Alarms1 */
254
AlarmFn2(PRAlarmID * id,void * clientData,PRUint32 late)255 static PRBool AlarmFn2(PRAlarmID *id, void *clientData, PRUint32 late)
256 {
257 PRBool keepGoing;
258 PRStatus rv = PR_SUCCESS;
259 AlarmData *ad = (AlarmData*)clientData;
260 PRIntervalTime interval, now = PR_IntervalNow();
261
262 PR_Lock(ad->ml);
263 ad->times += 1;
264 keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ?
265 PR_TRUE : PR_FALSE;
266 interval = (ad->period + ad->rate - 1) / ad->rate;
267
268 if (!late && (interval > 10))
269 {
270 interval &= (now & 0x03) + 1;
271 PR_WaitCondVar(ad->cv, interval);
272 }
273
274 if (!keepGoing) rv = PR_NotifyCondVar(ad->cv);
275
276 PR_Unlock(ad->ml);
277
278
279 if (rv != PR_SUCCESS)
280 failed_already=1;;
281
282 return keepGoing;
283 } /* AlarmFn2 */
284
Alarms2(PRUint32 loops)285 static PRIntervalTime Alarms2(PRUint32 loops)
286 {
287 PRStatus rv;
288 PRAlarm *alarm;
289 PRIntervalTime overhead, timein = PR_IntervalNow();
290 AlarmData ad;
291 PRIntervalTime duration = PR_SecondsToInterval(30);
292
293 PRLock *ml = PR_NewLock();
294 PRCondVar *cv = PR_NewCondVar(ml);
295
296 ad.ml = ml;
297 ad.cv = cv;
298 ad.rate = 1;
299 ad.times = loops;
300 ad.late = ad.times = 0;
301 ad.duration = duration;
302 ad.timein = PR_IntervalNow();
303 ad.period = PR_SecondsToInterval(1);
304
305 alarm = PR_CreateAlarm();
306
307 (void)PR_SetAlarm(
308 alarm, ad.period, ad.rate, AlarmFn2, &ad);
309
310 overhead = PR_IntervalNow() - timein;
311
312 PR_Lock(ml);
313 while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration)
314 PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
315 PR_Unlock(ml);
316
317 timein = PR_IntervalNow();
318
319 rv = PR_DestroyAlarm(alarm);
320 if (rv != PR_SUCCESS)
321 {
322 if (!debug_mode)
323 failed_already=1;
324 else
325 printf("***Destroying alarm status: FAIL\n");
326 }
327
328
329 PR_DestroyCondVar(cv);
330 PR_DestroyLock(ml);
331
332 overhead += (PR_IntervalNow() - timein);
333
334 return duration + overhead;
335 } /* Alarms2 */
336
Alarms3(PRUint32 loops)337 static PRIntervalTime Alarms3(PRUint32 loops)
338 {
339 PRIntn i;
340 PRStatus rv;
341 PRAlarm *alarm;
342 AlarmData ad[3];
343 PRIntervalTime duration = PR_SecondsToInterval(30);
344 PRIntervalTime overhead, timein = PR_IntervalNow();
345
346 PRLock *ml = PR_NewLock();
347 PRCondVar *cv = PR_NewCondVar(ml);
348
349 for (i = 0; i < 3; ++i)
350 {
351 ad[i].ml = ml;
352 ad[i].cv = cv;
353 ad[i].rate = 1;
354 ad[i].times = loops;
355 ad[i].duration = duration;
356 ad[i].late = ad[i].times = 0;
357 ad[i].timein = PR_IntervalNow();
358 ad[i].period = PR_SecondsToInterval(1);
359
360 /* more loops, faster rate => same elapsed time */
361 ad[i].times = (i + 1) * loops;
362 ad[i].rate = (i + 1) * 10;
363 }
364
365 alarm = PR_CreateAlarm();
366
367 for (i = 0; i < 3; ++i)
368 {
369 (void)PR_SetAlarm(
370 alarm, ad[i].period, ad[i].rate,
371 AlarmFn2, &ad[i]);
372 }
373
374 overhead = PR_IntervalNow() - timein;
375
376 PR_Lock(ml);
377 for (i = 0; i < 3; ++i)
378 {
379 while ((PRIntervalTime)(PR_IntervalNow() - ad[i].timein) < duration)
380 PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
381 }
382 PR_Unlock(ml);
383
384 timein = PR_IntervalNow();
385
386 if (debug_mode)
387 printf
388 ("Alarms3 finished at %u, %u, %u\n",
389 ad[0].timein, ad[1].timein, ad[2].timein);
390
391 rv = PR_DestroyAlarm(alarm);
392 if (rv != PR_SUCCESS)
393 {
394 if (!debug_mode)
395 failed_already=1;
396 else
397 printf("***Destroying alarm status: FAIL\n");
398 }
399 PR_DestroyCondVar(cv);
400 PR_DestroyLock(ml);
401
402 overhead += (duration / 3);
403 overhead += (PR_IntervalNow() - timein);
404
405 return overhead;
406 } /* Alarms3 */
407
TimeThis(const char * msg,PRUint32 (* func)(PRUint32 loops),PRUint32 loops)408 static PRUint32 TimeThis(
409 const char *msg, PRUint32 (*func)(PRUint32 loops), PRUint32 loops)
410 {
411 PRUint32 overhead, usecs;
412 PRIntervalTime predicted, timein, timeout, ticks;
413
414 if (debug_mode)
415 printf("Testing %s ...", msg);
416
417 timein = PR_IntervalNow();
418 predicted = func(loops);
419 timeout = PR_IntervalNow();
420
421 if (debug_mode)
422 printf(" done\n");
423
424 ticks = timeout - timein;
425 usecs = PR_IntervalToMicroseconds(ticks);
426 overhead = PR_IntervalToMicroseconds(predicted);
427
428 if(ticks < predicted)
429 {
430 if (debug_mode) {
431 printf("\tFinished in negative time\n");
432 printf("\tpredicted overhead was %d usecs\n", overhead);
433 printf("\ttest completed in %d usecs\n\n", usecs);
434 }
435 }
436 else
437 {
438 if (debug_mode)
439 printf(
440 "\ttotal: %d usecs\n\toverhead: %d usecs\n\tcost: %6.3f usecs\n\n",
441 usecs, overhead, ((double)(usecs - overhead) / (double)loops));
442 }
443
444 return overhead;
445 } /* TimeThis */
446
prmain(int argc,char ** argv)447 int prmain(int argc, char** argv)
448 {
449 PRUint32 cpu, cpus = 0, loops = 0;
450
451 /* The command line argument: -d is used to determine if the test is being run
452 in debug mode. The regress tool requires only one line output:PASS or FAIL.
453 All of the printfs associated with this test has been handled with a if (debug_mode)
454 test.
455 Usage: test_name [-d]
456 */
457 PLOptStatus os;
458 PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:c:");
459 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
460 {
461 if (PL_OPT_BAD == os) continue;
462 switch (opt->option)
463 {
464 case 'G': /* GLOBAL threads */
465 thread_scope = PR_GLOBAL_THREAD;
466 break;
467 case 'd': /* debug mode */
468 debug_mode = 1;
469 break;
470 case 'l': /* loop count */
471 loops = atoi(opt->value);
472 break;
473 case 'c': /* concurrency limit */
474 cpus = atoi(opt->value);
475 break;
476 default:
477 break;
478 }
479 }
480 PL_DestroyOptState(opt);
481
482
483 if (cpus == 0) cpus = 1;
484 if (loops == 0) loops = 4;
485
486 if (debug_mode)
487 printf("Alarm: Using %d loops\n", loops);
488
489 if (debug_mode)
490 printf("Alarm: Using %d cpu(s)\n", cpus);
491
492 for (cpu = 1; cpu <= cpus; ++cpu)
493 {
494 if (debug_mode)
495 printf("\nAlarm: Using %d CPU(s)\n", cpu);
496
497 PR_SetConcurrency(cpu);
498
499 /* some basic time test */
500 (void)TimeThis("ConditionNotify", ConditionNotify, loops);
501 (void)TimeThis("ConditionTimeout", ConditionTimeout, loops);
502 (void)TimeThis("Alarms1", Alarms1, loops);
503 (void)TimeThis("Alarms2", Alarms2, loops);
504 (void)TimeThis("Alarms3", Alarms3, loops);
505 }
506 return 0;
507 }
508
main(int argc,char ** argv)509 int main(int argc, char** argv)
510 {
511 PR_Initialize(prmain, argc, argv, 0);
512 PR_STDIO_INIT();
513 if (failed_already) return 1;
514 else return 0;
515
516 } /* main */
517
518
519 /* alarmtst.c */
520