|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 */ |