зеркало из https://github.com/mozilla/gecko-dev.git
164 строки
4.6 KiB
C++
164 строки
4.6 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
* vim: sw=2 ts=4 et :
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
// Avoid DMD-specific parts of MOZ_DEFINE_MALLOC_SIZE_OF
|
|
#undef MOZ_DMD
|
|
|
|
#include "nsIMemoryReporter.h"
|
|
#include "mozilla/Mutex.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static void AllocLockRecurseUnlockFree(int i) {
|
|
if (0 == i) return;
|
|
|
|
mozilla::Mutex* lock = new mozilla::Mutex("deadlockDetector.scalability.t1");
|
|
{
|
|
mozilla::MutexAutoLock _(*lock);
|
|
AllocLockRecurseUnlockFree(i - 1);
|
|
}
|
|
delete lock;
|
|
}
|
|
|
|
// This test creates a resource dependency chain N elements long, then
|
|
// frees all the resources in the chain.
|
|
TEST(DeadlockDetectorScalability, LengthNDepChain)
|
|
{
|
|
const int N = 1 << 14; // 16K
|
|
AllocLockRecurseUnlockFree(N);
|
|
ASSERT_TRUE(true);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// This test creates a single lock that is ordered < N resources, then
|
|
// repeatedly exercises this order k times.
|
|
//
|
|
// NB: It takes a minute or two to run so it is disabled by default.
|
|
TEST(DeadlockDetectorScalability, DISABLED_OneLockNDeps)
|
|
{
|
|
// NB: Using a larger test size to stress our traversal logic.
|
|
const int N = 1 << 17; // 131k
|
|
const int K = 100;
|
|
|
|
mozilla::Mutex* lock =
|
|
new mozilla::Mutex("deadlockDetector.scalability.t2.master");
|
|
mozilla::Mutex** locks = new mozilla::Mutex*[N];
|
|
if (!locks) MOZ_CRASH("couldn't allocate lock array");
|
|
|
|
for (int i = 0; i < N; ++i)
|
|
locks[i] = new mozilla::Mutex("deadlockDetector.scalability.t2.dep");
|
|
|
|
// establish orders
|
|
{
|
|
mozilla::MutexAutoLock m(*lock);
|
|
for (int i = 0; i < N; ++i) mozilla::MutexAutoLock s(*locks[i]);
|
|
}
|
|
|
|
// exercise order check
|
|
{
|
|
mozilla::MutexAutoLock m(*lock);
|
|
for (int i = 0; i < K; ++i)
|
|
for (int j = 0; j < N; ++j) mozilla::MutexAutoLock s(*locks[i]);
|
|
}
|
|
|
|
for (int i = 0; i < N; ++i) delete locks[i];
|
|
delete[] locks;
|
|
|
|
ASSERT_TRUE(true);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// This test creates N resources and adds the theoretical maximum number
|
|
// of dependencies, O(N^2). It then repeats that sequence of
|
|
// acquisitions k times. Finally, all resources are freed.
|
|
//
|
|
// It's very difficult to perform well on this test. It's put forth as a
|
|
// challenge problem.
|
|
|
|
TEST(DeadlockDetectorScalability, MaxDepsNsq)
|
|
{
|
|
const int N = 1 << 10; // 1k
|
|
const int K = 10;
|
|
|
|
mozilla::Mutex** locks = new mozilla::Mutex*[N];
|
|
if (!locks) MOZ_CRASH("couldn't allocate lock array");
|
|
|
|
for (int i = 0; i < N; ++i)
|
|
locks[i] = new mozilla::Mutex("deadlockDetector.scalability.t3");
|
|
|
|
for (int i = 0; i < N; ++i) {
|
|
mozilla::MutexAutoLock al1(*locks[i]);
|
|
for (int j = i + 1; j < N; ++j) mozilla::MutexAutoLock al2(*locks[j]);
|
|
}
|
|
|
|
for (int i = 0; i < K; ++i) {
|
|
for (int j = 0; j < N; ++j) {
|
|
mozilla::MutexAutoLock al1(*locks[j]);
|
|
for (int k = j + 1; k < N; ++k) mozilla::MutexAutoLock al2(*locks[k]);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < N; ++i) delete locks[i];
|
|
delete[] locks;
|
|
|
|
ASSERT_TRUE(true);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// This test creates a single lock that is ordered < N resources. The
|
|
// resources are allocated, exercised K times, and deallocated one at
|
|
// a time.
|
|
|
|
TEST(DeadlockDetectorScalability, OneLockNDepsUsedSeveralTimes)
|
|
{
|
|
const size_t N = 1 << 17; // 131k
|
|
const size_t K = 3;
|
|
|
|
// Create master lock.
|
|
mozilla::Mutex* lock_1 =
|
|
new mozilla::Mutex("deadlockDetector.scalability.t4.master");
|
|
for (size_t n = 0; n < N; n++) {
|
|
// Create child lock.
|
|
mozilla::Mutex* lock_2 =
|
|
new mozilla::Mutex("deadlockDetector.scalability.t4.child");
|
|
|
|
// First lock the master.
|
|
mozilla::MutexAutoLock m(*lock_1);
|
|
|
|
// Now lock and unlock the child a few times.
|
|
for (size_t k = 0; k < K; k++) {
|
|
mozilla::MutexAutoLock c(*lock_2);
|
|
}
|
|
|
|
// Destroy the child lock.
|
|
delete lock_2;
|
|
}
|
|
|
|
// Cleanup the master lock.
|
|
delete lock_1;
|
|
|
|
ASSERT_TRUE(true);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
MOZ_DEFINE_MALLOC_SIZE_OF(DeadlockDetectorMallocSizeOf)
|
|
|
|
// This is a simple test that exercises the deadlock detector memory reporting
|
|
// functionality.
|
|
TEST(DeadlockDetectorScalability, SizeOf)
|
|
{
|
|
size_t memory_used = mozilla::BlockingResourceBase::SizeOfDeadlockDetector(
|
|
DeadlockDetectorMallocSizeOf);
|
|
|
|
ASSERT_GT(memory_used, size_t(0));
|
|
}
|