Back to index

lightning-sunbird  0.9+nobinonly
alarm.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /***********************************************************************
00039 **  1996 - Netscape Communications Corporation
00040 **
00041 ** Name: alarmtst.c
00042 **
00043 ** Description: Test alarms
00044 **
00045 ** Modification History:
00046 ** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
00047 **              The debug mode will print all of the printfs associated with this test.
00048 **                    The regress mode will be the default mode. Since the regress tool limits
00049 **           the output to a one line status:PASS or FAIL,all of the printf statements
00050 **                    have been handled with an if (debug_mode) statement.
00051 ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
00052 **                   recognize the return code from tha main program.
00053 ***********************************************************************/
00054 
00055 /***********************************************************************
00056 ** Includes
00057 ***********************************************************************/
00058 
00059 #include "prlog.h"
00060 #include "prinit.h"
00061 #ifdef XP_MAC
00062 #include "pralarm.h"
00063 #else
00064 #include "obsolete/pralarm.h"
00065 #endif
00066 #include "prlock.h"
00067 #include "prlong.h"
00068 #include "prcvar.h"
00069 #include "prinrval.h"
00070 #include "prtime.h"
00071 
00072 /* Used to get the command line option */
00073 #include "plgetopt.h"
00074 #include <stdio.h>
00075 #include <stdlib.h>
00076 
00077 #if defined(XP_UNIX)
00078 #include <sys/time.h>
00079 #endif
00080 
00081 #ifdef XP_MAC
00082 #include "prlog.h"
00083 #define printf PR_LogPrint
00084 extern void SetupMacPrintfLog(char *logFile);
00085 #endif
00086 
00087 static PRIntn debug_mode;
00088 static PRIntn failed_already=0;
00089 static PRThreadScope thread_scope = PR_LOCAL_THREAD;
00090 
00091 typedef struct notifyData {
00092     PRLock *ml;
00093     PRCondVar *child;
00094     PRCondVar *parent;
00095     PRBool pending;
00096     PRUint32 counter;
00097 } NotifyData;
00098 
00099 static void Notifier(void *arg)
00100 {
00101     NotifyData *notifyData = (NotifyData*)arg;
00102     PR_Lock(notifyData->ml);
00103     while (notifyData->counter > 0)
00104     {
00105         while (!notifyData->pending)
00106             PR_WaitCondVar(notifyData->child, PR_INTERVAL_NO_TIMEOUT);
00107         notifyData->counter -= 1;
00108         notifyData->pending = PR_FALSE;
00109         PR_NotifyCondVar(notifyData->parent);
00110     }
00111     PR_Unlock(notifyData->ml);
00112 }  /* Notifier */
00113 /***********************************************************************
00114 ** PRIVATE FUNCTION:    ConditionNotify
00115 ** DESCRIPTION:
00116 ** 
00117 ** INPUTS:      loops
00118 ** OUTPUTS:     None
00119 ** RETURN:      overhead
00120 ** SIDE EFFECTS:
00121 **      
00122 ** RESTRICTIONS:
00123 **      None
00124 ** MEMORY:      NA
00125 ** ALGORITHM:
00126 **      
00127 ***********************************************************************/
00128 
00129 
00130 static PRIntervalTime ConditionNotify(PRUint32 loops)
00131 {
00132     PRThread *thread;
00133     NotifyData notifyData;
00134     PRIntervalTime timein, overhead;
00135     
00136     timein = PR_IntervalNow();
00137 
00138     notifyData.counter = loops;
00139     notifyData.ml = PR_NewLock();
00140     notifyData.child = PR_NewCondVar(notifyData.ml);
00141     notifyData.parent = PR_NewCondVar(notifyData.ml);
00142     thread = PR_CreateThread(
00143         PR_USER_THREAD, Notifier, &notifyData,
00144         PR_GetThreadPriority(PR_GetCurrentThread()),
00145         thread_scope, PR_JOINABLE_THREAD, 0);
00146 
00147     overhead = PR_IntervalNow() - timein;  /* elapsed so far */
00148 
00149     PR_Lock(notifyData.ml);
00150     while (notifyData.counter > 0)
00151     {
00152         notifyData.pending = PR_TRUE;
00153         PR_NotifyCondVar(notifyData.child);
00154         while (notifyData.pending)
00155             PR_WaitCondVar(notifyData.parent, PR_INTERVAL_NO_TIMEOUT);
00156     }
00157     PR_Unlock(notifyData.ml);
00158 
00159     timein = PR_IntervalNow();
00160 
00161     (void)PR_JoinThread(thread);
00162     PR_DestroyCondVar(notifyData.child);
00163     PR_DestroyCondVar(notifyData.parent);
00164     PR_DestroyLock(notifyData.ml);
00165     
00166     overhead += (PR_IntervalNow() - timein);  /* more overhead */
00167 
00168     return overhead;
00169 }  /* ConditionNotify */
00170 
00171 static PRIntervalTime ConditionTimeout(PRUint32 loops)
00172 {
00173     PRUintn count;
00174     PRIntervalTime overhead, timein = PR_IntervalNow();
00175 
00176     PRLock *ml = PR_NewLock();
00177     PRCondVar *cv = PR_NewCondVar(ml);
00178     PRIntervalTime interval = PR_MillisecondsToInterval(50);
00179 
00180     overhead = PR_IntervalNow() - timein;
00181 
00182     PR_Lock(ml);
00183     for (count = 0; count < loops; ++count)
00184     {
00185         overhead += interval;
00186         PR_ASSERT(PR_WaitCondVar(cv, interval) == PR_SUCCESS);
00187     }
00188     PR_Unlock(ml);
00189 
00190     timein = PR_IntervalNow();
00191     PR_DestroyCondVar(cv);
00192     PR_DestroyLock(ml);
00193     overhead += (PR_IntervalNow() - timein);
00194 
00195     return overhead;
00196 }  /* ConditionTimeout */
00197 
00198 typedef struct AlarmData {
00199     PRLock *ml;
00200     PRCondVar *cv;
00201     PRUint32 rate, late, times;
00202     PRIntervalTime duration, timein, period;
00203 } AlarmData;
00204 
00205 static PRBool AlarmFn1(PRAlarmID *id, void *clientData, PRUint32 late)
00206 {
00207     PRStatus rv = PR_SUCCESS;
00208     PRBool keepGoing, resetAlarm;
00209     PRIntervalTime interval, now = PR_IntervalNow();
00210     AlarmData *ad = (AlarmData*)clientData;
00211 
00212     PR_Lock(ad->ml);
00213     ad->late += late;
00214     ad->times += 1;
00215     keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ?
00216         PR_TRUE : PR_FALSE;
00217     if (!keepGoing)
00218         rv = PR_NotifyCondVar(ad->cv);
00219     resetAlarm = ((ad->times % 31) == 0) ? PR_TRUE : PR_FALSE;
00220                                          
00221     interval = (ad->period + ad->rate - 1) / ad->rate;
00222     if (!late && (interval > 10))
00223     {
00224         interval &= (now & 0x03) + 1;
00225         PR_WaitCondVar(ad->cv, interval);
00226     }
00227           
00228     PR_Unlock(ad->ml);
00229 
00230     if (rv != PR_SUCCESS)
00231     {
00232               if (!debug_mode) failed_already=1;
00233               else
00234                printf("AlarmFn: notify status: FAIL\n");
00235               
00236        }
00237 
00238     if (resetAlarm)
00239     {   
00240         ad->rate += 3;
00241         ad->late = ad->times = 0;
00242         if (PR_ResetAlarm(id, ad->period, ad->rate) != PR_SUCCESS)
00243         {
00244                      if (!debug_mode)
00245                             failed_already=1;
00246                      else          
00247                             printf("AlarmFn: Resetting alarm status: FAIL\n");
00248 
00249             keepGoing = PR_FALSE;
00250         }
00251 
00252     }
00253 
00254     return keepGoing;
00255 }  /* AlarmFn1 */
00256 
00257 static PRIntervalTime Alarms1(PRUint32 loops)
00258 {
00259     PRAlarm *alarm;
00260     AlarmData ad;
00261     PRIntervalTime overhead, timein = PR_IntervalNow();
00262     PRIntervalTime duration = PR_SecondsToInterval(3);
00263 
00264     PRLock *ml = PR_NewLock();
00265     PRCondVar *cv = PR_NewCondVar(ml);
00266 
00267     ad.ml = ml;
00268     ad.cv = cv;
00269     ad.rate = 1;
00270     ad.times = loops;
00271     ad.late = ad.times = 0;
00272     ad.duration = duration;
00273     ad.timein = PR_IntervalNow();
00274     ad.period = PR_SecondsToInterval(1);
00275 
00276     alarm = PR_CreateAlarm();
00277 
00278     (void)PR_SetAlarm(
00279         alarm, ad.period, ad.rate, AlarmFn1, &ad);
00280         
00281     overhead = PR_IntervalNow() - timein;
00282 
00283     PR_Lock(ml);
00284     while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration)
00285         PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
00286     PR_Unlock(ml);
00287 
00288     timein = PR_IntervalNow();
00289     (void)PR_DestroyAlarm(alarm);
00290     PR_DestroyCondVar(cv);
00291     PR_DestroyLock(ml);
00292     overhead += (PR_IntervalNow() - timein);
00293     
00294     return duration + overhead;
00295 }  /* Alarms1 */
00296 
00297 static PRBool AlarmFn2(PRAlarmID *id, void *clientData, PRUint32 late)
00298 {
00299 #if defined(XP_MAC)
00300 #pragma unused (id)
00301 #endif
00302 
00303     PRBool keepGoing;
00304     PRStatus rv = PR_SUCCESS;
00305     AlarmData *ad = (AlarmData*)clientData;
00306     PRIntervalTime interval, now = PR_IntervalNow();
00307 
00308     PR_Lock(ad->ml);
00309     ad->times += 1;
00310     keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ?
00311         PR_TRUE : PR_FALSE;
00312     interval = (ad->period + ad->rate - 1) / ad->rate;
00313 
00314     if (!late && (interval > 10))
00315     {
00316         interval &= (now & 0x03) + 1;
00317         PR_WaitCondVar(ad->cv, interval);
00318     }
00319 
00320     if (!keepGoing) rv = PR_NotifyCondVar(ad->cv);
00321 
00322     PR_Unlock(ad->ml);
00323 
00324 
00325     if (rv != PR_SUCCESS)
00326               failed_already=1;;
00327 
00328     return keepGoing;
00329 }  /* AlarmFn2 */
00330 
00331 static PRIntervalTime Alarms2(PRUint32 loops)
00332 {
00333     PRStatus rv;
00334     PRAlarm *alarm;
00335     PRIntervalTime overhead, timein = PR_IntervalNow();
00336     AlarmData ad;
00337     PRIntervalTime duration = PR_SecondsToInterval(30);
00338 
00339     PRLock *ml = PR_NewLock();
00340     PRCondVar *cv = PR_NewCondVar(ml);
00341 
00342     ad.ml = ml;
00343     ad.cv = cv;
00344     ad.rate = 1;
00345     ad.times = loops;
00346     ad.late = ad.times = 0;
00347     ad.duration = duration;
00348     ad.timein = PR_IntervalNow();
00349     ad.period = PR_SecondsToInterval(1);
00350 
00351     alarm = PR_CreateAlarm();
00352 
00353     (void)PR_SetAlarm(
00354         alarm, ad.period, ad.rate, AlarmFn2, &ad);
00355         
00356     overhead = PR_IntervalNow() - timein;
00357 
00358     PR_Lock(ml);
00359     while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration)
00360         PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
00361     PR_Unlock(ml);
00362     
00363     timein = PR_IntervalNow();
00364 
00365     rv = PR_DestroyAlarm(alarm);
00366     if (rv != PR_SUCCESS)
00367     {
00368               if (!debug_mode)
00369                      failed_already=1;
00370               else   
00371                      printf("***Destroying alarm status: FAIL\n");
00372     }
00373               
00374 
00375     PR_DestroyCondVar(cv);
00376     PR_DestroyLock(ml);
00377     
00378     overhead += (PR_IntervalNow() - timein);
00379     
00380     return duration + overhead;
00381 }  /* Alarms2 */
00382 
00383 static PRIntervalTime Alarms3(PRUint32 loops)
00384 {
00385     PRIntn i;
00386     PRStatus rv;
00387     PRAlarm *alarm;
00388     AlarmData ad[3];
00389     PRIntervalTime duration = PR_SecondsToInterval(30);
00390     PRIntervalTime overhead, timein = PR_IntervalNow();
00391 
00392     PRLock *ml = PR_NewLock();
00393     PRCondVar *cv = PR_NewCondVar(ml);
00394 
00395     for (i = 0; i < 3; ++i)
00396     {
00397         ad[i].ml = ml;
00398         ad[i].cv = cv;
00399         ad[i].rate = 1;
00400         ad[i].times = loops;
00401         ad[i].duration = duration;
00402         ad[i].late = ad[i].times = 0;
00403         ad[i].timein = PR_IntervalNow();
00404         ad[i].period = PR_SecondsToInterval(1);
00405 
00406         /* more loops, faster rate => same elapsed time */
00407         ad[i].times = (i + 1) * loops;
00408         ad[i].rate = (i + 1) * 10;
00409     }
00410 
00411     alarm = PR_CreateAlarm();
00412 
00413     for (i = 0; i < 3; ++i)
00414     {
00415         (void)PR_SetAlarm(
00416             alarm, ad[i].period, ad[i].rate,
00417             AlarmFn2, &ad[i]);
00418     }
00419         
00420     overhead = PR_IntervalNow() - timein;
00421 
00422     PR_Lock(ml);
00423     for (i = 0; i < 3; ++i)
00424     {
00425         while ((PRIntervalTime)(PR_IntervalNow() - ad[i].timein) < duration)
00426             PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
00427     }
00428     PR_Unlock(ml);
00429 
00430     timein = PR_IntervalNow();
00431 
00432        if (debug_mode)
00433        printf
00434         ("Alarms3 finished at %u, %u, %u\n",
00435         ad[0].timein, ad[1].timein, ad[2].timein);
00436     
00437     rv = PR_DestroyAlarm(alarm);
00438     if (rv != PR_SUCCESS)
00439     {
00440               if (!debug_mode)            
00441                      failed_already=1;
00442               else   
00443                  printf("***Destroying alarm status: FAIL\n");
00444        }
00445     PR_DestroyCondVar(cv);
00446     PR_DestroyLock(ml);
00447     
00448     overhead += (duration / 3);
00449     overhead += (PR_IntervalNow() - timein);
00450 
00451     return overhead;
00452 }  /* Alarms3 */
00453 
00454 static PRUint32 TimeThis(
00455     const char *msg, PRUint32 (*func)(PRUint32 loops), PRUint32 loops)
00456 {
00457     PRUint32 overhead, usecs;
00458     PRIntervalTime predicted, timein, timeout, ticks;
00459 
00460  if (debug_mode)
00461     printf("Testing %s ...", msg);
00462 
00463     timein = PR_IntervalNow();
00464     predicted = func(loops);
00465     timeout = PR_IntervalNow();
00466 
00467   if (debug_mode)
00468     printf(" done\n");
00469 
00470     ticks = timeout - timein;
00471     usecs = PR_IntervalToMicroseconds(ticks);
00472     overhead = PR_IntervalToMicroseconds(predicted);
00473 
00474     if(ticks < predicted)
00475     {
00476               if (debug_mode) {
00477         printf("\tFinished in negative time\n");
00478         printf("\tpredicted overhead was %d usecs\n", overhead);
00479         printf("\ttest completed in %d usecs\n\n", usecs);
00480               }
00481     }
00482     else
00483     {
00484        if (debug_mode)             
00485         printf(
00486             "\ttotal: %d usecs\n\toverhead: %d usecs\n\tcost: %6.3f usecs\n\n",
00487             usecs, overhead, ((double)(usecs - overhead) / (double)loops));
00488     }
00489 
00490     return overhead;
00491 }  /* TimeThis */
00492 
00493 int prmain(int argc, char** argv)
00494 {
00495     PRUint32 cpu, cpus = 0, loops = 0;
00496 
00497        /* The command line argument: -d is used to determine if the test is being run
00498        in debug mode. The regress tool requires only one line output:PASS or FAIL.
00499        All of the printfs associated with this test has been handled with a if (debug_mode)
00500        test.
00501        Usage: test_name [-d]
00502        */
00503        PLOptStatus os;
00504        PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:c:");
00505        while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
00506     {
00507               if (PL_OPT_BAD == os) continue;
00508         switch (opt->option)
00509         {
00510         case 'G':  /* GLOBAL threads */
00511                      thread_scope = PR_GLOBAL_THREAD;
00512             break;
00513         case 'd':  /* debug mode */
00514                      debug_mode = 1;
00515             break;
00516         case 'l':  /* loop count */
00517                      loops = atoi(opt->value);
00518             break;
00519         case 'c':  /* concurrency limit */
00520                      cpus = atoi(opt->value);
00521             break;
00522          default:
00523             break;
00524         }
00525     }
00526        PL_DestroyOptState(opt);
00527 
00528 
00529     if (cpus == 0) cpus = 1;
00530     if (loops == 0) loops = 4;
00531 
00532        if (debug_mode)
00533               printf("Alarm: Using %d loops\n", loops);
00534 
00535        if (debug_mode)             
00536         printf("Alarm: Using %d cpu(s)\n", cpus);
00537 #ifdef XP_MAC
00538        SetupMacPrintfLog("alarm.log");
00539        debug_mode = 1;
00540 #endif
00541 
00542     for (cpu = 1; cpu <= cpus; ++cpu)
00543     {
00544     if (debug_mode)
00545         printf("\nAlarm: Using %d CPU(s)\n", cpu);
00546 
00547        PR_SetConcurrency(cpu);
00548         
00549         /* some basic time test */
00550         (void)TimeThis("ConditionNotify", ConditionNotify, loops);
00551         (void)TimeThis("ConditionTimeout", ConditionTimeout, loops);
00552         (void)TimeThis("Alarms1", Alarms1, loops);
00553         (void)TimeThis("Alarms2", Alarms2, loops);
00554         (void)TimeThis("Alarms3", Alarms3, loops);
00555     }
00556     return 0;
00557 }
00558 
00559 int main(int argc, char** argv)
00560 {
00561      PR_Initialize(prmain, argc, argv, 0);
00562      PR_STDIO_INIT();
00563         if (failed_already) return 1;
00564         else return 0;
00565 
00566 }  /* main */
00567 
00568 
00569 /* alarmtst.c */