nsprpub/pr/tests/perf.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial