1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Mozilla Public License Version
6
* 1.1 (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/MPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is the Netscape Portable Runtime (NSPR).
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 1998-2000
20
* the Initial Developer. All Rights Reserved.
24
* Alternatively, the contents of this file may be used under the terms of
25
* either the GNU General Public License Version 2 or later (the "GPL"), or
26
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27
* in which case the provisions of the GPL or the LGPL are applicable instead
28
* of those above. If you wish to allow use of your version of this file only
29
* under the terms of either the GPL or the LGPL, and not to allow others to
30
* use your version of this file under the terms of the MPL, indicate your
31
* decision by deleting the provisions above and replace them with the notice
32
* and other provisions required by the GPL or the LGPL. If you do not delete
33
* the provisions above, a recipient may use your version of this file under
34
* the terms of any one of the MPL, the GPL or the LGPL.
36
* ***** END LICENSE BLOCK ***** */
46
#define DPRINTF(arg) if (_debug_on) printf arg
51
#define printf PR_LogPrint
52
extern void SetupMacPrintfLog(char *logFile);
54
#include "obsolete/prsem.h"
61
#define DEFAULT_COUNT 1000
65
static void nop(int a, int b, int c)
69
static void LocalProcedureCall(void)
73
for (i = 0; i < count; i++) {
78
static void DLLProcedureCall(void)
82
PRThread *self = PR_CurrentThread();
84
for (i = 0; i < count; i++) {
85
state = PR_GetThreadState(self);
94
for (i = 0; i < count; i++) {
99
static void Interval(void)
104
for (i = 0; i < count; i++) {
105
time = PR_IntervalNow();
109
static void IdleLock(void)
113
for (i = 0; i < count; i++) {
119
static void IdleMonitor(void)
123
for (i = 0; i < count; i++) {
124
PR_EnterMonitor(mon);
129
static void IdleCMonitor(void)
133
for (i = 0; i < count; i++) {
134
PR_CEnterMonitor((void*)7);
135
PR_CExitMonitor((void*)7);
139
/************************************************************************/
141
static void PR_CALLBACK dull(void *arg)
145
static void CDThread(void)
148
int num_threads = count;
151
* Cannot create too many threads
153
if (num_threads > 1000)
156
for (i = 0; i < num_threads; i++) {
157
PRThread *t = PR_CreateThread(PR_USER_THREAD,
161
PR_UNJOINABLE_THREAD,
164
fprintf(stderr, "CDThread: cannot create thread %3d\n", i);
166
DPRINTF(("CDThread: created thread %3d \n",i));
175
static void PR_CALLBACK CXReader(void *arg)
179
PR_EnterMonitor(mon);
181
for (i = 0; i < n; i++) {
183
DPRINTF(("CXReader: thread = 0x%lx waiting\n",
184
PR_GetCurrentThread()));
185
PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
192
PR_EnterMonitor(mon2);
195
PR_ExitMonitor(mon2);
196
DPRINTF(("CXReader: thread = 0x%lx exiting\n", PR_GetCurrentThread()));
199
static void PR_CALLBACK CXWriter(void *arg)
203
PR_EnterMonitor(mon);
205
for (i = 0; i < n; i++) {
207
DPRINTF(("CXWriter: thread = 0x%lx waiting\n",
208
PR_GetCurrentThread()));
209
PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
216
PR_EnterMonitor(mon2);
219
PR_ExitMonitor(mon2);
220
DPRINTF(("CXWriter: thread = 0x%lx exiting\n", PR_GetCurrentThread()));
223
static void ContextSwitch(PRThreadScope scope1, PRThreadScope scope2)
227
PR_EnterMonitor(mon2);
231
t1 = PR_CreateThread(PR_USER_THREAD,
235
PR_UNJOINABLE_THREAD,
238
fprintf(stderr, "ContextSwitch: cannot create thread\n");
240
DPRINTF(("ContextSwitch: created %s thread = 0x%lx\n",
241
(scope1 == PR_GLOBAL_THREAD ?
242
"PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"),
245
t2 = PR_CreateThread(PR_USER_THREAD,
249
PR_UNJOINABLE_THREAD,
252
fprintf(stderr, "ContextSwitch: cannot create thread\n");
254
DPRINTF(("ContextSwitch: created %s thread = 0x%lx\n",
255
(scope2 == PR_GLOBAL_THREAD ?
256
"PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"),
260
/* Wait for both of the threads to exit */
262
PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
264
PR_ExitMonitor(mon2);
267
static void ContextSwitchUU(void)
269
ContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
272
static void ContextSwitchUK(void)
274
ContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
277
static void ContextSwitchKU(void)
279
ContextSwitch(PR_GLOBAL_THREAD, PR_LOCAL_THREAD);
282
static void ContextSwitchKK(void)
284
ContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
287
/************************************************************************/
289
static void PR_CALLBACK SemaThread(void *argSema)
291
PRSemaphore **sem = (PRSemaphore **)argSema;
295
for (i = 0; i < n; i++) {
296
DPRINTF(("SemaThread: thread = 0x%lx waiting on sem = 0x%lx\n",
297
PR_GetCurrentThread(), sem[0]));
299
DPRINTF(("SemaThread: thread = 0x%lx posting on sem = 0x%lx\n",
300
PR_GetCurrentThread(), sem[1]));
304
PR_EnterMonitor(mon2);
307
PR_ExitMonitor(mon2);
308
DPRINTF(("SemaThread: thread = 0x%lx exiting\n", PR_GetCurrentThread()));
311
static PRSemaphore *sem_set1[2];
312
static PRSemaphore *sem_set2[2];
314
static void SemaContextSwitch(PRThreadScope scope1, PRThreadScope scope2)
317
sem_set1[0] = PR_NewSem(1);
318
sem_set1[1] = PR_NewSem(0);
319
sem_set2[0] = sem_set1[1];
320
sem_set2[1] = sem_set1[0];
322
PR_EnterMonitor(mon2);
326
t1 = PR_CreateThread(PR_USER_THREAD,
331
PR_UNJOINABLE_THREAD,
334
fprintf(stderr, "SemaContextSwitch: cannot create thread\n");
336
DPRINTF(("SemaContextSwitch: created %s thread = 0x%lx\n",
337
(scope1 == PR_GLOBAL_THREAD ?
338
"PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"),
341
t2 = PR_CreateThread(PR_USER_THREAD,
346
PR_UNJOINABLE_THREAD,
349
fprintf(stderr, "SemaContextSwitch: cannot create thread\n");
351
DPRINTF(("SemaContextSwitch: created %s thread = 0x%lx\n",
352
(scope2 == PR_GLOBAL_THREAD ?
353
"PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"),
357
/* Wait for both of the threads to exit */
359
PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
361
PR_ExitMonitor(mon2);
363
PR_DestroySem(sem_set1[0]);
364
PR_DestroySem(sem_set1[1]);
367
static void SemaContextSwitchUU(void)
369
SemaContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
372
static void SemaContextSwitchUK(void)
374
SemaContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
377
static void SemaContextSwitchKU(void)
379
SemaContextSwitch(PR_GLOBAL_THREAD, PR_LOCAL_THREAD);
382
static void SemaContextSwitchKK(void)
384
SemaContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
388
/************************************************************************/
390
static void Measure(void (*func)(void), const char *msg)
392
PRIntervalTime start, stop;
395
start = PR_IntervalNow();
397
stop = PR_IntervalNow() - start;
398
d = (double)PR_IntervalToMicroseconds(stop);
400
printf("%40s: %6.2f usec\n", msg, d / count);
403
int main(int argc, char **argv)
406
PLOptState *opt = PL_CreateOptState(argc, argv, "dc:");
407
while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
409
if (PL_OPT_BAD == os) continue;
412
case 'd': /* debug mode */
415
case 'c': /* loop count */
416
count = atoi(opt->value);
422
PL_DestroyOptState(opt);
424
if (0 == count) count = DEFAULT_COUNT;
426
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
427
PR_BlockClockInterrupts();
428
PR_UnblockClockInterrupts();
432
SetupMacPrintfLog("perf.log");
436
mon = PR_NewMonitor();
437
mon2 = PR_NewMonitor();
439
Measure(LocalProcedureCall, "local procedure call overhead");
440
Measure(DLLProcedureCall, "DLL procedure call overhead");
441
Measure(Now, "current calendar time");
442
Measure(Interval, "interval time");
443
Measure(IdleLock, "idle lock lock/unlock pair");
444
Measure(IdleMonitor, "idle monitor entry/exit pair");
445
Measure(IdleCMonitor, "idle cache monitor entry/exit pair");
446
Measure(CDThread, "create/destroy thread pair");
447
Measure(ContextSwitchUU, "context switch - user/user");
448
Measure(ContextSwitchUK, "context switch - user/kernel");
449
Measure(ContextSwitchKU, "context switch - kernel/user");
450
Measure(ContextSwitchKK, "context switch - kernel/kernel");
451
Measure(SemaContextSwitchUU, "sema context switch - user/user");
452
Measure(SemaContextSwitchUK, "sema context switch - user/kernel");
453
Measure(SemaContextSwitchKU, "sema context switch - kernel/user");
454
Measure(SemaContextSwitchKK, "sema context switch - kernel/kernel");
456
printf("--------------\n");
457
printf("Adding 7 additional CPUs\n");
459
PR_SetConcurrency(8);
460
printf("--------------\n");
462
Measure(LocalProcedureCall, "local procedure call overhead");
463
Measure(DLLProcedureCall, "DLL procedure call overhead");
464
Measure(Now, "current calendar time");
465
Measure(Interval, "interval time");
466
Measure(IdleLock, "idle lock lock/unlock pair");
467
Measure(IdleMonitor, "idle monitor entry/exit pair");
468
Measure(IdleCMonitor, "idle cache monitor entry/exit pair");
469
Measure(CDThread, "create/destroy thread pair");
470
Measure(ContextSwitchUU, "context switch - user/user");
471
Measure(ContextSwitchUK, "context switch - user/kernel");
472
Measure(ContextSwitchKU, "context switch - kernel/user");
473
Measure(ContextSwitchKK, "context switch - kernel/kernel");
474
Measure(SemaContextSwitchUU, "sema context switch - user/user");
475
Measure(SemaContextSwitchUK, "sema context switch - user/kernel");
476
Measure(SemaContextSwitchKU, "sema context switch - kernel/user");
477
Measure(SemaContextSwitchKK, "sema context switch - kernel/kernel");
479
PR_DestroyLock(lock);
480
PR_DestroyMonitor(mon);
481
PR_DestroyMonitor(mon2);