michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: ** File: lockfile.c michael@0: ** Purpose: test basic locking functions michael@0: ** Just because this times stuff, don't think its a perforamnce michael@0: ** test!!! michael@0: ** michael@0: ** Modification History: michael@0: ** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. michael@0: ** The debug mode will print all of the printfs associated with this test. michael@0: ** The regress mode will be the default mode. Since the regress tool limits michael@0: ** the output to a one line status:PASS or FAIL,all of the printf statements michael@0: ** have been handled with an if (debug_mode) statement. michael@0: ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to michael@0: ** recognize the return code from tha main program. michael@0: ***********************************************************************/ michael@0: /*********************************************************************** michael@0: ** Includes michael@0: ***********************************************************************/ michael@0: /* Used to get the command line option */ michael@0: #include "plgetopt.h" michael@0: michael@0: #include "prcmon.h" michael@0: #include "prerror.h" michael@0: #include "prinit.h" michael@0: #include "prinrval.h" michael@0: #include "prlock.h" michael@0: #include "prlog.h" michael@0: #include "prmon.h" michael@0: #include "prthread.h" michael@0: #include "prtypes.h" michael@0: michael@0: #include "private/pprio.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: PRIntn failed_already=0; michael@0: PRIntn debug_mode; michael@0: michael@0: const static PRIntervalTime contention_interval = 50; michael@0: michael@0: typedef struct LockContentious_s { michael@0: PRLock *ml; michael@0: PRInt32 loops; michael@0: PRIntervalTime overhead; michael@0: PRIntervalTime interval; michael@0: } LockContentious_t; michael@0: michael@0: #define LOCKFILE "prlock.fil" michael@0: michael@0: michael@0: michael@0: static PRIntervalTime NonContentiousLock(PRInt32 loops) michael@0: { michael@0: PRFileDesc *_lockfile; michael@0: while (loops-- > 0) michael@0: { michael@0: _lockfile = PR_Open(LOCKFILE, PR_CREATE_FILE|PR_RDWR, 0666); michael@0: if (!_lockfile) { michael@0: if (debug_mode) printf( michael@0: "could not create lockfile: %d [%d]\n", michael@0: PR_GetError(), PR_GetOSError()); michael@0: return PR_INTERVAL_NO_TIMEOUT; michael@0: } michael@0: PR_LockFile(_lockfile); michael@0: PR_UnlockFile(_lockfile); michael@0: PR_Close(_lockfile); michael@0: } michael@0: return 0; michael@0: } /* NonContentiousLock */ michael@0: michael@0: static void PR_CALLBACK LockContender(void *arg) michael@0: { michael@0: LockContentious_t *contention = (LockContentious_t*)arg; michael@0: PRFileDesc *_lockfile; michael@0: while (contention->loops-- > 0) michael@0: { michael@0: _lockfile = PR_Open(LOCKFILE, PR_CREATE_FILE|PR_RDWR, 0666); michael@0: if (!_lockfile) { michael@0: if (debug_mode) printf( michael@0: "could not create lockfile: %d [%d]\n", michael@0: PR_GetError(), PR_GetOSError()); michael@0: break; michael@0: } michael@0: PR_LockFile(_lockfile); michael@0: PR_Sleep(contention->interval); michael@0: PR_UnlockFile(_lockfile); michael@0: PR_Close(_lockfile); michael@0: } michael@0: michael@0: } /* LockContender */ michael@0: michael@0: /* michael@0: ** Win16 requires things passed to Threads not be on the stack michael@0: */ michael@0: static LockContentious_t contention; michael@0: michael@0: static PRIntervalTime ContentiousLock(PRInt32 loops) michael@0: { michael@0: PRStatus status; michael@0: PRThread *thread = NULL; michael@0: PRIntervalTime overhead, timein = PR_IntervalNow(); michael@0: michael@0: contention.loops = loops; michael@0: contention.overhead = 0; michael@0: contention.ml = PR_NewLock(); michael@0: contention.interval = contention_interval; michael@0: thread = PR_CreateThread( michael@0: PR_USER_THREAD, LockContender, &contention, michael@0: PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); michael@0: PR_ASSERT(thread != NULL); michael@0: michael@0: overhead = PR_IntervalNow() - timein; michael@0: michael@0: while (contention.loops > 0) michael@0: { michael@0: PR_Lock(contention.ml); michael@0: contention.overhead += contention.interval; michael@0: PR_Sleep(contention.interval); michael@0: PR_Unlock(contention.ml); michael@0: } michael@0: michael@0: timein = PR_IntervalNow(); michael@0: status = PR_JoinThread(thread); michael@0: PR_DestroyLock(contention.ml); michael@0: overhead += (PR_IntervalNow() - timein); michael@0: return overhead + contention.overhead; michael@0: } /* ContentiousLock */ michael@0: michael@0: static PRIntervalTime Test( michael@0: const char* msg, PRIntervalTime (*test)(PRInt32 loops), michael@0: PRInt32 loops, PRIntervalTime overhead) michael@0: { michael@0: /* michael@0: * overhead - overhead not measured by the test. michael@0: * duration - wall clock time it took to perform test. michael@0: * predicted - extra time test says should not be counted michael@0: * michael@0: * Time accountable to the test is duration - overhead - predicted michael@0: * All times are Intervals and accumulated for all iterations. michael@0: */ michael@0: PRFloat64 elapsed; michael@0: PRIntervalTime accountable, duration; michael@0: PRUintn spaces = strlen(msg); michael@0: PRIntervalTime timeout, timein = PR_IntervalNow(); michael@0: PRIntervalTime predicted = test(loops); michael@0: timeout = PR_IntervalNow(); michael@0: duration = timeout - timein; michael@0: accountable = duration - predicted; michael@0: accountable -= overhead; michael@0: elapsed = (PRFloat64)PR_IntervalToMicroseconds(accountable); michael@0: if (debug_mode) printf("%s:", msg); michael@0: while (spaces++ < 50) if (debug_mode) printf(" "); michael@0: if ((PRInt32)accountable < 0) { michael@0: if (debug_mode) printf("*****.** usecs/iteration\n"); michael@0: } else { michael@0: if (debug_mode) printf("%8.2f usecs/iteration\n", elapsed/loops); michael@0: } michael@0: return duration; michael@0: } /* Test */ michael@0: michael@0: int main(int argc, char **argv) michael@0: { michael@0: PRIntervalTime duration; michael@0: PRUint32 cpu, cpus = 2; michael@0: PRInt32 loops = 100; michael@0: michael@0: michael@0: /* The command line argument: -d is used to determine if the test is being run michael@0: in debug mode. The regress tool requires only one line output:PASS or FAIL. michael@0: All of the printfs associated with this test has been handled with a if (debug_mode) michael@0: test. michael@0: Usage: test_name -d michael@0: */ michael@0: PLOptStatus os; michael@0: PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); michael@0: while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) michael@0: { michael@0: if (PL_OPT_BAD == os) continue; michael@0: switch (opt->option) michael@0: { michael@0: case 'd': /* debug mode */ michael@0: debug_mode = 1; michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: PL_DestroyOptState(opt); michael@0: michael@0: /* main test */ michael@0: michael@0: PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); michael@0: PR_STDIO_INIT(); michael@0: michael@0: if (argc > 1) loops = atoi(argv[1]); michael@0: if (loops == 0) loops = 100; michael@0: if (debug_mode) printf("Lock: Using %d loops\n", loops); michael@0: michael@0: cpus = (argc < 3) ? 2 : atoi(argv[2]); michael@0: if (cpus == 0) cpus = 2; michael@0: if (debug_mode) printf("Lock: Using %d cpu(s)\n", cpus); michael@0: michael@0: michael@0: for (cpu = 1; cpu <= cpus; ++cpu) michael@0: { michael@0: if (debug_mode) printf("\nLockFile: Using %d CPU(s)\n", cpu); michael@0: PR_SetConcurrency(cpu); michael@0: michael@0: duration = Test("LockFile non-contentious locking/unlocking", NonContentiousLock, loops, 0); michael@0: (void)Test("LockFile contentious locking/unlocking", ContentiousLock, loops, duration); michael@0: } michael@0: michael@0: PR_Delete(LOCKFILE); /* try to get rid of evidence */ michael@0: michael@0: if (debug_mode) printf("%s: test %s\n", "Lock(mutex) test", ((failed_already) ? "failed" : "passed")); michael@0: if(failed_already) michael@0: return 1; michael@0: else michael@0: return 0; michael@0: } /* main */ michael@0: michael@0: /* testlock.c */