home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / tests / perf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  11.8 KB  |  443 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. #include "nspr.h"
  20. #include "plgetopt.h"
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25.  
  26. int _debug_on = 0;
  27. #define DPRINTF(arg) if (_debug_on) printf arg
  28.  
  29. #ifdef XP_MAC
  30. #include "prlog.h"
  31. #include "prsem.h"
  32. #define printf PR_LogPrint
  33. extern void SetupMacPrintfLog(char *logFile);
  34. #else
  35. #include "obsolete/prsem.h"
  36. #endif
  37.  
  38. PRLock *lock;
  39. PRMonitor *mon;
  40. PRMonitor *mon2;
  41.  
  42. #define DEFAULT_COUNT    1000
  43.  
  44. PRInt32 count;
  45.  
  46. static void nop(int a, int b, int c)
  47. {
  48. }
  49.  
  50. static void LocalProcedureCall(void)
  51. {
  52.     PRInt32 i;
  53.  
  54.     for (i = 0; i < count; i++) {
  55.     nop(i, i, 5);
  56.     }
  57. }
  58.  
  59. static void DLLProcedureCall(void)
  60. {
  61.     PRInt32 i;
  62.     PRThreadState state;
  63.     PRThread *self = PR_CurrentThread();
  64.  
  65.     for (i = 0; i < count; i++) {
  66.         state = PR_GetThreadState(self);
  67.     }
  68. }
  69.  
  70. static void IdleLock(void)
  71. {
  72.     PRInt32 i;
  73.  
  74.     for (i = 0; i < count; i++) {
  75.     PR_Lock(lock);
  76.     PR_Unlock(lock);
  77.     }
  78. }
  79.  
  80. static void IdleMonitor(void)
  81. {
  82.     PRInt32 i;
  83.  
  84.     for (i = 0; i < count; i++) {
  85.     PR_EnterMonitor(mon);
  86.     PR_ExitMonitor(mon);
  87.     }
  88. }
  89.  
  90. static void IdleCMonitor(void)
  91. {
  92.     PRInt32 i;
  93.  
  94.     for (i = 0; i < count; i++) {
  95.     PR_CEnterMonitor((void*)7);
  96.     PR_CExitMonitor((void*)7);
  97.     }
  98. }
  99.  
  100. /************************************************************************/
  101.  
  102. static void PR_CALLBACK dull(void *arg)
  103. {
  104. }
  105.  
  106. static void CDThread(void)
  107. {
  108.     PRInt32 i;
  109.     int num_threads = count;
  110.  
  111.     /*
  112.      * Cannot create too many threads
  113.      */
  114.     if (num_threads > 1000)
  115.     num_threads = 1000;
  116.  
  117.     for (i = 0; i < num_threads; i++) {
  118.         PRThread *t = PR_CreateThread(PR_USER_THREAD,
  119.                       dull, 0, 
  120.                       PR_PRIORITY_NORMAL,
  121.                       PR_LOCAL_THREAD,
  122.                       PR_UNJOINABLE_THREAD,
  123.                       0);
  124.         if (NULL == t) {
  125.             fprintf(stderr, "CDThread: cannot create thread %3d\n", i);
  126.         } else {
  127.             DPRINTF(("CDThread: created thread %3d \n",i));
  128.         }
  129.         PR_Sleep(0);
  130.     }
  131. }
  132.  
  133. static int alive;
  134. static int cxq;
  135.  
  136. static void PR_CALLBACK CXReader(void *arg)
  137. {
  138.     PRInt32 i, n;
  139.  
  140.     PR_EnterMonitor(mon);
  141.     n = count / 2;
  142.     for (i = 0; i < n; i++) {
  143.     while (cxq == 0) {
  144.             DPRINTF(("CXReader: thread = 0x%lx waiting\n",
  145.                     PR_GetCurrentThread()));
  146.         PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
  147.     }
  148.     --cxq;
  149.     PR_Notify(mon);
  150.     }
  151.     PR_ExitMonitor(mon);
  152.  
  153.     PR_EnterMonitor(mon2);
  154.     --alive;
  155.     PR_Notify(mon2);
  156.     PR_ExitMonitor(mon2);
  157.     DPRINTF(("CXReader: thread = 0x%lx exiting\n", PR_GetCurrentThread()));
  158. }
  159.  
  160. static void PR_CALLBACK CXWriter(void *arg)
  161. {
  162.     PRInt32 i, n;
  163.  
  164.     PR_EnterMonitor(mon);
  165.     n = count / 2;
  166.     for (i = 0; i < n; i++) {
  167.     while (cxq == 1) {
  168.             DPRINTF(("CXWriter: thread = 0x%lx waiting\n",
  169.                     PR_GetCurrentThread()));
  170.         PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
  171.     }
  172.     ++cxq;
  173.     PR_Notify(mon);
  174.     }
  175.     PR_ExitMonitor(mon);
  176.  
  177.     PR_EnterMonitor(mon2);
  178.     --alive;
  179.     PR_Notify(mon2);
  180.     PR_ExitMonitor(mon2);
  181.     DPRINTF(("CXWriter: thread = 0x%lx exiting\n", PR_GetCurrentThread()));
  182. }
  183.  
  184. static void ContextSwitch(PRThreadScope scope1, PRThreadScope scope2)
  185. {
  186.     PRThread *t1, *t2;
  187.  
  188.     PR_EnterMonitor(mon2);
  189.     alive = 2;
  190.     cxq = 0;
  191.  
  192.     t1 = PR_CreateThread(PR_USER_THREAD,
  193.                       CXReader, 0, 
  194.                       PR_PRIORITY_NORMAL,
  195.                       scope1,
  196.                       PR_UNJOINABLE_THREAD,
  197.                       0);
  198.     if (NULL == t1) {
  199.         fprintf(stderr, "ContextSwitch: cannot create thread\n");
  200.     } else {
  201.         DPRINTF(("ContextSwitch: created %s thread = 0x%lx\n",
  202.                 (scope1 == PR_GLOBAL_THREAD ?
  203.                 "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"),
  204.                             t1));
  205.     }
  206.     t2 = PR_CreateThread(PR_USER_THREAD,
  207.                       CXWriter, 0, 
  208.                       PR_PRIORITY_NORMAL,
  209.                       scope2,
  210.                       PR_UNJOINABLE_THREAD,
  211.                       0);
  212.     if (NULL == t2) {
  213.         fprintf(stderr, "ContextSwitch: cannot create thread\n");
  214.     } else {
  215.         DPRINTF(("ContextSwitch: created %s thread = 0x%lx\n",
  216.                 (scope2 == PR_GLOBAL_THREAD ?
  217.                 "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"),
  218.                             t2));
  219.     }
  220.  
  221.     /* Wait for both of the threads to exit */
  222.     while (alive) {
  223.     PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
  224.     }
  225.     PR_ExitMonitor(mon2);
  226. }
  227.  
  228. static void ContextSwitchUU(void)
  229. {
  230.     ContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
  231. }
  232.  
  233. static void ContextSwitchUK(void)
  234. {
  235.     ContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
  236. }
  237.  
  238. static void ContextSwitchKU(void)
  239. {
  240.     ContextSwitch(PR_GLOBAL_THREAD, PR_LOCAL_THREAD);
  241. }
  242.  
  243. static void ContextSwitchKK(void)
  244. {
  245.     ContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
  246. }
  247.  
  248. /************************************************************************/
  249.  
  250. static void PR_CALLBACK SemaThread(void *argSema)
  251. {
  252.     PRSemaphore **sem = (PRSemaphore **)argSema;
  253.     PRInt32 i, n;
  254.  
  255.     n = count / 2;
  256.     for (i = 0; i < n; i++) {
  257.         DPRINTF(("SemaThread: thread = 0x%lx waiting on sem = 0x%lx\n",
  258.                 PR_GetCurrentThread(), sem[0]));
  259.         PR_WaitSem(sem[0]);
  260.         DPRINTF(("SemaThread: thread = 0x%lx posting on sem = 0x%lx\n",
  261.                 PR_GetCurrentThread(), sem[1]));
  262.         PR_PostSem(sem[1]);
  263.     }
  264.  
  265.     PR_EnterMonitor(mon2);
  266.     --alive;
  267.     PR_Notify(mon2);
  268.     PR_ExitMonitor(mon2);
  269.     DPRINTF(("SemaThread: thread = 0x%lx exiting\n", PR_GetCurrentThread()));
  270. }
  271.  
  272. static  PRSemaphore *sem_set1[2];
  273. static  PRSemaphore *sem_set2[2];
  274.  
  275. static void SemaContextSwitch(PRThreadScope scope1, PRThreadScope scope2)
  276. {
  277.     PRThread *t1, *t2;
  278.     sem_set1[0] = PR_NewSem(1);
  279.     sem_set1[1] = PR_NewSem(0);
  280.     sem_set2[0] = sem_set1[1];
  281.     sem_set2[1] = sem_set1[0];
  282.  
  283.     PR_EnterMonitor(mon2);
  284.     alive = 2;
  285.     cxq = 0;
  286.  
  287.     t1 = PR_CreateThread(PR_USER_THREAD,
  288.                       SemaThread, 
  289.                       sem_set1, 
  290.                       PR_PRIORITY_NORMAL,
  291.                       scope1,
  292.                       PR_UNJOINABLE_THREAD,
  293.                       0);
  294.     if (NULL == t1) {
  295.         fprintf(stderr, "SemaContextSwitch: cannot create thread\n");
  296.     } else {
  297.         DPRINTF(("SemaContextSwitch: created %s thread = 0x%lx\n",
  298.                 (scope1 == PR_GLOBAL_THREAD ?
  299.                 "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"),
  300.                             t1));
  301.     }
  302.     t2 = PR_CreateThread(PR_USER_THREAD,
  303.                       SemaThread, 
  304.                       sem_set2, 
  305.                       PR_PRIORITY_NORMAL,
  306.                       scope2,
  307.                       PR_UNJOINABLE_THREAD,
  308.                       0);
  309.     if (NULL == t2) {
  310.         fprintf(stderr, "SemaContextSwitch: cannot create thread\n");
  311.     } else {
  312.         DPRINTF(("SemaContextSwitch: created %s thread = 0x%lx\n",
  313.                 (scope2 == PR_GLOBAL_THREAD ?
  314.                 "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"),
  315.                             t2));
  316.     }
  317.  
  318.     /* Wait for both of the threads to exit */
  319.     while (alive) {
  320.         PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
  321.     }
  322.     PR_ExitMonitor(mon2);
  323.  
  324.     PR_DestroySem(sem_set1[0]);
  325.     PR_DestroySem(sem_set1[1]);
  326. }
  327.  
  328. static void SemaContextSwitchUU(void)
  329. {
  330.     SemaContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
  331. }
  332.  
  333. static void SemaContextSwitchUK(void)
  334. {
  335.     SemaContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
  336. }
  337.  
  338. static void SemaContextSwitchKU(void)
  339. {
  340.     SemaContextSwitch(PR_GLOBAL_THREAD, PR_LOCAL_THREAD);
  341. }
  342.  
  343. static void SemaContextSwitchKK(void)
  344. {
  345.     SemaContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
  346. }
  347.  
  348.  
  349. /************************************************************************/
  350.  
  351. static void Measure(void (*func)(void), const char *msg)
  352. {
  353.     PRIntervalTime start, stop;
  354.     double d;
  355.  
  356.     start = PR_IntervalNow();
  357.     (*func)();
  358.     stop = PR_IntervalNow() - start;
  359.     d = (double)PR_IntervalToMicroseconds(stop);
  360.  
  361.     printf("%40s: %6.2f usec\n", msg, d / count);
  362. }
  363.  
  364. int main(int argc, char **argv)
  365. {
  366.     PLOptStatus os;
  367.     PLOptState *opt = PL_CreateOptState(argc, argv, "dc:");
  368.     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  369.     {
  370.         if (PL_OPT_BAD == os) continue;
  371.         switch (opt->option)
  372.         {
  373.         case 'd':  /* debug mode */
  374.             _debug_on = 1;
  375.             break;
  376.         case 'c':  /* loop count */
  377.             count = atoi(opt->value);
  378.             break;
  379.          default:
  380.             break;
  381.         }
  382.     }
  383.     PL_DestroyOptState(opt);
  384.  
  385.     if (0 == count) count = DEFAULT_COUNT;
  386.     
  387.     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
  388.     PR_BlockClockInterrupts();
  389.     PR_UnblockClockInterrupts();
  390.     PR_STDIO_INIT();
  391.  
  392. #ifdef XP_MAC
  393.     SetupMacPrintfLog("perf.log");
  394. #endif
  395.  
  396.     lock = PR_NewLock();
  397.     mon = PR_NewMonitor();
  398.     mon2 = PR_NewMonitor();
  399.  
  400.     Measure(LocalProcedureCall, "local procedure call overhead");
  401.     Measure(DLLProcedureCall, "DLL procedure call overhead");
  402.     Measure(IdleLock, "idle lock lock/unlock pair");
  403.     Measure(IdleMonitor, "idle monitor entry/exit pair");
  404.     Measure(IdleCMonitor, "idle cache monitor entry/exit pair");
  405.     Measure(CDThread, "create/destroy thread pair");
  406.     Measure(ContextSwitchUU, "context switch - user/user");
  407.     Measure(ContextSwitchUK, "context switch - user/kernel");
  408.     Measure(ContextSwitchKU, "context switch - kernel/user");
  409.     Measure(ContextSwitchKK, "context switch - kernel/kernel");
  410.     Measure(SemaContextSwitchUU, "sema context switch - user/user");
  411.     Measure(SemaContextSwitchUK, "sema context switch - user/kernel");
  412.     Measure(SemaContextSwitchKU, "sema context switch - kernel/user");
  413.     Measure(SemaContextSwitchKK, "sema context switch - kernel/kernel");
  414.  
  415.     printf("--------------\n");
  416.     printf("Adding 7 additional CPUs\n");
  417.  
  418.     PR_SetConcurrency(8);
  419.     printf("--------------\n");
  420.  
  421.     Measure(LocalProcedureCall, "local procedure call overhead");
  422.     Measure(DLLProcedureCall, "DLL procedure call overhead");
  423.     Measure(IdleLock, "idle lock lock/unlock pair");
  424.     Measure(IdleMonitor, "idle monitor entry/exit pair");
  425.     Measure(IdleCMonitor, "idle cache monitor entry/exit pair");
  426.     Measure(CDThread, "create/destroy thread pair");
  427.     Measure(ContextSwitchUU, "context switch - user/user");
  428.     Measure(ContextSwitchUK, "context switch - user/kernel");
  429.     Measure(ContextSwitchKU, "context switch - kernel/user");
  430.     Measure(ContextSwitchKK, "context switch - kernel/kernel");
  431.     Measure(SemaContextSwitchUU, "sema context switch - user/user");
  432.     Measure(SemaContextSwitchUK, "sema context switch - user/kernel");
  433.     Measure(SemaContextSwitchKU, "sema context switch - kernel/user");
  434.     Measure(SemaContextSwitchKK, "sema context switch - kernel/kernel");
  435.  
  436.     PR_DestroyLock(lock);
  437.     PR_DestroyMonitor(mon);
  438.     PR_DestroyMonitor(mon2);
  439.  
  440.     PR_Cleanup();
  441.     return 0;
  442. }
  443.