nsprpub/pr/tests/alarm.c

changeset 0
6474c204b198
     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, &notifyData,
   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 */

mercurial