1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/tests/perf.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,442 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nspr.h" 1.10 +#include "plgetopt.h" 1.11 + 1.12 +#include <stdio.h> 1.13 +#include <stdlib.h> 1.14 +#include <string.h> 1.15 + 1.16 +int _debug_on = 0; 1.17 +#define DPRINTF(arg) if (_debug_on) printf arg 1.18 + 1.19 +#include "obsolete/prsem.h" 1.20 + 1.21 +PRLock *lock; 1.22 +PRMonitor *mon; 1.23 +PRMonitor *mon2; 1.24 + 1.25 +#define DEFAULT_COUNT 1000 1.26 + 1.27 +PRInt32 count; 1.28 + 1.29 +static void nop(int a, int b, int c) 1.30 +{ 1.31 +} 1.32 + 1.33 +static void LocalProcedureCall(void) 1.34 +{ 1.35 + PRInt32 i; 1.36 + 1.37 + for (i = 0; i < count; i++) { 1.38 + nop(i, i, 5); 1.39 + } 1.40 +} 1.41 + 1.42 +static void DLLProcedureCall(void) 1.43 +{ 1.44 + PRInt32 i; 1.45 + PRThreadState state; 1.46 + PRThread *self = PR_GetCurrentThread(); 1.47 + 1.48 + for (i = 0; i < count; i++) { 1.49 + state = PR_GetThreadState(self); 1.50 + } 1.51 +} 1.52 + 1.53 +static void Now(void) 1.54 +{ 1.55 + PRInt32 i; 1.56 + PRTime time; 1.57 + 1.58 + for (i = 0; i < count; i++) { 1.59 + time = PR_Now(); 1.60 + } 1.61 +} 1.62 + 1.63 +static void Interval(void) 1.64 +{ 1.65 + PRInt32 i; 1.66 + PRIntervalTime time; 1.67 + 1.68 + for (i = 0; i < count; i++) { 1.69 + time = PR_IntervalNow(); 1.70 + } 1.71 +} 1.72 + 1.73 +static void IdleLock(void) 1.74 +{ 1.75 + PRInt32 i; 1.76 + 1.77 + for (i = 0; i < count; i++) { 1.78 + PR_Lock(lock); 1.79 + PR_Unlock(lock); 1.80 + } 1.81 +} 1.82 + 1.83 +static void IdleMonitor(void) 1.84 +{ 1.85 + PRInt32 i; 1.86 + 1.87 + for (i = 0; i < count; i++) { 1.88 + PR_EnterMonitor(mon); 1.89 + PR_ExitMonitor(mon); 1.90 + } 1.91 +} 1.92 + 1.93 +static void IdleCMonitor(void) 1.94 +{ 1.95 + PRInt32 i; 1.96 + 1.97 + for (i = 0; i < count; i++) { 1.98 + PR_CEnterMonitor((void*)7); 1.99 + PR_CExitMonitor((void*)7); 1.100 + } 1.101 +} 1.102 + 1.103 +/************************************************************************/ 1.104 + 1.105 +static void PR_CALLBACK dull(void *arg) 1.106 +{ 1.107 +} 1.108 + 1.109 +static void CDThread(void) 1.110 +{ 1.111 + PRInt32 i; 1.112 + int num_threads = count; 1.113 + 1.114 + /* 1.115 + * Cannot create too many threads 1.116 + */ 1.117 + if (num_threads > 1000) 1.118 + num_threads = 1000; 1.119 + 1.120 + for (i = 0; i < num_threads; i++) { 1.121 + PRThread *t = PR_CreateThread(PR_USER_THREAD, 1.122 + dull, 0, 1.123 + PR_PRIORITY_NORMAL, 1.124 + PR_LOCAL_THREAD, 1.125 + PR_UNJOINABLE_THREAD, 1.126 + 0); 1.127 + if (NULL == t) { 1.128 + fprintf(stderr, "CDThread: cannot create thread %3d\n", i); 1.129 + } else { 1.130 + DPRINTF(("CDThread: created thread %3d \n",i)); 1.131 + } 1.132 + PR_Sleep(0); 1.133 + } 1.134 +} 1.135 + 1.136 +static int alive; 1.137 +static int cxq; 1.138 + 1.139 +static void PR_CALLBACK CXReader(void *arg) 1.140 +{ 1.141 + PRInt32 i, n; 1.142 + 1.143 + PR_EnterMonitor(mon); 1.144 + n = count / 2; 1.145 + for (i = 0; i < n; i++) { 1.146 + while (cxq == 0) { 1.147 + DPRINTF(("CXReader: thread = 0x%lx waiting\n", 1.148 + PR_GetCurrentThread())); 1.149 + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); 1.150 + } 1.151 + --cxq; 1.152 + PR_Notify(mon); 1.153 + } 1.154 + PR_ExitMonitor(mon); 1.155 + 1.156 + PR_EnterMonitor(mon2); 1.157 + --alive; 1.158 + PR_Notify(mon2); 1.159 + PR_ExitMonitor(mon2); 1.160 + DPRINTF(("CXReader: thread = 0x%lx exiting\n", PR_GetCurrentThread())); 1.161 +} 1.162 + 1.163 +static void PR_CALLBACK CXWriter(void *arg) 1.164 +{ 1.165 + PRInt32 i, n; 1.166 + 1.167 + PR_EnterMonitor(mon); 1.168 + n = count / 2; 1.169 + for (i = 0; i < n; i++) { 1.170 + while (cxq == 1) { 1.171 + DPRINTF(("CXWriter: thread = 0x%lx waiting\n", 1.172 + PR_GetCurrentThread())); 1.173 + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); 1.174 + } 1.175 + ++cxq; 1.176 + PR_Notify(mon); 1.177 + } 1.178 + PR_ExitMonitor(mon); 1.179 + 1.180 + PR_EnterMonitor(mon2); 1.181 + --alive; 1.182 + PR_Notify(mon2); 1.183 + PR_ExitMonitor(mon2); 1.184 + DPRINTF(("CXWriter: thread = 0x%lx exiting\n", PR_GetCurrentThread())); 1.185 +} 1.186 + 1.187 +static void ContextSwitch(PRThreadScope scope1, PRThreadScope scope2) 1.188 +{ 1.189 + PRThread *t1, *t2; 1.190 + 1.191 + PR_EnterMonitor(mon2); 1.192 + alive = 2; 1.193 + cxq = 0; 1.194 + 1.195 + t1 = PR_CreateThread(PR_USER_THREAD, 1.196 + CXReader, 0, 1.197 + PR_PRIORITY_NORMAL, 1.198 + scope1, 1.199 + PR_UNJOINABLE_THREAD, 1.200 + 0); 1.201 + if (NULL == t1) { 1.202 + fprintf(stderr, "ContextSwitch: cannot create thread\n"); 1.203 + } else { 1.204 + DPRINTF(("ContextSwitch: created %s thread = 0x%lx\n", 1.205 + (scope1 == PR_GLOBAL_THREAD ? 1.206 + "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"), 1.207 + t1)); 1.208 + } 1.209 + t2 = PR_CreateThread(PR_USER_THREAD, 1.210 + CXWriter, 0, 1.211 + PR_PRIORITY_NORMAL, 1.212 + scope2, 1.213 + PR_UNJOINABLE_THREAD, 1.214 + 0); 1.215 + if (NULL == t2) { 1.216 + fprintf(stderr, "ContextSwitch: cannot create thread\n"); 1.217 + } else { 1.218 + DPRINTF(("ContextSwitch: created %s thread = 0x%lx\n", 1.219 + (scope2 == PR_GLOBAL_THREAD ? 1.220 + "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"), 1.221 + t2)); 1.222 + } 1.223 + 1.224 + /* Wait for both of the threads to exit */ 1.225 + while (alive) { 1.226 + PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); 1.227 + } 1.228 + PR_ExitMonitor(mon2); 1.229 +} 1.230 + 1.231 +static void ContextSwitchUU(void) 1.232 +{ 1.233 + ContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD); 1.234 +} 1.235 + 1.236 +static void ContextSwitchUK(void) 1.237 +{ 1.238 + ContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD); 1.239 +} 1.240 + 1.241 +static void ContextSwitchKU(void) 1.242 +{ 1.243 + ContextSwitch(PR_GLOBAL_THREAD, PR_LOCAL_THREAD); 1.244 +} 1.245 + 1.246 +static void ContextSwitchKK(void) 1.247 +{ 1.248 + ContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD); 1.249 +} 1.250 + 1.251 +/************************************************************************/ 1.252 + 1.253 +static void PR_CALLBACK SemaThread(void *argSema) 1.254 +{ 1.255 + PRSemaphore **sem = (PRSemaphore **)argSema; 1.256 + PRInt32 i, n; 1.257 + 1.258 + n = count / 2; 1.259 + for (i = 0; i < n; i++) { 1.260 + DPRINTF(("SemaThread: thread = 0x%lx waiting on sem = 0x%lx\n", 1.261 + PR_GetCurrentThread(), sem[0])); 1.262 + PR_WaitSem(sem[0]); 1.263 + DPRINTF(("SemaThread: thread = 0x%lx posting on sem = 0x%lx\n", 1.264 + PR_GetCurrentThread(), sem[1])); 1.265 + PR_PostSem(sem[1]); 1.266 + } 1.267 + 1.268 + PR_EnterMonitor(mon2); 1.269 + --alive; 1.270 + PR_Notify(mon2); 1.271 + PR_ExitMonitor(mon2); 1.272 + DPRINTF(("SemaThread: thread = 0x%lx exiting\n", PR_GetCurrentThread())); 1.273 +} 1.274 + 1.275 +static PRSemaphore *sem_set1[2]; 1.276 +static PRSemaphore *sem_set2[2]; 1.277 + 1.278 +static void SemaContextSwitch(PRThreadScope scope1, PRThreadScope scope2) 1.279 +{ 1.280 + PRThread *t1, *t2; 1.281 + sem_set1[0] = PR_NewSem(1); 1.282 + sem_set1[1] = PR_NewSem(0); 1.283 + sem_set2[0] = sem_set1[1]; 1.284 + sem_set2[1] = sem_set1[0]; 1.285 + 1.286 + PR_EnterMonitor(mon2); 1.287 + alive = 2; 1.288 + cxq = 0; 1.289 + 1.290 + t1 = PR_CreateThread(PR_USER_THREAD, 1.291 + SemaThread, 1.292 + sem_set1, 1.293 + PR_PRIORITY_NORMAL, 1.294 + scope1, 1.295 + PR_UNJOINABLE_THREAD, 1.296 + 0); 1.297 + if (NULL == t1) { 1.298 + fprintf(stderr, "SemaContextSwitch: cannot create thread\n"); 1.299 + } else { 1.300 + DPRINTF(("SemaContextSwitch: created %s thread = 0x%lx\n", 1.301 + (scope1 == PR_GLOBAL_THREAD ? 1.302 + "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"), 1.303 + t1)); 1.304 + } 1.305 + t2 = PR_CreateThread(PR_USER_THREAD, 1.306 + SemaThread, 1.307 + sem_set2, 1.308 + PR_PRIORITY_NORMAL, 1.309 + scope2, 1.310 + PR_UNJOINABLE_THREAD, 1.311 + 0); 1.312 + if (NULL == t2) { 1.313 + fprintf(stderr, "SemaContextSwitch: cannot create thread\n"); 1.314 + } else { 1.315 + DPRINTF(("SemaContextSwitch: created %s thread = 0x%lx\n", 1.316 + (scope2 == PR_GLOBAL_THREAD ? 1.317 + "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"), 1.318 + t2)); 1.319 + } 1.320 + 1.321 + /* Wait for both of the threads to exit */ 1.322 + while (alive) { 1.323 + PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); 1.324 + } 1.325 + PR_ExitMonitor(mon2); 1.326 + 1.327 + PR_DestroySem(sem_set1[0]); 1.328 + PR_DestroySem(sem_set1[1]); 1.329 +} 1.330 + 1.331 +static void SemaContextSwitchUU(void) 1.332 +{ 1.333 + SemaContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD); 1.334 +} 1.335 + 1.336 +static void SemaContextSwitchUK(void) 1.337 +{ 1.338 + SemaContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD); 1.339 +} 1.340 + 1.341 +static void SemaContextSwitchKU(void) 1.342 +{ 1.343 + SemaContextSwitch(PR_GLOBAL_THREAD, PR_LOCAL_THREAD); 1.344 +} 1.345 + 1.346 +static void SemaContextSwitchKK(void) 1.347 +{ 1.348 + SemaContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD); 1.349 +} 1.350 + 1.351 + 1.352 +/************************************************************************/ 1.353 + 1.354 +static void Measure(void (*func)(void), const char *msg) 1.355 +{ 1.356 + PRIntervalTime start, stop; 1.357 + double d; 1.358 + 1.359 + start = PR_IntervalNow(); 1.360 + (*func)(); 1.361 + stop = PR_IntervalNow() - start; 1.362 + d = (double)PR_IntervalToMicroseconds(stop); 1.363 + 1.364 + printf("%40s: %6.2f usec\n", msg, d / count); 1.365 +} 1.366 + 1.367 +int main(int argc, char **argv) 1.368 +{ 1.369 + PLOptStatus os; 1.370 + PLOptState *opt = PL_CreateOptState(argc, argv, "dc:"); 1.371 + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) 1.372 + { 1.373 + if (PL_OPT_BAD == os) continue; 1.374 + switch (opt->option) 1.375 + { 1.376 + case 'd': /* debug mode */ 1.377 + _debug_on = 1; 1.378 + break; 1.379 + case 'c': /* loop count */ 1.380 + count = atoi(opt->value); 1.381 + break; 1.382 + default: 1.383 + break; 1.384 + } 1.385 + } 1.386 + PL_DestroyOptState(opt); 1.387 + 1.388 + if (0 == count) count = DEFAULT_COUNT; 1.389 + 1.390 + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); 1.391 + PR_BlockClockInterrupts(); 1.392 + PR_UnblockClockInterrupts(); 1.393 + PR_STDIO_INIT(); 1.394 + 1.395 + lock = PR_NewLock(); 1.396 + mon = PR_NewMonitor(); 1.397 + mon2 = PR_NewMonitor(); 1.398 + 1.399 + Measure(LocalProcedureCall, "local procedure call overhead"); 1.400 + Measure(DLLProcedureCall, "DLL procedure call overhead"); 1.401 + Measure(Now, "current calendar time"); 1.402 + Measure(Interval, "interval time"); 1.403 + Measure(IdleLock, "idle lock lock/unlock pair"); 1.404 + Measure(IdleMonitor, "idle monitor entry/exit pair"); 1.405 + Measure(IdleCMonitor, "idle cache monitor entry/exit pair"); 1.406 + Measure(CDThread, "create/destroy thread pair"); 1.407 + Measure(ContextSwitchUU, "context switch - user/user"); 1.408 + Measure(ContextSwitchUK, "context switch - user/kernel"); 1.409 + Measure(ContextSwitchKU, "context switch - kernel/user"); 1.410 + Measure(ContextSwitchKK, "context switch - kernel/kernel"); 1.411 + Measure(SemaContextSwitchUU, "sema context switch - user/user"); 1.412 + Measure(SemaContextSwitchUK, "sema context switch - user/kernel"); 1.413 + Measure(SemaContextSwitchKU, "sema context switch - kernel/user"); 1.414 + Measure(SemaContextSwitchKK, "sema context switch - kernel/kernel"); 1.415 + 1.416 + printf("--------------\n"); 1.417 + printf("Adding 7 additional CPUs\n"); 1.418 + 1.419 + PR_SetConcurrency(8); 1.420 + printf("--------------\n"); 1.421 + 1.422 + Measure(LocalProcedureCall, "local procedure call overhead"); 1.423 + Measure(DLLProcedureCall, "DLL procedure call overhead"); 1.424 + Measure(Now, "current calendar time"); 1.425 + Measure(Interval, "interval time"); 1.426 + Measure(IdleLock, "idle lock lock/unlock pair"); 1.427 + Measure(IdleMonitor, "idle monitor entry/exit pair"); 1.428 + Measure(IdleCMonitor, "idle cache monitor entry/exit pair"); 1.429 + Measure(CDThread, "create/destroy thread pair"); 1.430 + Measure(ContextSwitchUU, "context switch - user/user"); 1.431 + Measure(ContextSwitchUK, "context switch - user/kernel"); 1.432 + Measure(ContextSwitchKU, "context switch - kernel/user"); 1.433 + Measure(ContextSwitchKK, "context switch - kernel/kernel"); 1.434 + Measure(SemaContextSwitchUU, "sema context switch - user/user"); 1.435 + Measure(SemaContextSwitchUK, "sema context switch - user/kernel"); 1.436 + Measure(SemaContextSwitchKU, "sema context switch - kernel/user"); 1.437 + Measure(SemaContextSwitchKK, "sema context switch - kernel/kernel"); 1.438 + 1.439 + PR_DestroyLock(lock); 1.440 + PR_DestroyMonitor(mon); 1.441 + PR_DestroyMonitor(mon2); 1.442 + 1.443 + PR_Cleanup(); 1.444 + return 0; 1.445 +}