nsprpub/pr/tests/perf.c

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nspr.h"
     7 #include "plgetopt.h"
     9 #include <stdio.h>
    10 #include <stdlib.h>
    11 #include <string.h>
    13 int _debug_on = 0;
    14 #define DPRINTF(arg) if (_debug_on) printf arg
    16 #include "obsolete/prsem.h"
    18 PRLock *lock;
    19 PRMonitor *mon;
    20 PRMonitor *mon2;
    22 #define DEFAULT_COUNT    1000
    24 PRInt32 count;
    26 static void nop(int a, int b, int c)
    27 {
    28 }
    30 static void LocalProcedureCall(void)
    31 {
    32     PRInt32 i;
    34     for (i = 0; i < count; i++) {
    35     nop(i, i, 5);
    36     }
    37 }
    39 static void DLLProcedureCall(void)
    40 {
    41     PRInt32 i;
    42 	PRThreadState state;
    43 	PRThread *self = PR_GetCurrentThread();
    45     for (i = 0; i < count; i++) {
    46     	state = PR_GetThreadState(self);
    47     }
    48 }
    50 static void Now(void)
    51 {
    52     PRInt32 i;
    53     PRTime time;
    55     for (i = 0; i < count; i++) {
    56         time = PR_Now();
    57     }
    58 }
    60 static void Interval(void)
    61 {
    62     PRInt32 i;
    63     PRIntervalTime time;
    65     for (i = 0; i < count; i++) {
    66         time = PR_IntervalNow();
    67     }
    68 }
    70 static void IdleLock(void)
    71 {
    72     PRInt32 i;
    74     for (i = 0; i < count; i++) {
    75     PR_Lock(lock);
    76     PR_Unlock(lock);
    77     }
    78 }
    80 static void IdleMonitor(void)
    81 {
    82     PRInt32 i;
    84     for (i = 0; i < count; i++) {
    85     PR_EnterMonitor(mon);
    86     PR_ExitMonitor(mon);
    87     }
    88 }
    90 static void IdleCMonitor(void)
    91 {
    92     PRInt32 i;
    94     for (i = 0; i < count; i++) {
    95     PR_CEnterMonitor((void*)7);
    96     PR_CExitMonitor((void*)7);
    97     }
    98 }
   100 /************************************************************************/
   102 static void PR_CALLBACK dull(void *arg)
   103 {
   104 }
   106 static void CDThread(void)
   107 {
   108     PRInt32 i;
   109     int num_threads = count;
   111     /*
   112      * Cannot create too many threads
   113      */
   114     if (num_threads > 1000)
   115     num_threads = 1000;
   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 }
   133 static int alive;
   134 static int cxq;
   136 static void PR_CALLBACK CXReader(void *arg)
   137 {
   138     PRInt32 i, n;
   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);
   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 }
   160 static void PR_CALLBACK CXWriter(void *arg)
   161 {
   162     PRInt32 i, n;
   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);
   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 }
   184 static void ContextSwitch(PRThreadScope scope1, PRThreadScope scope2)
   185 {
   186     PRThread *t1, *t2;
   188     PR_EnterMonitor(mon2);
   189     alive = 2;
   190     cxq = 0;
   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     }
   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 }
   228 static void ContextSwitchUU(void)
   229 {
   230     ContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
   231 }
   233 static void ContextSwitchUK(void)
   234 {
   235     ContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
   236 }
   238 static void ContextSwitchKU(void)
   239 {
   240     ContextSwitch(PR_GLOBAL_THREAD, PR_LOCAL_THREAD);
   241 }
   243 static void ContextSwitchKK(void)
   244 {
   245     ContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
   246 }
   248 /************************************************************************/
   250 static void PR_CALLBACK SemaThread(void *argSema)
   251 {
   252     PRSemaphore **sem = (PRSemaphore **)argSema;
   253     PRInt32 i, n;
   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     }
   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 }
   272 static  PRSemaphore *sem_set1[2];
   273 static  PRSemaphore *sem_set2[2];
   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];
   283     PR_EnterMonitor(mon2);
   284     alive = 2;
   285     cxq = 0;
   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     }
   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);
   324     PR_DestroySem(sem_set1[0]);
   325     PR_DestroySem(sem_set1[1]);
   326 }
   328 static void SemaContextSwitchUU(void)
   329 {
   330     SemaContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
   331 }
   333 static void SemaContextSwitchUK(void)
   334 {
   335     SemaContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
   336 }
   338 static void SemaContextSwitchKU(void)
   339 {
   340     SemaContextSwitch(PR_GLOBAL_THREAD, PR_LOCAL_THREAD);
   341 }
   343 static void SemaContextSwitchKK(void)
   344 {
   345     SemaContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
   346 }
   349 /************************************************************************/
   351 static void Measure(void (*func)(void), const char *msg)
   352 {
   353     PRIntervalTime start, stop;
   354     double d;
   356     start = PR_IntervalNow();
   357     (*func)();
   358     stop = PR_IntervalNow() - start;
   359     d = (double)PR_IntervalToMicroseconds(stop);
   361     printf("%40s: %6.2f usec\n", msg, d / count);
   362 }
   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);
   385     if (0 == count) count = DEFAULT_COUNT;
   387     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
   388 	PR_BlockClockInterrupts();
   389 	PR_UnblockClockInterrupts();
   390     PR_STDIO_INIT();
   392     lock = PR_NewLock();
   393     mon = PR_NewMonitor();
   394     mon2 = PR_NewMonitor();
   396     Measure(LocalProcedureCall, "local procedure call overhead");
   397     Measure(DLLProcedureCall, "DLL procedure call overhead");
   398     Measure(Now, "current calendar time");
   399     Measure(Interval, "interval time");
   400     Measure(IdleLock, "idle lock lock/unlock pair");
   401     Measure(IdleMonitor, "idle monitor entry/exit pair");
   402     Measure(IdleCMonitor, "idle cache monitor entry/exit pair");
   403     Measure(CDThread, "create/destroy thread pair");
   404     Measure(ContextSwitchUU, "context switch - user/user");
   405     Measure(ContextSwitchUK, "context switch - user/kernel");
   406     Measure(ContextSwitchKU, "context switch - kernel/user");
   407     Measure(ContextSwitchKK, "context switch - kernel/kernel");
   408     Measure(SemaContextSwitchUU, "sema context switch - user/user");
   409     Measure(SemaContextSwitchUK, "sema context switch - user/kernel");
   410     Measure(SemaContextSwitchKU, "sema context switch - kernel/user");
   411     Measure(SemaContextSwitchKK, "sema context switch - kernel/kernel");
   413     printf("--------------\n");
   414     printf("Adding 7 additional CPUs\n");
   416     PR_SetConcurrency(8);
   417     printf("--------------\n");
   419     Measure(LocalProcedureCall, "local procedure call overhead");
   420     Measure(DLLProcedureCall, "DLL procedure call overhead");
   421     Measure(Now, "current calendar time");
   422     Measure(Interval, "interval time");
   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");
   436     PR_DestroyLock(lock);
   437     PR_DestroyMonitor(mon);
   438     PR_DestroyMonitor(mon2);
   440     PR_Cleanup();
   441     return 0;
   442 }

mercurial