nsprpub/pr/tests/alarm.c

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

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

mercurial