tsan: improve deadlock detector test

- allow to specify which test to run
- allow to specify number of iterations
- specify number of threads required in the test itself

llvm-svn: 202358
This commit is contained in:
Dmitry Vyukov 2014-02-27 08:04:20 +00:00
parent a9a1d27677
commit c546943b6a
1 changed files with 51 additions and 18 deletions

View File

@ -9,8 +9,17 @@
#include <pthread.h>
#undef NDEBUG
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#ifndef LockType
#define LockType PthreadMutex
#endif
// You can optionally pass [test_number [iter_count]] on command line.
static int test_number = -1;
static int iter_count = 100000;
class PthreadMutex {
public:
explicit PthreadMutex(bool recursive = false) {
@ -88,8 +97,10 @@ class PthreadRWLock {
class LockTest {
public:
explicit LockTest(size_t n)
: n_(n), locks_(new LockType*[n]) {
LockTest() : n_(), locks_() {}
void Init(size_t n) {
n_ = n;
locks_ = new LockType*[n_];
for (size_t i = 0; i < n_; i++)
locks_[i] = new LockType;
}
@ -130,8 +141,10 @@ class LockTest {
// Simple lock order onversion.
void Test1() {
if (test_number > 0 && test_number != 1) return;
fprintf(stderr, "Starting Test1\n");
// CHECK: Starting Test1
Init(5);
fprintf(stderr, "Expecting lock inversion: %p %p\n", A(0), A(1));
// CHECK: Expecting lock inversion: [[A1:0x[a-f0-9]*]] [[A2:0x[a-f0-9]*]]
Lock_0_1();
@ -145,8 +158,10 @@ class LockTest {
// Simple lock order inversion with 3 locks.
void Test2() {
if (test_number > 0 && test_number != 2) return;
fprintf(stderr, "Starting Test2\n");
// CHECK: Starting Test2
Init(5);
fprintf(stderr, "Expecting lock inversion: %p %p %p\n", A(0), A(1), A(2));
// CHECK: Expecting lock inversion: [[A1:0x[a-f0-9]*]] [[A2:0x[a-f0-9]*]] [[A3:0x[a-f0-9]*]]
Lock2(0, 1);
@ -164,8 +179,10 @@ class LockTest {
// between. Since the new locks are not used we should still detect the
// deadlock.
void Test3() {
if (test_number > 0 && test_number != 3) return;
fprintf(stderr, "Starting Test3\n");
// CHECK: Starting Test3
Init(5);
Lock_0_1();
L(2);
CreateAndDestroyManyLocks();
@ -178,8 +195,10 @@ class LockTest {
// lock l0=>l1; then create and use lots of locks; then lock l1=>l0.
// The deadlock epoch should have changed and we should not report anything.
void Test4() {
if (test_number > 0 && test_number != 4) return;
fprintf(stderr, "Starting Test4\n");
// CHECK: Starting Test4
Init(5);
Lock_0_1();
L(2);
CreateLockUnlockAndDestroyManyLocks();
@ -189,24 +208,30 @@ class LockTest {
}
void Test5() {
if (test_number > 0 && test_number != 5) return;
fprintf(stderr, "Starting Test5\n");
// CHECK: Starting Test5
Init(5);
RunThreads(&LockTest::Lock_0_1, &LockTest::Lock_1_0);
// CHECK: WARNING: ThreadSanitizer: lock-order-inversion
// CHECK-NOT: WARNING: ThreadSanitizer:
}
void Test6() {
fprintf(stderr, "Starting Test6\n");
if (test_number > 0 && test_number != 6) return;
fprintf(stderr, "Starting Test6: 3 threads lock/unlock private mutexes\n");
// CHECK: Starting Test6
Init(100);
// CHECK-NOT: WARNING: ThreadSanitizer:
RunThreads(&LockTest::Lock1_Loop_0, &LockTest::Lock1_Loop_1,
&LockTest::Lock1_Loop_2);
}
void Test7() {
if (test_number > 0 && test_number != 7) return;
fprintf(stderr, "Starting Test7\n");
// CHECK: Starting Test7
Init(10);
L(0); T(1); U(1); U(0);
T(1); L(0); U(1); U(0);
// CHECK-NOT: WARNING: ThreadSanitizer:
@ -233,8 +258,10 @@ class LockTest {
}
void Test8() {
if (test_number > 0 && test_number != 8) return;
if (!LockType::supports_read_lock()) return;
fprintf(stderr, "Starting Test8\n");
Init(5);
// CHECK-RD: Starting Test8
RL(0); L(1); RU(0); U(1);
L(1); RL(0); RU(0); U(1);
@ -250,9 +277,11 @@ class LockTest {
}
void Test9() {
if (test_number > 0 && test_number != 9) return;
if (!LockType::supports_recursive_lock()) return;
fprintf(stderr, "Starting Test9\n");
// CHECK-REC: Starting Test9
Init(5);
L(0); L(0); L(0); L(1); U(1); U(0); U(0); U(0);
L(1); L(1); L(1); L(0); U(0); U(1); U(1); U(1);
// CHECK-REC: WARNING: ThreadSanitizer: lock-order-inversion
@ -270,9 +299,9 @@ class LockTest {
}
// fprintf(stderr, "\n");
}
void Lock1_Loop_0() { Lock1_Loop(0, 100000); }
void Lock1_Loop_1() { Lock1_Loop(10, 100000); }
void Lock1_Loop_2() { Lock1_Loop(20, 100000); }
void Lock1_Loop_0() { Lock1_Loop(0, iter_count); }
void Lock1_Loop_1() { Lock1_Loop(10, iter_count); }
void Lock1_Loop_2() { Lock1_Loop(20, iter_count); }
void CreateAndDestroyManyLocks() {
LockType create_many_locks_but_never_acquire[kDeadlockGraphSize];
@ -317,17 +346,21 @@ class LockTest {
LockType **locks_;
};
int main() {
{ LockTest t(5); t.Test1(); }
{ LockTest t(5); t.Test2(); }
{ LockTest t(5); t.Test3(); }
{ LockTest t(5); t.Test4(); }
{ LockTest t(5); t.Test5(); }
{ LockTest t(100); t.Test6(); }
{ LockTest t(10); t.Test7(); }
{ LockTest t(5); t.Test8(); }
{ LockTest t(5); t.Test9(); }
fprintf(stderr, "DONE\n");
// CHECK: DONE
int main(int argc, char **argv) {
if (argc > 1)
test_number = atoi(argv[1]);
if (argc > 2)
iter_count = atoi(argv[2]);
LockTest().Test1();
LockTest().Test2();
LockTest().Test3();
LockTest().Test4();
LockTest().Test5();
LockTest().Test6();
LockTest().Test7();
LockTest().Test8();
LockTest().Test9();
fprintf(stderr, "ALL-DONE\n");
// CHECK: ALL-DONE
}