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 }