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