1 package org.apache.maven.surefire.junitcore;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.surefire.junitcore.pc.ParallelComputer;
23 import org.apache.maven.surefire.junitcore.pc.ParallelComputerBuilder;
24 import org.apache.maven.surefire.testset.TestSetFailedException;
25
26
27
28
29
30
31
32
33
34
35 final class ParallelComputerFactory
36 {
37 private static int availableProcessors = Runtime.getRuntime().availableProcessors();
38
39 static class Concurrency
40 {
41 int suites, classes, methods, capacity;
42 }
43
44 private ParallelComputerFactory()
45 {
46 throw new IllegalStateException("Suppresses calling constructor, ensuring non-instantiability.");
47 }
48
49
50
51
52 static void overrideAvailableProcessors( int availableProcessors )
53 {
54 ParallelComputerFactory.availableProcessors = availableProcessors;
55 }
56
57
58
59
60 static void setDefaultAvailableProcessors()
61 {
62 ParallelComputerFactory.availableProcessors = Runtime.getRuntime().availableProcessors();
63 }
64
65 static ParallelComputer createParallelComputer( JUnitCoreParameters params ) throws TestSetFailedException
66 {
67 Concurrency concurrency = resolveConcurrency( params );
68 ParallelComputerBuilder builder = new ParallelComputerBuilder();
69
70 if ( params.isParallelSuites() )
71 {
72 resolveSuitesConcurrency( builder, concurrency.suites );
73 }
74
75 if ( params.isParallelClasses() )
76 {
77 resolveClassesConcurrency( builder, concurrency.classes );
78 }
79
80 if ( params.isParallelMethod() )
81 {
82 resolveMethodsConcurrency( builder, concurrency.methods );
83 }
84
85 resolveCapacity( builder, concurrency.capacity );
86 return builder.buildComputer();
87 }
88
89 static Concurrency resolveConcurrency( JUnitCoreParameters params ) throws TestSetFailedException
90 {
91 if ( !params.isAnyParallelitySelected() )
92 {
93 throw new TestSetFailedException( "Unspecified parameter '" + JUnitCoreParameters.PARALLEL_KEY + "'." );
94 }
95
96 if ( !params.isUseUnlimitedThreads() && !hasThreadCount( params ) && !hasThreadCounts( params ) )
97 {
98 throw new TestSetFailedException( "Unspecified thread-count(s). " +
99 "See the parameters " + JUnitCoreParameters.USEUNLIMITEDTHREADS_KEY + ", "
100 + JUnitCoreParameters.THREADCOUNT_KEY + ", " + JUnitCoreParameters.THREADCOUNTSUITES_KEY + ", "
101 + JUnitCoreParameters.THREADCOUNTCLASSES_KEY + ", " + JUnitCoreParameters.THREADCOUNTMETHODS_KEY + ".");
102 }
103
104 if ( params.isUseUnlimitedThreads() )
105 {
106 return concurrencyForUnlimitedThreads( params );
107 }
108 else
109 {
110 if ( hasThreadCount( params ) )
111 {
112 if ( hasThreadCounts( params ) )
113 {
114 return isLeafUnspecified( params ) ?
115 concurrencyFromAllThreadCountsButUnspecifiedLeafCount( params ) :
116 concurrencyFromAllThreadCounts( params );
117 }
118 else
119 {
120 return estimateConcurrency( params );
121 }
122 }
123 else
124 {
125 return concurrencyFromThreadCounts( params );
126 }
127 }
128 }
129
130 private static void resolveSuitesConcurrency( ParallelComputerBuilder builder, int concurrency )
131 {
132 if ( concurrency > 0 )
133 {
134 if ( concurrency == Integer.MAX_VALUE )
135 {
136 builder.parallelSuites();
137 }
138 else
139 {
140 builder.parallelSuites( concurrency );
141 }
142 }
143 }
144
145 private static void resolveClassesConcurrency( ParallelComputerBuilder builder, int concurrency )
146 {
147 if ( concurrency > 0 )
148 {
149 if ( concurrency == Integer.MAX_VALUE )
150 {
151 builder.parallelClasses();
152 }
153 else
154 {
155 builder.parallelClasses( concurrency );
156 }
157 }
158 }
159
160 private static void resolveMethodsConcurrency( ParallelComputerBuilder builder, int concurrency )
161 {
162 if ( concurrency > 0 )
163 {
164 if ( concurrency == Integer.MAX_VALUE )
165 {
166 builder.parallelMethods();
167 }
168 else
169 {
170 builder.parallelMethods( concurrency );
171 }
172 }
173 }
174
175 private static void resolveCapacity( ParallelComputerBuilder builder, int capacity )
176 {
177 if ( capacity > 0 )
178 {
179 builder.useOnePool( capacity );
180 }
181 }
182
183 private static Concurrency concurrencyForUnlimitedThreads( JUnitCoreParameters params )
184 {
185 Concurrency concurrency = new Concurrency();
186 concurrency.suites = params.isParallelSuites() ? threadCountSuites( params ) : 0;
187 concurrency.classes = params.isParallelClasses() ? threadCountClasses( params ) : 0;
188 concurrency.methods = params.isParallelMethod() ? threadCountMethods( params ) : 0;
189 concurrency.capacity = Integer.MAX_VALUE;
190 return concurrency;
191 }
192
193 private static Concurrency estimateConcurrency( JUnitCoreParameters params )
194 {
195 Concurrency concurrency = new Concurrency();
196 concurrency.suites = params.isParallelSuites() ? params.getThreadCountSuites() : 0;
197 concurrency.classes = params.isParallelClasses() ? params.getThreadCountClasses() : 0;
198 concurrency.methods = params.isParallelMethod() ? params.getThreadCountMethods() : 0;
199 concurrency.capacity = params.getThreadCount();
200
201
202 double ratio = 1d / countParallelEntities( params );
203 int threads = multiplyByCoreCount( params, ratio * concurrency.capacity );
204 concurrency.suites = params.isParallelSuites() ? threads : 0;
205 concurrency.classes = params.isParallelClasses() ? threads : 0;
206 concurrency.methods = params.isParallelMethod() ? threads : 0;
207 if ( countParallelEntities( params ) == 1 )
208 {
209 concurrency.capacity = 0;
210 }
211 else
212 {
213 concurrency.capacity = multiplyByCoreCount( params, concurrency.capacity );
214 adjustLeaf( params, concurrency );
215 }
216 return concurrency;
217 }
218
219 private static Concurrency concurrencyFromAllThreadCountsButUnspecifiedLeafCount( JUnitCoreParameters params )
220 {
221 Concurrency concurrency = new Concurrency();
222 concurrency.suites = params.isParallelSuites() ? params.getThreadCountSuites() : 0;
223 concurrency.classes = params.isParallelClasses() ? params.getThreadCountClasses() : 0;
224 concurrency.methods = params.isParallelMethod() ? params.getThreadCountMethods() : 0;
225 concurrency.capacity = params.getThreadCount();
226
227 setLeafInfinite( params, concurrency );
228 concurrency.suites = params.isParallelSuites() ? multiplyByCoreCount( params, concurrency.suites ) : 0;
229 concurrency.classes = params.isParallelClasses() ? multiplyByCoreCount( params, concurrency.classes ) : 0;
230 concurrency.methods = params.isParallelMethod() ? multiplyByCoreCount( params, concurrency.methods ) : 0;
231 concurrency.capacity = multiplyByCoreCount( params, concurrency.capacity );
232
233 return concurrency;
234 }
235
236 private static Concurrency concurrencyFromAllThreadCounts( JUnitCoreParameters params )
237 {
238 Concurrency concurrency = new Concurrency();
239 concurrency.suites = params.isParallelSuites() ? params.getThreadCountSuites() : 0;
240 concurrency.classes = params.isParallelClasses() ? params.getThreadCountClasses() : 0;
241 concurrency.methods = params.isParallelMethod() ? params.getThreadCountMethods() : 0;
242 concurrency.capacity = params.getThreadCount();
243 double all = sumThreadCounts( concurrency );
244
245 concurrency.suites = params.isParallelSuites() ?
246 multiplyByCoreCount( params, concurrency.capacity * ( concurrency.suites / all ) ) : 0;
247
248 concurrency.classes = params.isParallelClasses() ?
249 multiplyByCoreCount( params, concurrency.capacity * ( concurrency.classes / all ) ) : 0;
250
251 concurrency.methods = params.isParallelMethod() ?
252 multiplyByCoreCount( params, concurrency.capacity * ( concurrency.methods / all ) ) : 0;
253
254 concurrency.capacity = multiplyByCoreCount( params, concurrency.capacity );
255 adjustPrecisionInLeaf( params, concurrency );
256 return concurrency;
257 }
258
259 private static Concurrency concurrencyFromThreadCounts( JUnitCoreParameters params )
260 {
261 Concurrency concurrency = new Concurrency();
262 concurrency.suites = params.isParallelSuites() ? threadCountSuites( params ) : 0;
263 concurrency.classes = params.isParallelClasses() ? threadCountClasses( params ) : 0;
264 concurrency.methods = params.isParallelMethod() ? threadCountMethods( params ) : 0 ;
265 concurrency.capacity = (int) Math.min( sumThreadCounts( concurrency ), Integer.MAX_VALUE );
266 return concurrency;
267 }
268
269 private static int countParallelEntities( JUnitCoreParameters params )
270 {
271 int count = 0;
272 if ( params.isParallelSuites() ) count++;
273 if ( params.isParallelClasses() ) count++;
274 if ( params.isParallelMethod() ) count++;
275 return count;
276 }
277
278 private static void adjustPrecisionInLeaf( JUnitCoreParameters params, Concurrency concurrency )
279 {
280 if ( params.isParallelMethod() )
281 {
282 concurrency.methods = concurrency.capacity - concurrency.suites - concurrency.classes;
283 }
284 else if ( params.isParallelClasses() )
285 {
286 concurrency.classes = concurrency.capacity - concurrency.suites;
287 }
288 }
289
290 private static void adjustLeaf( JUnitCoreParameters params, Concurrency concurrency )
291 {
292 if ( params.isParallelMethod() )
293 {
294 concurrency.methods = Integer.MAX_VALUE;
295 }
296 else if ( params.isParallelClasses() )
297 {
298 concurrency.classes = Integer.MAX_VALUE;
299 }
300 }
301
302 private static void setLeafInfinite( JUnitCoreParameters params, Concurrency concurrency )
303 {
304 if ( params.isParallelMethod() ) concurrency.methods = Integer.MAX_VALUE;
305 else if ( params.isParallelClasses() ) concurrency.classes = Integer.MAX_VALUE;
306 else if ( params.isParallelSuites() ) concurrency.suites = Integer.MAX_VALUE;
307 }
308
309 private static boolean isLeafUnspecified( JUnitCoreParameters params )
310 {
311 int maskOfParallel = params.isParallelSuites() ? 4: 0;
312 maskOfParallel |= params.isParallelClasses() ? 2 : 0;
313 maskOfParallel |= params.isParallelMethod() ? 1 : 0;
314
315 int maskOfConcurrency = params.getThreadCountSuites() > 0 ? 4 : 0;
316 maskOfConcurrency |= params.getThreadCountClasses() > 0 ? 2 : 0;
317 maskOfConcurrency |= params.getThreadCountMethods() > 0 ? 1 : 0;
318
319 maskOfConcurrency &= maskOfParallel;
320
321 int leaf = Integer.lowestOneBit( maskOfParallel );
322 return maskOfConcurrency == maskOfParallel - leaf;
323 }
324
325 private static double sumThreadCounts( Concurrency concurrency )
326 {
327 double sum = concurrency.suites;
328 sum += concurrency.classes;
329 sum += concurrency.methods;
330 return sum;
331 }
332
333 private static boolean hasThreadCounts( JUnitCoreParameters jUnitCoreParameters )
334 {
335 return jUnitCoreParameters.getThreadCountSuites() > 0 ||
336 jUnitCoreParameters.getThreadCountClasses() > 0 ||
337 jUnitCoreParameters.getThreadCountMethods() > 0;
338 }
339
340 private static boolean hasThreadCount ( JUnitCoreParameters jUnitCoreParameters )
341 {
342 return jUnitCoreParameters.getThreadCount() > 0;
343 }
344
345 private static int threadCountMethods( JUnitCoreParameters jUnitCoreParameters )
346 {
347 return multiplyByCoreCount( jUnitCoreParameters, jUnitCoreParameters.getThreadCountMethods() );
348 }
349
350 private static int threadCountClasses( JUnitCoreParameters jUnitCoreParameters )
351 {
352 return multiplyByCoreCount( jUnitCoreParameters, jUnitCoreParameters.getThreadCountClasses() );
353 }
354
355 private static int threadCountSuites( JUnitCoreParameters jUnitCoreParameters )
356 {
357 return multiplyByCoreCount( jUnitCoreParameters, jUnitCoreParameters.getThreadCountSuites() );
358 }
359
360 private static int multiplyByCoreCount( JUnitCoreParameters jUnitCoreParameters, double threadsPerCore )
361 {
362 double numberOfThreads =
363 jUnitCoreParameters.isPerCoreThreadCount() ?
364 threadsPerCore * (double) availableProcessors : threadsPerCore;
365
366 return numberOfThreads > 0 ? (int) Math.min( numberOfThreads, Integer.MAX_VALUE ) : Integer.MAX_VALUE;
367 }
368 }