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, &notifyData,
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