home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / tests / lock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  14.5 KB  |  492 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20. ** File:        lock.c
  21. ** Purpose:     test basic locking functions
  22. **
  23. ** Modification History:
  24. ** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
  25. **             The debug mode will print all of the printfs associated with this test.
  26. **             The regress mode will be the default mode. Since the regress tool limits
  27. **           the output to a one line status:PASS or FAIL,all of the printf statements
  28. **             have been handled with an if (debug_mode) statement.
  29. ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
  30. **            recognize the return code from tha main program.
  31. **
  32. ** 11-Aug-97 LarryH. Win16 port of NSPR.
  33. **           - Added "PASS", "FAIL" messages on completion.
  34. **           - Change stack variables to static scope variables
  35. **             because of shadow-stack use by Win16
  36. **           - Added PR_CALLBACK attribute to functions called by NSPR
  37. **           - Added command line arguments:
  38. **             - l <num> to control the number of loops
  39. **             - c <num> to control the number of CPUs.
  40. **             (was positional argv).
  41. ** 
  42. **
  43. ***********************************************************************/
  44.  
  45. /***********************************************************************
  46. ** Includes
  47. ***********************************************************************/
  48. /* Used to get the command line option */
  49. #include "plgetopt.h"
  50.  
  51. #include "prcmon.h"
  52. #include "prinit.h"
  53. #include "prinrval.h"
  54. #include "prlock.h"
  55. #include "prlog.h"
  56. #include "prmon.h"
  57. #include "prmem.h"
  58. #include "prthread.h"
  59. #include "prtypes.h"
  60.  
  61. #include "plstr.h"
  62.  
  63. #include <stdio.h>
  64. #include <stdlib.h>
  65.  
  66. #if defined(XP_UNIX)
  67. #include <string.h>
  68. #endif
  69.  
  70. #ifdef XP_MAC
  71. #include "prlog.h"
  72. #define printf PR_LogPrint
  73. extern void SetupMacPrintfLog(char *logFile);
  74. #endif
  75. PRIntn failed_already=0;
  76. PRIntn debug_mode;
  77.  
  78. const static PRIntervalTime contention_interval = 50;
  79.  
  80. typedef struct LockContentious_s {
  81.     PRLock *ml;
  82.     PRUint32 loops;
  83.     PRIntervalTime overhead;
  84.     PRIntervalTime interval;
  85. } LockContentious_t;
  86.  
  87. typedef struct MonitorContentious_s {
  88.     PRMonitor *ml;
  89.     PRUint32 loops;
  90.     PRIntervalTime overhead;
  91.     PRIntervalTime interval;
  92. } MonitorContentious_t;
  93.  
  94.  
  95. static PRIntervalTime Sleeper(PRUint32 loops)
  96. {
  97.     PRIntervalTime predicted = 0;
  98.     while (loops-- > 0)
  99.     {
  100.         predicted += contention_interval;
  101.         (void)PR_Sleep(contention_interval);
  102.     }
  103.     return predicted;
  104. }  /* Sleeper */
  105.  
  106. /*
  107. ** BASIC LOCKS
  108. */
  109. static PRIntervalTime MakeLock(PRUint32 loops)
  110. {
  111.     PRLock *ml = NULL;
  112.     while (loops-- > 0)
  113.     {
  114.         ml = PR_NewLock();
  115.         PR_DestroyLock(ml);
  116.         ml = NULL;
  117.     }
  118.     return 0;
  119. }  /* MakeLock */
  120.  
  121. static PRIntervalTime NonContentiousLock(PRUint32 loops)
  122. {
  123.     PRLock *ml = NULL;
  124.     ml = PR_NewLock();
  125.     while (loops-- > 0)
  126.     {
  127.         PR_Lock(ml);
  128.         PR_Unlock(ml);
  129.     }
  130.     PR_DestroyLock(ml);
  131.     return 0;
  132. }  /* NonContentiousLock */
  133.  
  134. static void PR_CALLBACK LockContender(void *arg)
  135. {
  136.     LockContentious_t *contention = (LockContentious_t*)arg;
  137.     while (contention->loops-- > 0)
  138.     {
  139.         PR_Lock(contention->ml);
  140.         contention->overhead += contention->interval;
  141.         PR_Sleep(contention->interval);
  142.         PR_Unlock(contention->ml);
  143.     }
  144. }  /* LockContender */
  145.  
  146. static PRIntervalTime ContentiousLock(PRUint32 loops)
  147. {
  148.     PRStatus status;
  149.     PRThread *thread = NULL;
  150.     LockContentious_t * contention;
  151.     PRIntervalTime rv, overhead, timein = PR_IntervalNow();
  152.  
  153.     contention = (LockContentious_t *) PR_Calloc( 1, sizeof(LockContentious_t));
  154.     contention->loops = loops;
  155.     contention->overhead = 0;
  156.     contention->ml = PR_NewLock();
  157.     contention->interval = contention_interval;
  158.     thread = PR_CreateThread(
  159.         PR_USER_THREAD, LockContender, contention,
  160.         PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
  161.     PR_ASSERT(thread != NULL);
  162.  
  163.     overhead = PR_IntervalNow() - timein;
  164.  
  165.     while (contention->loops > 0)
  166.     {
  167.         PR_Lock(contention->ml);
  168.         contention->overhead += contention->interval;
  169.         PR_Sleep(contention->interval);
  170.         PR_Unlock(contention->ml);
  171.     }
  172.  
  173.     timein = PR_IntervalNow();
  174.     status = PR_JoinThread(thread);
  175.     PR_DestroyLock(contention->ml);
  176.     overhead += (PR_IntervalNow() - timein);
  177.     rv = overhead + contention->overhead;
  178.     PR_Free(contention);
  179.     return rv;
  180. }  /* ContentiousLock */
  181.  
  182. /*
  183. ** MONITORS
  184. */
  185. static PRIntervalTime MakeMonitor(PRUint32 loops)
  186. {
  187.     PRMonitor *ml = NULL;
  188.     while (loops-- > 0)
  189.     {
  190.         ml = PR_NewMonitor();
  191.         PR_DestroyMonitor(ml);
  192.         ml = NULL;
  193.     }
  194.     return 0;
  195. }  /* MakeMonitor */
  196.  
  197. static PRIntervalTime NonContentiousMonitor(PRUint32 loops)
  198. {
  199.     PRMonitor *ml = NULL;
  200.     ml = PR_NewMonitor();
  201.     while (loops-- > 0)
  202.     {
  203.         PR_EnterMonitor(ml);
  204.         PR_ExitMonitor(ml);
  205.     }
  206.     PR_DestroyMonitor(ml);
  207.     return 0;
  208. }  /* NonContentiousMonitor */
  209.  
  210. static void PR_CALLBACK TryEntry(void *arg)
  211. {
  212.     PRMonitor *ml = (PRMonitor*)arg;
  213.     if (debug_mode) printf("Reentrant thread created\n");
  214.     PR_EnterMonitor(ml);
  215.     if (debug_mode) printf("Reentrant thread acquired monitor\n");
  216.     PR_ExitMonitor(ml);
  217.     if (debug_mode) printf("Reentrant thread released monitor\n");
  218. }  /* TryEntry */
  219.  
  220. static PRIntervalTime ReentrantMonitor(PRUint32 loops)
  221. {
  222.      PRStatus status;
  223.     PRThread *thread;
  224.     PRMonitor *ml = PR_NewMonitor();
  225.     if (debug_mode) printf("\nMonitor created for reentrant test\n");
  226.  
  227.     PR_EnterMonitor(ml);
  228.     PR_EnterMonitor(ml);
  229.     if (debug_mode) printf("Monitor acquired twice\n");
  230.  
  231.     thread = PR_CreateThread(
  232.         PR_USER_THREAD, TryEntry, ml,
  233.         PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
  234.     PR_ASSERT(thread != NULL);
  235.     PR_Sleep(PR_SecondsToInterval(1));
  236.  
  237.     PR_ExitMonitor(ml);
  238.     if (debug_mode) printf("Monitor released first time\n");
  239.  
  240.     PR_ExitMonitor(ml);
  241.     if (debug_mode) printf("Monitor released second time\n");
  242.  
  243.     status = PR_JoinThread(thread);
  244.     if (debug_mode) printf(
  245.         "Reentrant thread joined %s\n",
  246.         (status == PR_SUCCESS) ? "successfully" : "in error");
  247.  
  248.     PR_DestroyMonitor(ml);
  249.     return 0;
  250. }  /* ReentrantMonitor */
  251.  
  252. static void PR_CALLBACK MonitorContender(void *arg)
  253. {
  254.     MonitorContentious_t *contention = (MonitorContentious_t*)arg;
  255.     while (contention->loops-- > 0)
  256.     {
  257.         PR_EnterMonitor(contention->ml);
  258.         contention->overhead += contention->interval;
  259.         PR_Sleep(contention->interval);
  260.         PR_ExitMonitor(contention->ml);
  261.     }
  262. }  /* MonitorContender */
  263.  
  264. static PRUint32 ContentiousMonitor(PRUint32 loops)
  265. {
  266.     PRStatus status;
  267.     PRThread *thread = NULL;
  268.     MonitorContentious_t * contention;
  269.     PRIntervalTime rv, overhead, timein = PR_IntervalNow();
  270.  
  271.     contention = (MonitorContentious_t *) PR_Calloc(1, sizeof(MonitorContentious_t));
  272.     contention->loops = loops;
  273.     contention->overhead = 0;
  274.     contention->ml = PR_NewMonitor();
  275.     contention->interval = contention_interval;
  276.     thread = PR_CreateThread(
  277.         PR_USER_THREAD, MonitorContender, contention,
  278.         PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
  279.     PR_ASSERT(thread != NULL);
  280.  
  281.     overhead = PR_IntervalNow() - timein;
  282.  
  283.     while (contention->loops > 0)
  284.     {
  285.         PR_EnterMonitor(contention->ml);
  286.         contention->overhead += contention->interval;
  287.         PR_Sleep(contention->interval);
  288.         PR_ExitMonitor(contention->ml);
  289.     }
  290.  
  291.     timein = PR_IntervalNow();
  292.     status = PR_JoinThread(thread);
  293.     PR_DestroyMonitor(contention->ml);
  294.     overhead += (PR_IntervalNow() - timein);
  295.     rv = overhead + contention->overhead;
  296.     PR_Free(contention);
  297.     return rv;
  298. }  /* ContentiousMonitor */
  299.  
  300. /*
  301. ** CACHED MONITORS
  302. */
  303. static PRIntervalTime NonContentiousCMonitor(PRUint32 loops)
  304. {
  305.     MonitorContentious_t contention;
  306.     while (loops-- > 0)
  307.     {
  308.         PR_CEnterMonitor(&contention);
  309.         PR_CExitMonitor(&contention);
  310.     }
  311.     return 0;
  312. }  /* NonContentiousCMonitor */
  313.  
  314. static void PR_CALLBACK Contender(void *arg)
  315. {
  316.     MonitorContentious_t *contention = (MonitorContentious_t*)arg;
  317.     while (contention->loops-- > 0)
  318.     {
  319.         PR_CEnterMonitor(contention);
  320.         contention->overhead += contention->interval;
  321.         PR_Sleep(contention->interval);
  322.         PR_CExitMonitor(contention);
  323.     }
  324. }  /* Contender */
  325.  
  326. static PRIntervalTime ContentiousCMonitor(PRUint32 loops)
  327. {
  328.     PRStatus status;
  329.     PRThread *thread = NULL;
  330.     MonitorContentious_t * contention;
  331.     PRIntervalTime overhead, timein = PR_IntervalNow();
  332.  
  333.     contention = (MonitorContentious_t *) PR_Calloc(1, sizeof(MonitorContentious_t));
  334.     contention->ml = NULL;
  335.     contention->overhead = 0;
  336.     contention->loops = loops;
  337.     contention->interval = contention_interval;
  338.     thread = PR_CreateThread(
  339.         PR_USER_THREAD, Contender, contention,
  340.         PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
  341.     PR_ASSERT(thread != NULL);
  342.  
  343.     overhead = PR_IntervalNow() - timein;
  344.  
  345.     while (contention->loops > 0)
  346.     {
  347.         PR_CEnterMonitor(contention);
  348.         contention->overhead += contention->interval;
  349.         PR_Sleep(contention->interval);
  350.         PR_CExitMonitor(contention);
  351.     }
  352.  
  353.     timein = PR_IntervalNow();
  354.     status = PR_JoinThread(thread);
  355.     overhead += (PR_IntervalNow() - timein);
  356.     return overhead + contention->overhead;
  357. }  /* ContentiousCMonitor */
  358.  
  359. static PRIntervalTime Test(
  360.     const char* msg, PRUint32 (*test)(PRUint32 loops),
  361.     PRUint32 loops, PRIntervalTime overhead)
  362.     /*
  363.      * overhead - overhead not measured by the test.
  364.      * duration - wall clock time it took to perform test.
  365.      * predicted - extra time test says should not be counted 
  366.      *
  367.      * Time accountable to the test is duration - overhead - predicted
  368.      * All times are Intervals and accumulated for all iterations.
  369.      */
  370.     PRFloat64 elapsed;
  371.     PRIntervalTime accountable, duration;    
  372.     PRUintn spaces = PL_strlen(msg);
  373.     PRIntervalTime timeout, timein = PR_IntervalNow();
  374.     PRIntervalTime predicted = test(loops);
  375.     timeout = PR_IntervalNow();
  376.     duration = timeout - timein;
  377.  
  378.     if (debug_mode)
  379.     {
  380.         accountable = duration - predicted;
  381.         accountable -= overhead;
  382.         elapsed = (PRFloat64)PR_IntervalToMicroseconds(accountable);
  383.         printf("%s:", msg);
  384.         while (spaces++ < 50) printf(" ");
  385.         if ((PRInt32)accountable < 0)
  386.             printf("*****.** usecs/iteration\n");
  387.         else
  388.             printf("%8.2f usecs/iteration\n", elapsed/loops);
  389.     }
  390.     return duration;
  391. }  /* Test */
  392.  
  393. int main(int argc,  char **argv)
  394. {
  395.     PRBool rv = PR_TRUE;
  396.     PRIntervalTime duration;
  397.     PRUint32 cpu, cpus = 2, loops = 100;
  398.  
  399.     
  400.     PR_STDIO_INIT();
  401.     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
  402.     {
  403.         /* The command line argument: -d is used to determine if the test is being run
  404.         in debug mode. The regress tool requires only one line output:PASS or FAIL.
  405.         All of the printfs associated with this test has been handled with a if (debug_mode)
  406.         test.
  407.         Command line argument -l <num> sets the number of loops.
  408.         Command line argument -c <num> sets the number of cpus.
  409.         Usage: lock [-d] [-l <num>] [-c <num>]
  410.         */
  411.         PLOptStatus os;
  412.         PLOptState *opt = PL_CreateOptState(argc, argv, "dl:c:");
  413.         while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  414.         {
  415.             if (PL_OPT_BAD == os) continue;
  416.             switch (opt->option)
  417.             {
  418.             case 'd':  /* debug mode */
  419.                 debug_mode = 1;
  420.                 break;
  421.             case 'l':  /* number of loops */
  422.                 loops = atoi(opt->value);
  423.                 break;
  424.             case 'c':  /* number of cpus */
  425.                 cpus = atoi(opt->value);
  426.                 break;
  427.              default:
  428.                 break;
  429.             }
  430.         }
  431.         PL_DestroyOptState(opt);
  432.     }
  433.  
  434.  /* main test */
  435.     PR_SetConcurrency(8);
  436.  
  437. #ifdef XP_MAC
  438.     SetupMacPrintfLog("lock.log");
  439.     debug_mode = 1;
  440. #endif
  441.  
  442.     if (loops == 0) loops = 100;
  443.     if (debug_mode) printf("Lock: Using %d loops\n", loops);
  444.  
  445.     if (cpus == 0) cpus = 2;
  446.     if (debug_mode) printf("Lock: Using %d cpu(s)\n", cpus);
  447.  
  448.     (void)Sleeper(10);  /* try filling in the caches */
  449.  
  450.     for (cpu = 1; cpu <= cpus; ++cpu)
  451.     {
  452.         if (debug_mode) printf("\nLock: Using %d CPU(s)\n", cpu);
  453.         PR_SetConcurrency(cpu);
  454.  
  455.         duration = Test("Overhead of PR_Sleep", Sleeper, loops, 0);
  456.         duration = 0;
  457.  
  458.         (void)Test("Lock creation/deletion", MakeLock, loops, 0);
  459.         (void)Test("Lock non-contentious locking/unlocking", NonContentiousLock, loops, 0);
  460.         (void)Test("Lock contentious locking/unlocking", ContentiousLock, loops, duration);
  461.         (void)Test("Monitor creation/deletion", MakeMonitor, loops, 0);
  462.         (void)Test("Monitor non-contentious locking/unlocking", NonContentiousMonitor, loops, 0);
  463.         (void)Test("Monitor contentious locking/unlocking", ContentiousMonitor, loops, duration);
  464.  
  465.         (void)Test("Cached monitor non-contentious locking/unlocking", NonContentiousCMonitor, loops, 0);
  466.         (void)Test("Cached monitor contentious locking/unlocking", ContentiousCMonitor, loops, duration);
  467.  
  468.         (void)ReentrantMonitor(loops);
  469.     }
  470.  
  471.     if (debug_mode) printf("%s: test %s\n", "Lock(mutex) test", ((rv) ? "passed" : "failed"));
  472.     else {
  473.          if (!rv)
  474.              failed_already=1;
  475.     }
  476.  
  477.     if(failed_already)    
  478.     {
  479.         printf("FAIL\n"); 
  480.         return 1;
  481.     } 
  482.     else
  483.     {
  484.         printf("PASS\n"); 
  485.         return 0;
  486.     }
  487.  
  488. }  /* main */
  489.  
  490. /* testlock.c */
  491.