tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

perf.c (10286B)


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