Coverage Report - org.apache.maven.surefire.junitcore.ParallelComputerFactory
 
Classes in this File Line Coverage Branch Coverage Complexity
ParallelComputerFactory
77%
104/135
80%
106/132
3,654
ParallelComputerFactory$Concurrency
100%
1/1
N/A
3,654
 
 1  
 package org.apache.maven.surefire.junitcore;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *     http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 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  
  * An algorithm which configures {@link ParallelComputer} with allocated thread resources by given {@link JUnitCoreParameters}.
 28  
  * The <code>AbstractSurefireMojo</code> has to provide correct combinations of thread-counts and <em>parallel</em>.
 29  
  *
 30  
  * @author Tibor Digana (tibor17)
 31  
  * @since 2.16
 32  
  *
 33  
  * @see org.apache.maven.surefire.junitcore.pc.ParallelComputerBuilder
 34  
  */
 35  
 final class ParallelComputerFactory
 36  
 {
 37  1
     private static int availableProcessors = Runtime.getRuntime().availableProcessors();
 38  
 
 39  84
     static class Concurrency
 40  
     {
 41  
         int suites, classes, methods, capacity;
 42  
     }
 43  
 
 44  
     private ParallelComputerFactory()
 45  0
     {
 46  0
         throw new IllegalStateException("Suppresses calling constructor, ensuring non-instantiability.");
 47  
     }
 48  
 
 49  
     /*
 50  
     * For testing purposes.
 51  
     */
 52  
     static void overrideAvailableProcessors( int availableProcessors )
 53  
     {
 54  61
         ParallelComputerFactory.availableProcessors = availableProcessors;
 55  61
     }
 56  
 
 57  
     /*
 58  
     * For testing purposes.
 59  
     */
 60  
     static void setDefaultAvailableProcessors()
 61  
     {
 62  1
         ParallelComputerFactory.availableProcessors = Runtime.getRuntime().availableProcessors();
 63  1
     }
 64  
 
 65  
     static ParallelComputer createParallelComputer( JUnitCoreParameters params ) throws TestSetFailedException
 66  
     {
 67  0
         Concurrency concurrency = resolveConcurrency( params );
 68  0
         ParallelComputerBuilder builder = new ParallelComputerBuilder();
 69  
 
 70  0
         if ( params.isParallelSuites() )
 71  
         {
 72  0
             resolveSuitesConcurrency( builder, concurrency.suites );
 73  
         }
 74  
 
 75  0
         if ( params.isParallelClasses() )
 76  
         {
 77  0
             resolveClassesConcurrency( builder, concurrency.classes );
 78  
         }
 79  
 
 80  0
         if ( params.isParallelMethod() )
 81  
         {
 82  0
             resolveMethodsConcurrency( builder, concurrency.methods );
 83  
         }
 84  
 
 85  0
         resolveCapacity( builder, concurrency.capacity );
 86  0
         return builder.buildComputer();
 87  
     }
 88  
 
 89  
     static Concurrency resolveConcurrency( JUnitCoreParameters params ) throws TestSetFailedException
 90  
     {
 91  93
         if ( !params.isAnyParallelitySelected() )
 92  
         {
 93  1
             throw new TestSetFailedException( "Unspecified parameter '" + JUnitCoreParameters.PARALLEL_KEY + "'." );
 94  
         }
 95  
 
 96  92
         if ( !params.isUseUnlimitedThreads() && !hasThreadCount( params ) && !hasThreadCounts( params ) )
 97  
         {
 98  8
             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  84
         if ( params.isUseUnlimitedThreads() )
 105  
         {
 106  28
             return concurrencyForUnlimitedThreads( params );
 107  
         }
 108  
         else
 109  
         {
 110  56
             if ( hasThreadCount( params ) )
 111  
             {
 112  32
                 if ( hasThreadCounts( params ) )
 113  
                 {
 114  16
                     return isLeafUnspecified( params ) ?
 115  
                             concurrencyFromAllThreadCountsButUnspecifiedLeafCount( params ) :
 116  
                             concurrencyFromAllThreadCounts( params );
 117  
                 }
 118  
                 else
 119  
                 {
 120  16
                     return estimateConcurrency( params );
 121  
                 }
 122  
             }
 123  
             else
 124  
             {
 125  24
                 return concurrencyFromThreadCounts( params );
 126  
             }
 127  
         }
 128  
     }
 129  
 
 130  
     private static void resolveSuitesConcurrency( ParallelComputerBuilder builder, int concurrency )
 131  
     {
 132  0
         if ( concurrency > 0 )
 133  
         {
 134  0
             if ( concurrency == Integer.MAX_VALUE )
 135  
             {
 136  0
                 builder.parallelSuites();
 137  
             }
 138  
             else
 139  
             {
 140  0
                 builder.parallelSuites( concurrency );
 141  
             }
 142  
         }
 143  0
     }
 144  
 
 145  
     private static void resolveClassesConcurrency( ParallelComputerBuilder builder, int concurrency )
 146  
     {
 147  0
         if ( concurrency > 0 )
 148  
         {
 149  0
             if ( concurrency == Integer.MAX_VALUE )
 150  
             {
 151  0
                 builder.parallelClasses();
 152  
             }
 153  
             else
 154  
             {
 155  0
                 builder.parallelClasses( concurrency );
 156  
             }
 157  
         }
 158  0
     }
 159  
 
 160  
     private static void resolveMethodsConcurrency( ParallelComputerBuilder builder, int concurrency )
 161  
     {
 162  0
         if ( concurrency > 0 )
 163  
         {
 164  0
             if ( concurrency == Integer.MAX_VALUE )
 165  
             {
 166  0
                 builder.parallelMethods();
 167  
             }
 168  
             else
 169  
             {
 170  0
                 builder.parallelMethods( concurrency );
 171  
             }
 172  
         }
 173  0
     }
 174  
 
 175  
     private static void resolveCapacity( ParallelComputerBuilder builder, int capacity )
 176  
     {
 177  0
         if ( capacity > 0 )
 178  
         {
 179  0
             builder.useOnePool( capacity );
 180  
         }
 181  0
     }
 182  
 
 183  
     private static Concurrency concurrencyForUnlimitedThreads( JUnitCoreParameters params )
 184  
     {
 185  28
         Concurrency concurrency = new Concurrency();
 186  28
         concurrency.suites = params.isParallelSuites() ? threadCountSuites( params ) : 0;
 187  28
         concurrency.classes = params.isParallelClasses() ? threadCountClasses( params ) : 0;
 188  28
         concurrency.methods = params.isParallelMethod() ? threadCountMethods( params ) : 0;
 189  28
         concurrency.capacity = Integer.MAX_VALUE;
 190  28
         return concurrency;
 191  
     }
 192  
 
 193  
     private static Concurrency estimateConcurrency( JUnitCoreParameters params )
 194  
     {
 195  16
         Concurrency concurrency = new Concurrency();
 196  16
         concurrency.suites = params.isParallelSuites() ? params.getThreadCountSuites() : 0;
 197  16
         concurrency.classes = params.isParallelClasses() ? params.getThreadCountClasses() : 0;
 198  16
         concurrency.methods = params.isParallelMethod() ? params.getThreadCountMethods() : 0;
 199  16
         concurrency.capacity = params.getThreadCount();
 200  
 
 201  
         // estimate parallel thread counts
 202  16
         double ratio = 1d / countParallelEntities( params );
 203  16
         int threads = multiplyByCoreCount( params, ratio * concurrency.capacity );
 204  16
         concurrency.suites = params.isParallelSuites() ? threads : 0;
 205  16
         concurrency.classes = params.isParallelClasses() ? threads : 0;
 206  16
         concurrency.methods = params.isParallelMethod() ? threads : 0;
 207  16
         if ( countParallelEntities( params ) == 1 )
 208  
         {
 209  6
             concurrency.capacity = 0;
 210  
         }
 211  
         else
 212  
         {
 213  10
             concurrency.capacity = multiplyByCoreCount( params, concurrency.capacity );
 214  10
             adjustLeaf( params, concurrency );
 215  
         }
 216  16
         return concurrency;
 217  
     }
 218  
 
 219  
     private static Concurrency concurrencyFromAllThreadCountsButUnspecifiedLeafCount( JUnitCoreParameters params )
 220  
     {
 221  8
         Concurrency concurrency = new Concurrency();
 222  8
         concurrency.suites = params.isParallelSuites() ? params.getThreadCountSuites() : 0;
 223  8
         concurrency.classes = params.isParallelClasses() ? params.getThreadCountClasses() : 0;
 224  8
         concurrency.methods = params.isParallelMethod() ? params.getThreadCountMethods() : 0;
 225  8
         concurrency.capacity = params.getThreadCount();
 226  
 
 227  8
         setLeafInfinite( params, concurrency );
 228  8
         concurrency.suites = params.isParallelSuites() ? multiplyByCoreCount( params, concurrency.suites ) : 0;
 229  8
         concurrency.classes = params.isParallelClasses() ? multiplyByCoreCount( params, concurrency.classes ) : 0;
 230  8
         concurrency.methods = params.isParallelMethod() ? multiplyByCoreCount( params, concurrency.methods ) : 0;
 231  8
         concurrency.capacity = multiplyByCoreCount( params, concurrency.capacity );
 232  
 
 233  8
         return concurrency;
 234  
     }
 235  
 
 236  
     private static Concurrency concurrencyFromAllThreadCounts( JUnitCoreParameters params )
 237  
     {
 238  8
         Concurrency concurrency = new Concurrency();
 239  8
         concurrency.suites = params.isParallelSuites() ? params.getThreadCountSuites() : 0;
 240  8
         concurrency.classes = params.isParallelClasses() ? params.getThreadCountClasses() : 0;
 241  8
         concurrency.methods = params.isParallelMethod() ? params.getThreadCountMethods() : 0;
 242  8
         concurrency.capacity = params.getThreadCount();
 243  8
         double all = sumThreadCounts( concurrency );
 244  
 
 245  8
         concurrency.suites = params.isParallelSuites() ?
 246  
                 multiplyByCoreCount( params, concurrency.capacity * ( concurrency.suites / all ) ) : 0;
 247  
 
 248  8
         concurrency.classes = params.isParallelClasses() ?
 249  
                 multiplyByCoreCount( params, concurrency.capacity * ( concurrency.classes / all ) ) : 0;
 250  
 
 251  8
         concurrency.methods = params.isParallelMethod() ?
 252  
                 multiplyByCoreCount( params, concurrency.capacity * ( concurrency.methods / all ) ) : 0;
 253  
 
 254  8
         concurrency.capacity = multiplyByCoreCount( params, concurrency.capacity );
 255  8
         adjustPrecisionInLeaf( params, concurrency );
 256  8
         return concurrency;
 257  
     }
 258  
 
 259  
     private static Concurrency concurrencyFromThreadCounts( JUnitCoreParameters params )
 260  
     {
 261  24
         Concurrency concurrency = new Concurrency();
 262  24
         concurrency.suites = params.isParallelSuites() ? threadCountSuites( params ) : 0;
 263  24
         concurrency.classes = params.isParallelClasses() ? threadCountClasses( params ) : 0;
 264  24
         concurrency.methods = params.isParallelMethod() ? threadCountMethods( params ) : 0 ;
 265  24
         concurrency.capacity = (int) Math.min( sumThreadCounts( concurrency ), Integer.MAX_VALUE );
 266  24
         return concurrency;
 267  
     }
 268  
 
 269  
     private static int countParallelEntities( JUnitCoreParameters params )
 270  
     {
 271  32
         int count = 0;
 272  32
         if ( params.isParallelSuites() ) count++;
 273  32
         if ( params.isParallelClasses() ) count++;
 274  32
         if ( params.isParallelMethod() ) count++;
 275  32
         return count;
 276  
     }
 277  
 
 278  
     private static void adjustPrecisionInLeaf( JUnitCoreParameters params, Concurrency concurrency )
 279  
     {
 280  8
         if ( params.isParallelMethod() )
 281  
         {
 282  6
             concurrency.methods = concurrency.capacity - concurrency.suites - concurrency.classes;
 283  
         }
 284  2
         else if ( params.isParallelClasses() )
 285  
         {
 286  2
             concurrency.classes = concurrency.capacity - concurrency.suites;
 287  
         }
 288  8
     }
 289  
 
 290  
     private static void adjustLeaf( JUnitCoreParameters params, Concurrency concurrency )
 291  
     {
 292  10
         if ( params.isParallelMethod() )
 293  
         {
 294  8
             concurrency.methods = Integer.MAX_VALUE;
 295  
         }
 296  2
         else if ( params.isParallelClasses() )
 297  
         {
 298  2
             concurrency.classes = Integer.MAX_VALUE;
 299  
         }
 300  10
     }
 301  
 
 302  
     private static void setLeafInfinite( JUnitCoreParameters params, Concurrency concurrency )
 303  
     {
 304  8
         if ( params.isParallelMethod() ) concurrency.methods = Integer.MAX_VALUE;
 305  2
         else if ( params.isParallelClasses() ) concurrency.classes = Integer.MAX_VALUE;
 306  0
         else if ( params.isParallelSuites() ) concurrency.suites = Integer.MAX_VALUE;
 307  8
     }
 308  
 
 309  
     private static boolean isLeafUnspecified( JUnitCoreParameters params )
 310  
     {
 311  16
         int maskOfParallel = params.isParallelSuites() ? 4: 0;
 312  16
         maskOfParallel |= params.isParallelClasses() ? 2 : 0;
 313  16
         maskOfParallel |= params.isParallelMethod() ? 1 : 0;
 314  
 
 315  16
         int maskOfConcurrency = params.getThreadCountSuites() > 0 ? 4 : 0;
 316  16
         maskOfConcurrency |= params.getThreadCountClasses() > 0 ? 2 : 0;
 317  16
         maskOfConcurrency |= params.getThreadCountMethods() > 0 ? 1 : 0;
 318  
 
 319  16
         maskOfConcurrency &= maskOfParallel;
 320  
 
 321  16
         int leaf = Integer.lowestOneBit( maskOfParallel );
 322  16
         return maskOfConcurrency == maskOfParallel - leaf;
 323  
     }
 324  
 
 325  
     private static double sumThreadCounts( Concurrency concurrency )
 326  
     {
 327  32
         double sum = concurrency.suites;
 328  32
         sum += concurrency.classes;
 329  32
         sum += concurrency.methods;
 330  32
         return sum;
 331  
     }
 332  
 
 333  
     private static boolean hasThreadCounts( JUnitCoreParameters jUnitCoreParameters )
 334  
     {
 335  64
         return jUnitCoreParameters.getThreadCountSuites() > 0 ||
 336  
                 jUnitCoreParameters.getThreadCountClasses() > 0 ||
 337  
                 jUnitCoreParameters.getThreadCountMethods() > 0;
 338  
     }
 339  
 
 340  
     private static boolean hasThreadCount ( JUnitCoreParameters jUnitCoreParameters )
 341  
     {
 342  120
         return jUnitCoreParameters.getThreadCount() > 0;
 343  
     }
 344  
 
 345  
     private static int threadCountMethods( JUnitCoreParameters jUnitCoreParameters )
 346  
     {
 347  32
         return multiplyByCoreCount( jUnitCoreParameters, jUnitCoreParameters.getThreadCountMethods() );
 348  
     }
 349  
 
 350  
     private static int threadCountClasses( JUnitCoreParameters jUnitCoreParameters )
 351  
     {
 352  32
         return multiplyByCoreCount( jUnitCoreParameters, jUnitCoreParameters.getThreadCountClasses() );
 353  
     }
 354  
 
 355  
     private static int threadCountSuites( JUnitCoreParameters jUnitCoreParameters )
 356  
     {
 357  32
         return multiplyByCoreCount( jUnitCoreParameters, jUnitCoreParameters.getThreadCountSuites() );
 358  
     }
 359  
 
 360  
     private static int multiplyByCoreCount( JUnitCoreParameters jUnitCoreParameters, double threadsPerCore )
 361  
     {
 362  174
         double numberOfThreads =
 363  
                     jUnitCoreParameters.isPerCoreThreadCount() ?
 364  
                             threadsPerCore * (double) availableProcessors : threadsPerCore;
 365  
 
 366  174
         return numberOfThreads > 0 ? (int) Math.min( numberOfThreads, Integer.MAX_VALUE ) : Integer.MAX_VALUE;
 367  
     }
 368  
 }