1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: sw=4 ts=4 et :
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 1998
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Chris Jones <jones.chris.g@gmail.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "TestHarness.h"
41 :
42 : //#define OLD_API
43 :
44 : #define PASS() \
45 : do { \
46 : passed(__FUNCTION__); \
47 : return NS_OK; \
48 : } while (0)
49 :
50 : #define FAIL(why) \
51 : do { \
52 : fail("%s | %s - %s", __FILE__, __FUNCTION__, why); \
53 : return NS_ERROR_FAILURE; \
54 : } while (0)
55 :
56 : #ifdef OLD_API
57 : # include "nsAutoLock.h"
58 : typedef PRLock* moz_lock_t;
59 : # define NEWLOCK(n) nsAutoLock::NewLock(n)
60 : # define DELETELOCK(v) nsAutoLock::DestroyLock(v)
61 : # define AUTOLOCK(v, l) nsAutoLock v(l)
62 : #else
63 : # include "mozilla/Mutex.h"
64 : typedef mozilla::Mutex* moz_lock_t;
65 : # define NEWLOCK(n) new mozilla::Mutex(n)
66 : # define DELETELOCK(v) delete (v)
67 : # define AUTOLOCK(v, l) mozilla::MutexAutoLock v(*l)
68 : #endif
69 :
70 : // def/undef these to run particular tests.
71 : #undef DD_TEST1
72 : #undef DD_TEST2
73 : #undef DD_TEST3
74 :
75 : //-----------------------------------------------------------------------------
76 :
77 : #ifdef DD_TEST1
78 :
79 : static void
80 : AllocLockRecurseUnlockFree(int i)
81 : {
82 : if (0 == i)
83 : return;
84 :
85 : moz_lock_t lock = NEWLOCK("deadlockDetector.scalability.t1");
86 : {
87 : AUTOLOCK(_, lock);
88 : AllocLockRecurseUnlockFree(i - 1);
89 : }
90 : DELETELOCK(lock);
91 : }
92 :
93 : // This test creates a resource dependency chain N elements long, then
94 : // frees all the resources in the chain.
95 : static nsresult
96 : LengthNDepChain(int N)
97 : {
98 : AllocLockRecurseUnlockFree(N);
99 : PASS();
100 : }
101 :
102 : #endif
103 :
104 : //-----------------------------------------------------------------------------
105 :
106 : #ifdef DD_TEST2
107 :
108 : // This test creates a single lock that is ordered < N resources, then
109 : // repeatedly exercises this order k times.
110 : static nsresult
111 : OneLockNDeps(const int N, const int K)
112 : {
113 : moz_lock_t lock = NEWLOCK("deadlockDetector.scalability.t2.master");
114 : moz_lock_t* locks = new moz_lock_t[N];
115 : if (!locks)
116 : NS_RUNTIMEABORT("couldn't allocate lock array");
117 :
118 : for (int i = 0; i < N; ++i)
119 : locks[i] =
120 : NEWLOCK("deadlockDetector.scalability.t2.dep");
121 :
122 : // establish orders
123 : {AUTOLOCK(m, lock);
124 : for (int i = 0; i < N; ++i)
125 : AUTOLOCK(s, locks[i]);
126 : }
127 :
128 : // exercise order check
129 : {AUTOLOCK(m, lock);
130 : for (int i = 0; i < K; ++i)
131 : for (int j = 0; j < N; ++j)
132 : AUTOLOCK(s, locks[i]);
133 : }
134 :
135 : for (int i = 0; i < N; ++i)
136 : DELETELOCK(locks[i]);
137 : delete[] locks;
138 :
139 : PASS();
140 : }
141 :
142 : #endif
143 :
144 : //-----------------------------------------------------------------------------
145 :
146 : #ifdef DD_TEST3
147 :
148 : // This test creates N resources and adds the theoretical maximum number
149 : // of dependencies, O(N^2). It then repeats that sequence of
150 : // acquisitions k times. Finally, all resources are freed.
151 : //
152 : // It's very difficult to perform well on this test. It's put forth as a
153 : // challenge problem.
154 :
155 : static nsresult
156 : MaxDepsNsq(const int N, const int K)
157 : {
158 : moz_lock_t* locks = new moz_lock_t[N];
159 : if (!locks)
160 : NS_RUNTIMEABORT("couldn't allocate lock array");
161 :
162 : for (int i = 0; i < N; ++i)
163 : locks[i] = NEWLOCK("deadlockDetector.scalability.t3");
164 :
165 : for (int i = 0; i < N; ++i) {
166 : AUTOLOCK(al1, locks[i]);
167 : for (int j = i+1; j < N; ++j)
168 : AUTOLOCK(al2, locks[j]);
169 : }
170 :
171 : for (int i = 0; i < K; ++i) {
172 : for (int j = 0; j < N; ++j) {
173 : AUTOLOCK(al1, locks[j]);
174 : for (int k = j+1; k < N; ++k)
175 : AUTOLOCK(al2, locks[k]);
176 : }
177 : }
178 :
179 : for (int i = 0; i < N; ++i)
180 : DELETELOCK(locks[i]);
181 : delete[] locks;
182 :
183 : PASS();
184 : }
185 :
186 : #endif
187 :
188 : //-----------------------------------------------------------------------------
189 :
190 : int
191 1 : main(int argc, char** argv)
192 : {
193 2 : ScopedXPCOM xpcom("Deadlock detector scalability (" __FILE__ ")");
194 1 : if (xpcom.failed())
195 0 : return 1;
196 :
197 1 : int rv = 0;
198 :
199 : // Uncomment these tests to run them. Not expected to be common.
200 :
201 : #ifndef DD_TEST1
202 1 : puts("Skipping not-requested LengthNDepChain() test");
203 : #else
204 : if (NS_FAILED(LengthNDepChain(1 << 14))) // 16K
205 : rv = 1;
206 : #endif
207 :
208 : #ifndef DD_TEST2
209 1 : puts("Skipping not-requested OneLockNDeps() test");
210 : #else
211 : if (NS_FAILED(OneLockNDeps(1 << 14, 100))) // 16k
212 : rv = 1;
213 : #endif
214 :
215 : #ifndef DD_TEST3
216 1 : puts("Skipping not-requested MaxDepsNsq() test");
217 : #else
218 : if (NS_FAILED(MaxDepsNsq(1 << 10, 10))) // 1k
219 : rv = 1;
220 : #endif
221 :
222 1 : return rv;
223 : }
|