1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/tests/alarm.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,519 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/*********************************************************************** 1.10 +** 1996 - Netscape Communications Corporation 1.11 +** 1.12 +** Name: alarmtst.c 1.13 +** 1.14 +** Description: Test alarms 1.15 +** 1.16 +** Modification History: 1.17 +** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. 1.18 +** The debug mode will print all of the printfs associated with this test. 1.19 +** The regress mode will be the default mode. Since the regress tool limits 1.20 +** the output to a one line status:PASS or FAIL,all of the printf statements 1.21 +** have been handled with an if (debug_mode) statement. 1.22 +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to 1.23 +** recognize the return code from tha main program. 1.24 +***********************************************************************/ 1.25 + 1.26 +/*********************************************************************** 1.27 +** Includes 1.28 +***********************************************************************/ 1.29 + 1.30 +#include "prlog.h" 1.31 +#include "prinit.h" 1.32 +#include "obsolete/pralarm.h" 1.33 +#include "prlock.h" 1.34 +#include "prlong.h" 1.35 +#include "prcvar.h" 1.36 +#include "prinrval.h" 1.37 +#include "prtime.h" 1.38 + 1.39 +/* Used to get the command line option */ 1.40 +#include "plgetopt.h" 1.41 +#include <stdio.h> 1.42 +#include <stdlib.h> 1.43 + 1.44 +#if defined(XP_UNIX) 1.45 +#include <sys/time.h> 1.46 +#endif 1.47 + 1.48 +static PRIntn debug_mode; 1.49 +static PRIntn failed_already=0; 1.50 +static PRThreadScope thread_scope = PR_LOCAL_THREAD; 1.51 + 1.52 +typedef struct notifyData { 1.53 + PRLock *ml; 1.54 + PRCondVar *child; 1.55 + PRCondVar *parent; 1.56 + PRBool pending; 1.57 + PRUint32 counter; 1.58 +} NotifyData; 1.59 + 1.60 +static void Notifier(void *arg) 1.61 +{ 1.62 + NotifyData *notifyData = (NotifyData*)arg; 1.63 + PR_Lock(notifyData->ml); 1.64 + while (notifyData->counter > 0) 1.65 + { 1.66 + while (!notifyData->pending) 1.67 + PR_WaitCondVar(notifyData->child, PR_INTERVAL_NO_TIMEOUT); 1.68 + notifyData->counter -= 1; 1.69 + notifyData->pending = PR_FALSE; 1.70 + PR_NotifyCondVar(notifyData->parent); 1.71 + } 1.72 + PR_Unlock(notifyData->ml); 1.73 +} /* Notifier */ 1.74 +/*********************************************************************** 1.75 +** PRIVATE FUNCTION: ConditionNotify 1.76 +** DESCRIPTION: 1.77 +** 1.78 +** INPUTS: loops 1.79 +** OUTPUTS: None 1.80 +** RETURN: overhead 1.81 +** SIDE EFFECTS: 1.82 +** 1.83 +** RESTRICTIONS: 1.84 +** None 1.85 +** MEMORY: NA 1.86 +** ALGORITHM: 1.87 +** 1.88 +***********************************************************************/ 1.89 + 1.90 + 1.91 +static PRIntervalTime ConditionNotify(PRUint32 loops) 1.92 +{ 1.93 + PRThread *thread; 1.94 + NotifyData notifyData; 1.95 + PRIntervalTime timein, overhead; 1.96 + 1.97 + timein = PR_IntervalNow(); 1.98 + 1.99 + notifyData.counter = loops; 1.100 + notifyData.ml = PR_NewLock(); 1.101 + notifyData.child = PR_NewCondVar(notifyData.ml); 1.102 + notifyData.parent = PR_NewCondVar(notifyData.ml); 1.103 + thread = PR_CreateThread( 1.104 + PR_USER_THREAD, Notifier, ¬ifyData, 1.105 + PR_GetThreadPriority(PR_GetCurrentThread()), 1.106 + thread_scope, PR_JOINABLE_THREAD, 0); 1.107 + 1.108 + overhead = PR_IntervalNow() - timein; /* elapsed so far */ 1.109 + 1.110 + PR_Lock(notifyData.ml); 1.111 + while (notifyData.counter > 0) 1.112 + { 1.113 + notifyData.pending = PR_TRUE; 1.114 + PR_NotifyCondVar(notifyData.child); 1.115 + while (notifyData.pending) 1.116 + PR_WaitCondVar(notifyData.parent, PR_INTERVAL_NO_TIMEOUT); 1.117 + } 1.118 + PR_Unlock(notifyData.ml); 1.119 + 1.120 + timein = PR_IntervalNow(); 1.121 + 1.122 + (void)PR_JoinThread(thread); 1.123 + PR_DestroyCondVar(notifyData.child); 1.124 + PR_DestroyCondVar(notifyData.parent); 1.125 + PR_DestroyLock(notifyData.ml); 1.126 + 1.127 + overhead += (PR_IntervalNow() - timein); /* more overhead */ 1.128 + 1.129 + return overhead; 1.130 +} /* ConditionNotify */ 1.131 + 1.132 +static PRIntervalTime ConditionTimeout(PRUint32 loops) 1.133 +{ 1.134 + PRUintn count; 1.135 + PRIntervalTime overhead, timein = PR_IntervalNow(); 1.136 + 1.137 + PRLock *ml = PR_NewLock(); 1.138 + PRCondVar *cv = PR_NewCondVar(ml); 1.139 + PRIntervalTime interval = PR_MillisecondsToInterval(50); 1.140 + 1.141 + overhead = PR_IntervalNow() - timein; 1.142 + 1.143 + PR_Lock(ml); 1.144 + for (count = 0; count < loops; ++count) 1.145 + { 1.146 + overhead += interval; 1.147 + PR_ASSERT(PR_WaitCondVar(cv, interval) == PR_SUCCESS); 1.148 + } 1.149 + PR_Unlock(ml); 1.150 + 1.151 + timein = PR_IntervalNow(); 1.152 + PR_DestroyCondVar(cv); 1.153 + PR_DestroyLock(ml); 1.154 + overhead += (PR_IntervalNow() - timein); 1.155 + 1.156 + return overhead; 1.157 +} /* ConditionTimeout */ 1.158 + 1.159 +typedef struct AlarmData { 1.160 + PRLock *ml; 1.161 + PRCondVar *cv; 1.162 + PRUint32 rate, late, times; 1.163 + PRIntervalTime duration, timein, period; 1.164 +} AlarmData; 1.165 + 1.166 +static PRBool AlarmFn1(PRAlarmID *id, void *clientData, PRUint32 late) 1.167 +{ 1.168 + PRStatus rv = PR_SUCCESS; 1.169 + PRBool keepGoing, resetAlarm; 1.170 + PRIntervalTime interval, now = PR_IntervalNow(); 1.171 + AlarmData *ad = (AlarmData*)clientData; 1.172 + 1.173 + PR_Lock(ad->ml); 1.174 + ad->late += late; 1.175 + ad->times += 1; 1.176 + keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ? 1.177 + PR_TRUE : PR_FALSE; 1.178 + if (!keepGoing) 1.179 + rv = PR_NotifyCondVar(ad->cv); 1.180 + resetAlarm = ((ad->times % 31) == 0) ? PR_TRUE : PR_FALSE; 1.181 + 1.182 + interval = (ad->period + ad->rate - 1) / ad->rate; 1.183 + if (!late && (interval > 10)) 1.184 + { 1.185 + interval &= (now & 0x03) + 1; 1.186 + PR_WaitCondVar(ad->cv, interval); 1.187 + } 1.188 + 1.189 + PR_Unlock(ad->ml); 1.190 + 1.191 + if (rv != PR_SUCCESS) 1.192 + { 1.193 + if (!debug_mode) failed_already=1; 1.194 + else 1.195 + printf("AlarmFn: notify status: FAIL\n"); 1.196 + 1.197 + } 1.198 + 1.199 + if (resetAlarm) 1.200 + { 1.201 + ad->rate += 3; 1.202 + ad->late = ad->times = 0; 1.203 + if (PR_ResetAlarm(id, ad->period, ad->rate) != PR_SUCCESS) 1.204 + { 1.205 + if (!debug_mode) 1.206 + failed_already=1; 1.207 + else 1.208 + printf("AlarmFn: Resetting alarm status: FAIL\n"); 1.209 + 1.210 + keepGoing = PR_FALSE; 1.211 + } 1.212 + 1.213 + } 1.214 + 1.215 + return keepGoing; 1.216 +} /* AlarmFn1 */ 1.217 + 1.218 +static PRIntervalTime Alarms1(PRUint32 loops) 1.219 +{ 1.220 + PRAlarm *alarm; 1.221 + AlarmData ad; 1.222 + PRIntervalTime overhead, timein = PR_IntervalNow(); 1.223 + PRIntervalTime duration = PR_SecondsToInterval(3); 1.224 + 1.225 + PRLock *ml = PR_NewLock(); 1.226 + PRCondVar *cv = PR_NewCondVar(ml); 1.227 + 1.228 + ad.ml = ml; 1.229 + ad.cv = cv; 1.230 + ad.rate = 1; 1.231 + ad.times = loops; 1.232 + ad.late = ad.times = 0; 1.233 + ad.duration = duration; 1.234 + ad.timein = PR_IntervalNow(); 1.235 + ad.period = PR_SecondsToInterval(1); 1.236 + 1.237 + alarm = PR_CreateAlarm(); 1.238 + 1.239 + (void)PR_SetAlarm( 1.240 + alarm, ad.period, ad.rate, AlarmFn1, &ad); 1.241 + 1.242 + overhead = PR_IntervalNow() - timein; 1.243 + 1.244 + PR_Lock(ml); 1.245 + while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration) 1.246 + PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT); 1.247 + PR_Unlock(ml); 1.248 + 1.249 + timein = PR_IntervalNow(); 1.250 + (void)PR_DestroyAlarm(alarm); 1.251 + PR_DestroyCondVar(cv); 1.252 + PR_DestroyLock(ml); 1.253 + overhead += (PR_IntervalNow() - timein); 1.254 + 1.255 + return duration + overhead; 1.256 +} /* Alarms1 */ 1.257 + 1.258 +static PRBool AlarmFn2(PRAlarmID *id, void *clientData, PRUint32 late) 1.259 +{ 1.260 + PRBool keepGoing; 1.261 + PRStatus rv = PR_SUCCESS; 1.262 + AlarmData *ad = (AlarmData*)clientData; 1.263 + PRIntervalTime interval, now = PR_IntervalNow(); 1.264 + 1.265 + PR_Lock(ad->ml); 1.266 + ad->times += 1; 1.267 + keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ? 1.268 + PR_TRUE : PR_FALSE; 1.269 + interval = (ad->period + ad->rate - 1) / ad->rate; 1.270 + 1.271 + if (!late && (interval > 10)) 1.272 + { 1.273 + interval &= (now & 0x03) + 1; 1.274 + PR_WaitCondVar(ad->cv, interval); 1.275 + } 1.276 + 1.277 + if (!keepGoing) rv = PR_NotifyCondVar(ad->cv); 1.278 + 1.279 + PR_Unlock(ad->ml); 1.280 + 1.281 + 1.282 + if (rv != PR_SUCCESS) 1.283 + failed_already=1;; 1.284 + 1.285 + return keepGoing; 1.286 +} /* AlarmFn2 */ 1.287 + 1.288 +static PRIntervalTime Alarms2(PRUint32 loops) 1.289 +{ 1.290 + PRStatus rv; 1.291 + PRAlarm *alarm; 1.292 + PRIntervalTime overhead, timein = PR_IntervalNow(); 1.293 + AlarmData ad; 1.294 + PRIntervalTime duration = PR_SecondsToInterval(30); 1.295 + 1.296 + PRLock *ml = PR_NewLock(); 1.297 + PRCondVar *cv = PR_NewCondVar(ml); 1.298 + 1.299 + ad.ml = ml; 1.300 + ad.cv = cv; 1.301 + ad.rate = 1; 1.302 + ad.times = loops; 1.303 + ad.late = ad.times = 0; 1.304 + ad.duration = duration; 1.305 + ad.timein = PR_IntervalNow(); 1.306 + ad.period = PR_SecondsToInterval(1); 1.307 + 1.308 + alarm = PR_CreateAlarm(); 1.309 + 1.310 + (void)PR_SetAlarm( 1.311 + alarm, ad.period, ad.rate, AlarmFn2, &ad); 1.312 + 1.313 + overhead = PR_IntervalNow() - timein; 1.314 + 1.315 + PR_Lock(ml); 1.316 + while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration) 1.317 + PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT); 1.318 + PR_Unlock(ml); 1.319 + 1.320 + timein = PR_IntervalNow(); 1.321 + 1.322 + rv = PR_DestroyAlarm(alarm); 1.323 + if (rv != PR_SUCCESS) 1.324 + { 1.325 + if (!debug_mode) 1.326 + failed_already=1; 1.327 + else 1.328 + printf("***Destroying alarm status: FAIL\n"); 1.329 + } 1.330 + 1.331 + 1.332 + PR_DestroyCondVar(cv); 1.333 + PR_DestroyLock(ml); 1.334 + 1.335 + overhead += (PR_IntervalNow() - timein); 1.336 + 1.337 + return duration + overhead; 1.338 +} /* Alarms2 */ 1.339 + 1.340 +static PRIntervalTime Alarms3(PRUint32 loops) 1.341 +{ 1.342 + PRIntn i; 1.343 + PRStatus rv; 1.344 + PRAlarm *alarm; 1.345 + AlarmData ad[3]; 1.346 + PRIntervalTime duration = PR_SecondsToInterval(30); 1.347 + PRIntervalTime overhead, timein = PR_IntervalNow(); 1.348 + 1.349 + PRLock *ml = PR_NewLock(); 1.350 + PRCondVar *cv = PR_NewCondVar(ml); 1.351 + 1.352 + for (i = 0; i < 3; ++i) 1.353 + { 1.354 + ad[i].ml = ml; 1.355 + ad[i].cv = cv; 1.356 + ad[i].rate = 1; 1.357 + ad[i].times = loops; 1.358 + ad[i].duration = duration; 1.359 + ad[i].late = ad[i].times = 0; 1.360 + ad[i].timein = PR_IntervalNow(); 1.361 + ad[i].period = PR_SecondsToInterval(1); 1.362 + 1.363 + /* more loops, faster rate => same elapsed time */ 1.364 + ad[i].times = (i + 1) * loops; 1.365 + ad[i].rate = (i + 1) * 10; 1.366 + } 1.367 + 1.368 + alarm = PR_CreateAlarm(); 1.369 + 1.370 + for (i = 0; i < 3; ++i) 1.371 + { 1.372 + (void)PR_SetAlarm( 1.373 + alarm, ad[i].period, ad[i].rate, 1.374 + AlarmFn2, &ad[i]); 1.375 + } 1.376 + 1.377 + overhead = PR_IntervalNow() - timein; 1.378 + 1.379 + PR_Lock(ml); 1.380 + for (i = 0; i < 3; ++i) 1.381 + { 1.382 + while ((PRIntervalTime)(PR_IntervalNow() - ad[i].timein) < duration) 1.383 + PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT); 1.384 + } 1.385 + PR_Unlock(ml); 1.386 + 1.387 + timein = PR_IntervalNow(); 1.388 + 1.389 + if (debug_mode) 1.390 + printf 1.391 + ("Alarms3 finished at %u, %u, %u\n", 1.392 + ad[0].timein, ad[1].timein, ad[2].timein); 1.393 + 1.394 + rv = PR_DestroyAlarm(alarm); 1.395 + if (rv != PR_SUCCESS) 1.396 + { 1.397 + if (!debug_mode) 1.398 + failed_already=1; 1.399 + else 1.400 + printf("***Destroying alarm status: FAIL\n"); 1.401 + } 1.402 + PR_DestroyCondVar(cv); 1.403 + PR_DestroyLock(ml); 1.404 + 1.405 + overhead += (duration / 3); 1.406 + overhead += (PR_IntervalNow() - timein); 1.407 + 1.408 + return overhead; 1.409 +} /* Alarms3 */ 1.410 + 1.411 +static PRUint32 TimeThis( 1.412 + const char *msg, PRUint32 (*func)(PRUint32 loops), PRUint32 loops) 1.413 +{ 1.414 + PRUint32 overhead, usecs; 1.415 + PRIntervalTime predicted, timein, timeout, ticks; 1.416 + 1.417 + if (debug_mode) 1.418 + printf("Testing %s ...", msg); 1.419 + 1.420 + timein = PR_IntervalNow(); 1.421 + predicted = func(loops); 1.422 + timeout = PR_IntervalNow(); 1.423 + 1.424 + if (debug_mode) 1.425 + printf(" done\n"); 1.426 + 1.427 + ticks = timeout - timein; 1.428 + usecs = PR_IntervalToMicroseconds(ticks); 1.429 + overhead = PR_IntervalToMicroseconds(predicted); 1.430 + 1.431 + if(ticks < predicted) 1.432 + { 1.433 + if (debug_mode) { 1.434 + printf("\tFinished in negative time\n"); 1.435 + printf("\tpredicted overhead was %d usecs\n", overhead); 1.436 + printf("\ttest completed in %d usecs\n\n", usecs); 1.437 + } 1.438 + } 1.439 + else 1.440 + { 1.441 + if (debug_mode) 1.442 + printf( 1.443 + "\ttotal: %d usecs\n\toverhead: %d usecs\n\tcost: %6.3f usecs\n\n", 1.444 + usecs, overhead, ((double)(usecs - overhead) / (double)loops)); 1.445 + } 1.446 + 1.447 + return overhead; 1.448 +} /* TimeThis */ 1.449 + 1.450 +int prmain(int argc, char** argv) 1.451 +{ 1.452 + PRUint32 cpu, cpus = 0, loops = 0; 1.453 + 1.454 + /* The command line argument: -d is used to determine if the test is being run 1.455 + in debug mode. The regress tool requires only one line output:PASS or FAIL. 1.456 + All of the printfs associated with this test has been handled with a if (debug_mode) 1.457 + test. 1.458 + Usage: test_name [-d] 1.459 + */ 1.460 + PLOptStatus os; 1.461 + PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:c:"); 1.462 + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) 1.463 + { 1.464 + if (PL_OPT_BAD == os) continue; 1.465 + switch (opt->option) 1.466 + { 1.467 + case 'G': /* GLOBAL threads */ 1.468 + thread_scope = PR_GLOBAL_THREAD; 1.469 + break; 1.470 + case 'd': /* debug mode */ 1.471 + debug_mode = 1; 1.472 + break; 1.473 + case 'l': /* loop count */ 1.474 + loops = atoi(opt->value); 1.475 + break; 1.476 + case 'c': /* concurrency limit */ 1.477 + cpus = atoi(opt->value); 1.478 + break; 1.479 + default: 1.480 + break; 1.481 + } 1.482 + } 1.483 + PL_DestroyOptState(opt); 1.484 + 1.485 + 1.486 + if (cpus == 0) cpus = 1; 1.487 + if (loops == 0) loops = 4; 1.488 + 1.489 + if (debug_mode) 1.490 + printf("Alarm: Using %d loops\n", loops); 1.491 + 1.492 + if (debug_mode) 1.493 + printf("Alarm: Using %d cpu(s)\n", cpus); 1.494 + 1.495 + for (cpu = 1; cpu <= cpus; ++cpu) 1.496 + { 1.497 + if (debug_mode) 1.498 + printf("\nAlarm: Using %d CPU(s)\n", cpu); 1.499 + 1.500 + PR_SetConcurrency(cpu); 1.501 + 1.502 + /* some basic time test */ 1.503 + (void)TimeThis("ConditionNotify", ConditionNotify, loops); 1.504 + (void)TimeThis("ConditionTimeout", ConditionTimeout, loops); 1.505 + (void)TimeThis("Alarms1", Alarms1, loops); 1.506 + (void)TimeThis("Alarms2", Alarms2, loops); 1.507 + (void)TimeThis("Alarms3", Alarms3, loops); 1.508 + } 1.509 + return 0; 1.510 +} 1.511 + 1.512 +int main(int argc, char** argv) 1.513 +{ 1.514 + PR_Initialize(prmain, argc, argv, 0); 1.515 + PR_STDIO_INIT(); 1.516 + if (failed_already) return 1; 1.517 + else return 0; 1.518 + 1.519 +} /* main */ 1.520 + 1.521 + 1.522 +/* alarmtst.c */