michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: sw=4 ts=4 et : 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: #include "TestHarness.h" michael@0: michael@0: //#define OLD_API michael@0: michael@0: #define PASS() \ michael@0: do { \ michael@0: passed(__FUNCTION__); \ michael@0: return NS_OK; \ michael@0: } while (0) michael@0: michael@0: #define FAIL(why) \ michael@0: do { \ michael@0: fail("%s | %s - %s", __FILE__, __FUNCTION__, why); \ michael@0: return NS_ERROR_FAILURE; \ michael@0: } while (0) michael@0: michael@0: #ifdef OLD_API michael@0: # include "nsAutoLock.h" michael@0: typedef PRLock* moz_lock_t; michael@0: # define NEWLOCK(n) nsAutoLock::NewLock(n) michael@0: # define DELETELOCK(v) nsAutoLock::DestroyLock(v) michael@0: # define AUTOLOCK(v, l) nsAutoLock v(l) michael@0: #else michael@0: # include "mozilla/Mutex.h" michael@0: typedef mozilla::Mutex* moz_lock_t; michael@0: # define NEWLOCK(n) new mozilla::Mutex(n) michael@0: # define DELETELOCK(v) delete (v) michael@0: # define AUTOLOCK(v, l) mozilla::MutexAutoLock v(*l) michael@0: #endif michael@0: michael@0: // def/undef these to run particular tests. michael@0: #undef DD_TEST1 michael@0: #undef DD_TEST2 michael@0: #undef DD_TEST3 michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: #ifdef DD_TEST1 michael@0: michael@0: static void michael@0: AllocLockRecurseUnlockFree(int i) michael@0: { michael@0: if (0 == i) michael@0: return; michael@0: michael@0: moz_lock_t lock = NEWLOCK("deadlockDetector.scalability.t1"); michael@0: { michael@0: AUTOLOCK(_, lock); michael@0: AllocLockRecurseUnlockFree(i - 1); michael@0: } michael@0: DELETELOCK(lock); michael@0: } michael@0: michael@0: // This test creates a resource dependency chain N elements long, then michael@0: // frees all the resources in the chain. michael@0: static nsresult michael@0: LengthNDepChain(int N) michael@0: { michael@0: AllocLockRecurseUnlockFree(N); michael@0: PASS(); michael@0: } michael@0: michael@0: #endif michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: #ifdef DD_TEST2 michael@0: michael@0: // This test creates a single lock that is ordered < N resources, then michael@0: // repeatedly exercises this order k times. michael@0: static nsresult michael@0: OneLockNDeps(const int N, const int K) michael@0: { michael@0: moz_lock_t lock = NEWLOCK("deadlockDetector.scalability.t2.master"); michael@0: moz_lock_t* locks = new moz_lock_t[N]; michael@0: if (!locks) michael@0: NS_RUNTIMEABORT("couldn't allocate lock array"); michael@0: michael@0: for (int i = 0; i < N; ++i) michael@0: locks[i] = michael@0: NEWLOCK("deadlockDetector.scalability.t2.dep"); michael@0: michael@0: // establish orders michael@0: {AUTOLOCK(m, lock); michael@0: for (int i = 0; i < N; ++i) michael@0: AUTOLOCK(s, locks[i]); michael@0: } michael@0: michael@0: // exercise order check michael@0: {AUTOLOCK(m, lock); michael@0: for (int i = 0; i < K; ++i) michael@0: for (int j = 0; j < N; ++j) michael@0: AUTOLOCK(s, locks[i]); michael@0: } michael@0: michael@0: for (int i = 0; i < N; ++i) michael@0: DELETELOCK(locks[i]); michael@0: delete[] locks; michael@0: michael@0: PASS(); michael@0: } michael@0: michael@0: #endif michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: #ifdef DD_TEST3 michael@0: michael@0: // This test creates N resources and adds the theoretical maximum number michael@0: // of dependencies, O(N^2). It then repeats that sequence of michael@0: // acquisitions k times. Finally, all resources are freed. michael@0: // michael@0: // It's very difficult to perform well on this test. It's put forth as a michael@0: // challenge problem. michael@0: michael@0: static nsresult michael@0: MaxDepsNsq(const int N, const int K) michael@0: { michael@0: moz_lock_t* locks = new moz_lock_t[N]; michael@0: if (!locks) michael@0: NS_RUNTIMEABORT("couldn't allocate lock array"); michael@0: michael@0: for (int i = 0; i < N; ++i) michael@0: locks[i] = NEWLOCK("deadlockDetector.scalability.t3"); michael@0: michael@0: for (int i = 0; i < N; ++i) { michael@0: AUTOLOCK(al1, locks[i]); michael@0: for (int j = i+1; j < N; ++j) michael@0: AUTOLOCK(al2, locks[j]); michael@0: } michael@0: michael@0: for (int i = 0; i < K; ++i) { michael@0: for (int j = 0; j < N; ++j) { michael@0: AUTOLOCK(al1, locks[j]); michael@0: for (int k = j+1; k < N; ++k) michael@0: AUTOLOCK(al2, locks[k]); michael@0: } michael@0: } michael@0: michael@0: for (int i = 0; i < N; ++i) michael@0: DELETELOCK(locks[i]); michael@0: delete[] locks; michael@0: michael@0: PASS(); michael@0: } michael@0: michael@0: #endif michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: int michael@0: main(int argc, char** argv) michael@0: { michael@0: ScopedXPCOM xpcom("Deadlock detector scalability (" __FILE__ ")"); michael@0: if (xpcom.failed()) michael@0: return 1; michael@0: michael@0: int rv = 0; michael@0: michael@0: // Uncomment these tests to run them. Not expected to be common. michael@0: michael@0: #ifndef DD_TEST1 michael@0: puts("Skipping not-requested LengthNDepChain() test"); michael@0: #else michael@0: if (NS_FAILED(LengthNDepChain(1 << 14))) // 16K michael@0: rv = 1; michael@0: #endif michael@0: michael@0: #ifndef DD_TEST2 michael@0: puts("Skipping not-requested OneLockNDeps() test"); michael@0: #else michael@0: if (NS_FAILED(OneLockNDeps(1 << 14, 100))) // 16k michael@0: rv = 1; michael@0: #endif michael@0: michael@0: #ifndef DD_TEST3 michael@0: puts("Skipping not-requested MaxDepsNsq() test"); michael@0: #else michael@0: if (NS_FAILED(MaxDepsNsq(1 << 10, 10))) // 1k michael@0: rv = 1; michael@0: #endif michael@0: michael@0: return rv; michael@0: }