123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553 |
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- /***********************************************************************
- ** 1996 - Netscape Communications Corporation
- **
- ** Name: alarmtst.c
- **
- ** Description: Test alarms
- **
- ** Modification History:
- ** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
- ** The debug mode will print all of the printfs associated with this test.
- ** The regress mode will be the default mode. Since the regress tool limits
- ** the output to a one line status:PASS or FAIL,all of the printf statements
- ** have been handled with an if (debug_mode) statement.
- ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
- ** recognize the return code from tha main program.
- ***********************************************************************/
- /***********************************************************************
- ** Includes
- ***********************************************************************/
- #include "prlog.h"
- #include "prinit.h"
- #include "obsolete/pralarm.h"
- #include "prlock.h"
- #include "prlong.h"
- #include "prcvar.h"
- #include "prinrval.h"
- #include "prtime.h"
- /* Used to get the command line option */
- #include "plgetopt.h"
- #include <stdio.h>
- #include <stdlib.h>
- #if defined(XP_UNIX)
- #include <sys/time.h>
- #endif
- static PRIntn debug_mode;
- static PRIntn failed_already=0;
- static PRThreadScope thread_scope = PR_LOCAL_THREAD;
- typedef struct notifyData {
- PRLock *ml;
- PRCondVar *child;
- PRCondVar *parent;
- PRBool pending;
- PRUint32 counter;
- } NotifyData;
- static void Notifier(void *arg)
- {
- NotifyData *notifyData = (NotifyData*)arg;
- PR_Lock(notifyData->ml);
- while (notifyData->counter > 0)
- {
- while (!notifyData->pending) {
- PR_WaitCondVar(notifyData->child, PR_INTERVAL_NO_TIMEOUT);
- }
- notifyData->counter -= 1;
- notifyData->pending = PR_FALSE;
- PR_NotifyCondVar(notifyData->parent);
- }
- PR_Unlock(notifyData->ml);
- } /* Notifier */
- /***********************************************************************
- ** PRIVATE FUNCTION: ConditionNotify
- ** DESCRIPTION:
- **
- ** INPUTS: loops
- ** OUTPUTS: None
- ** RETURN: overhead
- ** SIDE EFFECTS:
- **
- ** RESTRICTIONS:
- ** None
- ** MEMORY: NA
- ** ALGORITHM:
- **
- ***********************************************************************/
- static PRIntervalTime ConditionNotify(PRUint32 loops)
- {
- PRThread *thread;
- NotifyData notifyData;
- PRIntervalTime timein, overhead;
- timein = PR_IntervalNow();
- notifyData.counter = loops;
- notifyData.ml = PR_NewLock();
- notifyData.child = PR_NewCondVar(notifyData.ml);
- notifyData.parent = PR_NewCondVar(notifyData.ml);
- thread = PR_CreateThread(
- PR_USER_THREAD, Notifier, ¬ifyData,
- PR_GetThreadPriority(PR_GetCurrentThread()),
- thread_scope, PR_JOINABLE_THREAD, 0);
- overhead = PR_IntervalNow() - timein; /* elapsed so far */
- PR_Lock(notifyData.ml);
- while (notifyData.counter > 0)
- {
- notifyData.pending = PR_TRUE;
- PR_NotifyCondVar(notifyData.child);
- while (notifyData.pending) {
- PR_WaitCondVar(notifyData.parent, PR_INTERVAL_NO_TIMEOUT);
- }
- }
- PR_Unlock(notifyData.ml);
- timein = PR_IntervalNow();
- (void)PR_JoinThread(thread);
- PR_DestroyCondVar(notifyData.child);
- PR_DestroyCondVar(notifyData.parent);
- PR_DestroyLock(notifyData.ml);
- overhead += (PR_IntervalNow() - timein); /* more overhead */
- return overhead;
- } /* ConditionNotify */
- static PRIntervalTime ConditionTimeout(PRUint32 loops)
- {
- PRUintn count;
- PRIntervalTime overhead, timein = PR_IntervalNow();
- PRLock *ml = PR_NewLock();
- PRCondVar *cv = PR_NewCondVar(ml);
- PRIntervalTime interval = PR_MillisecondsToInterval(50);
- overhead = PR_IntervalNow() - timein;
- PR_Lock(ml);
- for (count = 0; count < loops; ++count)
- {
- overhead += interval;
- PR_ASSERT(PR_WaitCondVar(cv, interval) == PR_SUCCESS);
- }
- PR_Unlock(ml);
- timein = PR_IntervalNow();
- PR_DestroyCondVar(cv);
- PR_DestroyLock(ml);
- overhead += (PR_IntervalNow() - timein);
- return overhead;
- } /* ConditionTimeout */
- typedef struct AlarmData {
- PRLock *ml;
- PRCondVar *cv;
- PRUint32 rate, late, times;
- PRIntervalTime duration, timein, period;
- } AlarmData;
- static PRBool AlarmFn1(PRAlarmID *id, void *clientData, PRUint32 late)
- {
- PRStatus rv = PR_SUCCESS;
- PRBool keepGoing, resetAlarm;
- PRIntervalTime interval, now = PR_IntervalNow();
- AlarmData *ad = (AlarmData*)clientData;
- PR_Lock(ad->ml);
- ad->late += late;
- ad->times += 1;
- keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ?
- PR_TRUE : PR_FALSE;
- if (!keepGoing) {
- rv = PR_NotifyCondVar(ad->cv);
- }
- resetAlarm = ((ad->times % 31) == 0) ? PR_TRUE : PR_FALSE;
- interval = (ad->period + ad->rate - 1) / ad->rate;
- if (!late && (interval > 10))
- {
- interval &= (now & 0x03) + 1;
- PR_WaitCondVar(ad->cv, interval);
- }
- PR_Unlock(ad->ml);
- if (rv != PR_SUCCESS)
- {
- if (!debug_mode) {
- failed_already=1;
- }
- else {
- printf("AlarmFn: notify status: FAIL\n");
- }
- }
- if (resetAlarm)
- {
- ad->rate += 3;
- ad->late = ad->times = 0;
- if (PR_ResetAlarm(id, ad->period, ad->rate) != PR_SUCCESS)
- {
- if (!debug_mode) {
- failed_already=1;
- }
- else {
- printf("AlarmFn: Resetting alarm status: FAIL\n");
- }
- keepGoing = PR_FALSE;
- }
- }
- return keepGoing;
- } /* AlarmFn1 */
- static PRIntervalTime Alarms1(PRUint32 loops)
- {
- PRAlarm *alarm;
- AlarmData ad;
- PRIntervalTime overhead, timein = PR_IntervalNow();
- PRIntervalTime duration = PR_SecondsToInterval(3);
- PRLock *ml = PR_NewLock();
- PRCondVar *cv = PR_NewCondVar(ml);
- ad.ml = ml;
- ad.cv = cv;
- ad.rate = 1;
- ad.times = loops;
- ad.late = ad.times = 0;
- ad.duration = duration;
- ad.timein = PR_IntervalNow();
- ad.period = PR_SecondsToInterval(1);
- alarm = PR_CreateAlarm();
- (void)PR_SetAlarm(
- alarm, ad.period, ad.rate, AlarmFn1, &ad);
- overhead = PR_IntervalNow() - timein;
- PR_Lock(ml);
- while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration) {
- PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
- }
- PR_Unlock(ml);
- timein = PR_IntervalNow();
- (void)PR_DestroyAlarm(alarm);
- PR_DestroyCondVar(cv);
- PR_DestroyLock(ml);
- overhead += (PR_IntervalNow() - timein);
- return duration + overhead;
- } /* Alarms1 */
- static PRBool AlarmFn2(PRAlarmID *id, void *clientData, PRUint32 late)
- {
- PRBool keepGoing;
- PRStatus rv = PR_SUCCESS;
- AlarmData *ad = (AlarmData*)clientData;
- PRIntervalTime interval, now = PR_IntervalNow();
- PR_Lock(ad->ml);
- ad->times += 1;
- keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ?
- PR_TRUE : PR_FALSE;
- interval = (ad->period + ad->rate - 1) / ad->rate;
- if (!late && (interval > 10))
- {
- interval &= (now & 0x03) + 1;
- PR_WaitCondVar(ad->cv, interval);
- }
- if (!keepGoing) {
- rv = PR_NotifyCondVar(ad->cv);
- }
- PR_Unlock(ad->ml);
- if (rv != PR_SUCCESS) {
- failed_already=1;
- };
- return keepGoing;
- } /* AlarmFn2 */
- static PRIntervalTime Alarms2(PRUint32 loops)
- {
- PRStatus rv;
- PRAlarm *alarm;
- PRIntervalTime overhead, timein = PR_IntervalNow();
- AlarmData ad;
- PRIntervalTime duration = PR_SecondsToInterval(30);
- PRLock *ml = PR_NewLock();
- PRCondVar *cv = PR_NewCondVar(ml);
- ad.ml = ml;
- ad.cv = cv;
- ad.rate = 1;
- ad.times = loops;
- ad.late = ad.times = 0;
- ad.duration = duration;
- ad.timein = PR_IntervalNow();
- ad.period = PR_SecondsToInterval(1);
- alarm = PR_CreateAlarm();
- (void)PR_SetAlarm(
- alarm, ad.period, ad.rate, AlarmFn2, &ad);
- overhead = PR_IntervalNow() - timein;
- PR_Lock(ml);
- while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration) {
- PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
- }
- PR_Unlock(ml);
- timein = PR_IntervalNow();
- rv = PR_DestroyAlarm(alarm);
- if (rv != PR_SUCCESS)
- {
- if (!debug_mode) {
- failed_already=1;
- }
- else {
- printf("***Destroying alarm status: FAIL\n");
- }
- }
- PR_DestroyCondVar(cv);
- PR_DestroyLock(ml);
- overhead += (PR_IntervalNow() - timein);
- return duration + overhead;
- } /* Alarms2 */
- static PRIntervalTime Alarms3(PRUint32 loops)
- {
- PRIntn i;
- PRStatus rv;
- PRAlarm *alarm;
- AlarmData ad[3];
- PRIntervalTime duration = PR_SecondsToInterval(30);
- PRIntervalTime overhead, timein = PR_IntervalNow();
- PRLock *ml = PR_NewLock();
- PRCondVar *cv = PR_NewCondVar(ml);
- for (i = 0; i < 3; ++i)
- {
- ad[i].ml = ml;
- ad[i].cv = cv;
- ad[i].rate = 1;
- ad[i].times = loops;
- ad[i].duration = duration;
- ad[i].late = ad[i].times = 0;
- ad[i].timein = PR_IntervalNow();
- ad[i].period = PR_SecondsToInterval(1);
- /* more loops, faster rate => same elapsed time */
- ad[i].times = (i + 1) * loops;
- ad[i].rate = (i + 1) * 10;
- }
- alarm = PR_CreateAlarm();
- for (i = 0; i < 3; ++i)
- {
- (void)PR_SetAlarm(
- alarm, ad[i].period, ad[i].rate,
- AlarmFn2, &ad[i]);
- }
- overhead = PR_IntervalNow() - timein;
- PR_Lock(ml);
- for (i = 0; i < 3; ++i)
- {
- while ((PRIntervalTime)(PR_IntervalNow() - ad[i].timein) < duration) {
- PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
- }
- }
- PR_Unlock(ml);
- timein = PR_IntervalNow();
- if (debug_mode)
- printf
- ("Alarms3 finished at %u, %u, %u\n",
- ad[0].timein, ad[1].timein, ad[2].timein);
- rv = PR_DestroyAlarm(alarm);
- if (rv != PR_SUCCESS)
- {
- if (!debug_mode) {
- failed_already=1;
- }
- else {
- printf("***Destroying alarm status: FAIL\n");
- }
- }
- PR_DestroyCondVar(cv);
- PR_DestroyLock(ml);
- overhead += (duration / 3);
- overhead += (PR_IntervalNow() - timein);
- return overhead;
- } /* Alarms3 */
- static PRUint32 TimeThis(
- const char *msg, PRUint32 (*func)(PRUint32 loops), PRUint32 loops)
- {
- PRUint32 overhead, usecs;
- PRIntervalTime predicted, timein, timeout, ticks;
- if (debug_mode) {
- printf("Testing %s ...", msg);
- }
- timein = PR_IntervalNow();
- predicted = func(loops);
- timeout = PR_IntervalNow();
- if (debug_mode) {
- printf(" done\n");
- }
- ticks = timeout - timein;
- usecs = PR_IntervalToMicroseconds(ticks);
- overhead = PR_IntervalToMicroseconds(predicted);
- if(ticks < predicted)
- {
- if (debug_mode) {
- printf("\tFinished in negative time\n");
- printf("\tpredicted overhead was %d usecs\n", overhead);
- printf("\ttest completed in %d usecs\n\n", usecs);
- }
- }
- else
- {
- if (debug_mode)
- printf(
- "\ttotal: %d usecs\n\toverhead: %d usecs\n\tcost: %6.3f usecs\n\n",
- usecs, overhead, ((double)(usecs - overhead) / (double)loops));
- }
- return overhead;
- } /* TimeThis */
- int prmain(int argc, char** argv)
- {
- PRUint32 cpu, cpus = 0, loops = 0;
- /* The command line argument: -d is used to determine if the test is being run
- in debug mode. The regress tool requires only one line output:PASS or FAIL.
- All of the printfs associated with this test has been handled with a if (debug_mode)
- test.
- Usage: test_name [-d]
- */
- PLOptStatus os;
- PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:c:");
- while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
- {
- if (PL_OPT_BAD == os) {
- continue;
- }
- switch (opt->option)
- {
- case 'G': /* GLOBAL threads */
- thread_scope = PR_GLOBAL_THREAD;
- break;
- case 'd': /* debug mode */
- debug_mode = 1;
- break;
- case 'l': /* loop count */
- loops = atoi(opt->value);
- break;
- case 'c': /* concurrency limit */
- cpus = atoi(opt->value);
- break;
- default:
- break;
- }
- }
- PL_DestroyOptState(opt);
- if (cpus == 0) {
- cpus = 1;
- }
- if (loops == 0) {
- loops = 4;
- }
- if (debug_mode) {
- printf("Alarm: Using %d loops\n", loops);
- }
- if (debug_mode) {
- printf("Alarm: Using %d cpu(s)\n", cpus);
- }
- for (cpu = 1; cpu <= cpus; ++cpu)
- {
- if (debug_mode) {
- printf("\nAlarm: Using %d CPU(s)\n", cpu);
- }
- PR_SetConcurrency(cpu);
- /* some basic time test */
- (void)TimeThis("ConditionNotify", ConditionNotify, loops);
- (void)TimeThis("ConditionTimeout", ConditionTimeout, loops);
- (void)TimeThis("Alarms1", Alarms1, loops);
- (void)TimeThis("Alarms2", Alarms2, loops);
- (void)TimeThis("Alarms3", Alarms3, loops);
- }
- return 0;
- }
- int main(int argc, char** argv)
- {
- PR_Initialize(prmain, argc, argv, 0);
- PR_STDIO_INIT();
- if (failed_already) {
- return 1;
- }
- else {
- return 0;
- }
- } /* main */
- /* alarmtst.c */
|