unit tests for algorithm
Project: http://git-wip-us.apache.org/repos/asf/maven-surefire/repo Commit: http://git-wip-us.apache.org/repos/asf/maven-surefire/commit/c85e6e83 Tree: http://git-wip-us.apache.org/repos/asf/maven-surefire/tree/c85e6e83 Diff: http://git-wip-us.apache.org/repos/asf/maven-surefire/diff/c85e6e83 Branch: refs/heads/master Commit: c85e6e83eee7513d9e1d4ae9c5aa7286b4ee3920 Parents: eaeaa28 Author: Tibor Digana <tibo...@lycos.com> Authored: Fri Feb 28 02:56:39 2014 +0100 Committer: Andreas Gudian <agud...@apache.org> Committed: Sun Mar 9 19:46:40 2014 +0100 ---------------------------------------------------------------------- .../junitcore/ParallelComputerFactory.java | 51 ++- .../surefire/junitcore/pc/RunnerCounter.java | 2 +- .../OptimizedParallelComputerTest.java | 323 +++++++++++++++++++ 3 files changed, 363 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c85e6e83/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ParallelComputerFactory.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ParallelComputerFactory.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ParallelComputerFactory.java index 91ef5bc..70d4a64 100644 --- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ParallelComputerFactory.java +++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/ParallelComputerFactory.java @@ -207,9 +207,9 @@ final class ParallelComputerFactory // Estimate parallel thread counts. double ratio = 1d / parallelEntities; int threads = multiplyByCoreCount( params, ratio * params.getThreadCount() ); - concurrency.suites = params.isParallelSuites() ? threads : 0; - concurrency.classes = params.isParallelClasses() ? threads : 0; - concurrency.methods = params.isParallelMethods() ? threads : 0; + concurrency.suites = params.isParallelSuites() ? minSuites( threads, counts ) : 0; + concurrency.classes = params.isParallelClasses() ? minClasses( threads, counts ) : 0; + concurrency.methods = params.isParallelMethods() ? minMethods( threads, counts ) : 0; if ( parallelEntities == 1 ) { concurrency.capacity = 0; @@ -222,11 +222,11 @@ final class ParallelComputerFactory else { // Try to allocate suites+classes+methods within threadCount, - concurrency.suites = params.isParallelSuites() ? multiplyByCoreCount( params, counts.suites ) : 0; - concurrency.classes = params.isParallelClasses() ? multiplyByCoreCount( params, counts.classes ) : 0; + concurrency.suites = params.isParallelSuites() ? toNonNegative( counts.suites ) : 0; + concurrency.classes = params.isParallelClasses() ? toNonNegative( counts.classes ) : 0; concurrency.methods = - params.isParallelMethods() ? multiplyByCoreCount( params, counts.methods / counts.classes ) : 0; - double sum = (double) concurrency.suites + concurrency.classes + concurrency.methods; + params.isParallelMethods() ? toNonNegative( Math.ceil( counts.methods / (double) counts.classes ) ) : 0; + double sum = toNonNegative( concurrency.suites + concurrency.classes + concurrency.methods ); if ( concurrency.capacity < sum && sum != 0 ) { // otherwise allocate them using the weighting factor < 1. @@ -234,7 +234,6 @@ final class ParallelComputerFactory concurrency.suites *= weight; concurrency.classes *= weight; concurrency.methods *= weight; - adjustPrecisionInLeaf( params, concurrency ); } adjustLeaf( params, concurrency ); } @@ -255,8 +254,8 @@ final class ParallelComputerFactory if ( counts != null ) { - concurrency.suites = (int) Math.min( Math.min( concurrency.suites, counts.suites ), Integer.MAX_VALUE ); - concurrency.classes = (int) Math.min( Math.min( concurrency.classes, counts.classes ), Integer.MAX_VALUE ); + concurrency.suites = toNonNegative( Math.min( concurrency.suites, counts.suites ) ); + concurrency.classes = toNonNegative( Math.min( concurrency.classes, counts.classes ) ); } setLeafInfinite( params, concurrency ); @@ -293,7 +292,7 @@ final class ParallelComputerFactory concurrency.suites = params.isParallelSuites() ? threadCountSuites( params ) : 0; concurrency.classes = params.isParallelClasses() ? threadCountClasses( params ) : 0; concurrency.methods = params.isParallelMethods() ? threadCountMethods( params ) : 0; - concurrency.capacity = (int) Math.min( sumThreadCounts( concurrency ), Integer.MAX_VALUE ); + concurrency.capacity = toNonNegative( sumThreadCounts( concurrency ) ); return concurrency; } @@ -413,7 +412,35 @@ final class ParallelComputerFactory double numberOfThreads = jUnitCoreParameters.isPerCoreThreadCount() ? threadsPerCore * (double) availableProcessors : threadsPerCore; - return numberOfThreads > 0 ? (int) Math.min( numberOfThreads, Integer.MAX_VALUE ) : Integer.MAX_VALUE; + return numberOfThreads > 0 ? toNonNegative( numberOfThreads ) : Integer.MAX_VALUE; + } + + private static int minSuites( int threads, RunnerCounter counts ) + { + long count = counts == null ? Integer.MAX_VALUE : counts.suites; + return Math.min( threads, toNonNegative( count ) ); + } + + private static int minClasses( int threads, RunnerCounter counts ) + { + long count = counts == null ? Integer.MAX_VALUE : counts.classes; + return Math.min( threads, toNonNegative( count ) ); + } + + private static int minMethods( int threads, RunnerCounter counts ) + { + long count = counts == null ? Integer.MAX_VALUE : counts.methods; + return Math.min( threads, toNonNegative( count ) ); + } + + private static int toNonNegative( long num ) + { + return (int) Math.min( num > 0 ? num : 0, Integer.MAX_VALUE ); + } + + private static int toNonNegative( double num ) + { + return (int) Math.min( num > 0 ? num : 0, Integer.MAX_VALUE ); } static class Concurrency http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c85e6e83/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/RunnerCounter.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/RunnerCounter.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/RunnerCounter.java index 48ef73a..ec0e80d 100644 --- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/RunnerCounter.java +++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/pc/RunnerCounter.java @@ -34,7 +34,7 @@ final public class RunnerCounter//todo needs refactoring, remove public public final long methods; - RunnerCounter( long suites, long classes, long methods ) + public RunnerCounter( long suites, long classes, long methods ) { this.suites = suites; this.classes = classes; http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c85e6e83/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/OptimizedParallelComputerTest.java ---------------------------------------------------------------------- diff --git a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/OptimizedParallelComputerTest.java b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/OptimizedParallelComputerTest.java new file mode 100644 index 0000000..c1ac0b4 --- /dev/null +++ b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/OptimizedParallelComputerTest.java @@ -0,0 +1,323 @@ +package org.apache.maven.surefire.junitcore; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.surefire.junitcore.pc.RunnerCounter; +import org.apache.maven.surefire.testset.TestSetFailedException; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.experimental.theories.DataPoint; +import org.junit.experimental.theories.Theories; +import org.junit.experimental.theories.Theory; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; + +import java.util.Properties; + +import static org.apache.maven.surefire.junitcore.JUnitCoreParameters.*; +import static org.apache.maven.surefire.junitcore.ParallelComputerFactory.resolveConcurrency; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.*; + +/** + * Testing an algorithm in {@link ParallelComputerFactory} which configures + * optimized thread resources in ParallelComputer by given {@link JUnitCoreParameters}. + * + * @author Tibor Digana (tibor17) + * @see org.apache.maven.surefire.junitcore.ParallelComputerFactory + * @since 2.17 + */ +@RunWith( Theories.class ) +public final class OptimizedParallelComputerTest +{ + @DataPoint + public static final int CPU_1 = 1; + + @DataPoint + public static final int CPU_4 = 4; + + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Rule + public final Stopwatch runtime = new Stopwatch(); + + @BeforeClass + public static void beforeClass() + { + ParallelComputerFactory.overrideAvailableProcessors( 1 ); + } + + @AfterClass + public static void afterClass() + { + ParallelComputerFactory.setDefaultAvailableProcessors(); + } + + @Theory + public void threadCountSuites( int cpu ) + throws TestSetFailedException + { + ParallelComputerFactory.overrideAvailableProcessors( cpu ); + Properties properties = new Properties(); + properties.setProperty( PARALLEL_KEY, "suites" ); + properties.setProperty( THREADCOUNT_KEY, "3" ); + JUnitCoreParameters params = new JUnitCoreParameters( properties ); + RunnerCounter counter = new RunnerCounter( 5, 10, 20 ); + ParallelComputerFactory.Concurrency concurrency = resolveConcurrency( params, counter ); + assertTrue( params.isParallelSuites() ); + assertFalse( params.isParallelClasses() ); + assertFalse( params.isParallelMethods() ); + assertThat( concurrency.capacity, is( 0 ) ); + assertThat( concurrency.suites, is( (int) Math.min( 3 * cpu, counter.suites ) ) ); + assertThat( concurrency.classes, is( 0 ) ); + assertThat( concurrency.methods, is( 0 ) ); + } + + @Theory + public void threadCountClasses( int cpu ) + throws TestSetFailedException + { + ParallelComputerFactory.overrideAvailableProcessors( cpu ); + Properties properties = new Properties(); + properties.setProperty( PARALLEL_KEY, "classes" ); + properties.setProperty( THREADCOUNT_KEY, "3" ); + JUnitCoreParameters params = new JUnitCoreParameters( properties ); + RunnerCounter counter = new RunnerCounter( 1, 5, 10 ); + ParallelComputerFactory.Concurrency concurrency = resolveConcurrency( params, counter ); + assertFalse( params.isParallelSuites() ); + assertTrue( params.isParallelClasses() ); + assertFalse( params.isParallelMethods() ); + assertThat( concurrency.capacity, is( 0 ) ); + assertThat( concurrency.suites, is( 0 ) ); + assertThat( concurrency.classes, is( (int) Math.min( 3 * cpu, counter.classes ) ) ); + assertThat( concurrency.methods, is( 0 ) ); + } + + @Theory + public void threadCountMethods( int cpu ) + throws TestSetFailedException + { + ParallelComputerFactory.overrideAvailableProcessors( cpu ); + Properties properties = new Properties(); + properties.setProperty( PARALLEL_KEY, "methods" ); + properties.setProperty( THREADCOUNT_KEY, "3" ); + JUnitCoreParameters params = new JUnitCoreParameters( properties ); + RunnerCounter counter = new RunnerCounter( 1, 2, 5 ); + ParallelComputerFactory.Concurrency concurrency = resolveConcurrency( params, counter ); + assertFalse( params.isParallelSuites() ); + assertFalse( params.isParallelClasses() ); + assertTrue( params.isParallelMethods() ); + assertThat( concurrency.capacity, is( 0 ) ); + assertThat( concurrency.suites, is( 0 ) ); + assertThat( concurrency.classes, is( 0 ) ); + assertThat( concurrency.methods, is( (int) Math.min( 3 * cpu, counter.methods ) ) ); + } + + @Theory + public void threadCountBoth( int cpu ) + throws TestSetFailedException + { + ParallelComputerFactory.overrideAvailableProcessors( cpu ); + Properties properties = new Properties(); + properties.setProperty( PARALLEL_KEY, "both" ); + properties.setProperty( THREADCOUNT_KEY, "3" ); + JUnitCoreParameters params = new JUnitCoreParameters( properties ); + RunnerCounter counter = new RunnerCounter( 1, 2, 5 ); + ParallelComputerFactory.Concurrency concurrency = resolveConcurrency( params, counter ); + assertFalse( params.isParallelSuites() ); + assertTrue( params.isParallelClasses() ); + assertTrue( params.isParallelMethods() ); + assertThat( concurrency.capacity, is( 3 * cpu ) ); + assertThat( concurrency.suites, is( 0 ) ); + assertThat( concurrency.classes, is( (int) Math.min( ( 3d / 2 ) * cpu, 2 ) ) ); + assertThat( concurrency.methods, is( Integer.MAX_VALUE ) ); + } + + @Theory + public void threadCountClassesAndMethods( int cpu ) + throws TestSetFailedException + { + ParallelComputerFactory.overrideAvailableProcessors( cpu ); + Properties properties = new Properties(); + properties.setProperty( PARALLEL_KEY, "classesAndMethods" ); + properties.setProperty( THREADCOUNT_KEY, "3" ); + JUnitCoreParameters params = new JUnitCoreParameters( properties ); + RunnerCounter counter = new RunnerCounter( 1, 2, 5 ); + ParallelComputerFactory.Concurrency concurrency = resolveConcurrency( params, counter ); + assertFalse( params.isParallelSuites() ); + assertTrue( params.isParallelClasses() ); + assertTrue( params.isParallelMethods() ); + assertThat( concurrency.capacity, is( 3 * cpu ) ); + assertThat( concurrency.suites, is( 0 ) ); + assertThat( concurrency.classes, is( (int) Math.min( ( 3d / 2 ) * cpu, 2 ) ) ); + assertThat( concurrency.methods, is( Integer.MAX_VALUE ) ); + } + + @Theory + public void threadCountSuitesAndMethods( int cpu ) + throws TestSetFailedException + { + ParallelComputerFactory.overrideAvailableProcessors( cpu ); + Properties properties = new Properties(); + properties.setProperty( PARALLEL_KEY, "suitesAndMethods" ); + properties.setProperty( THREADCOUNT_KEY, "3" ); + JUnitCoreParameters params = new JUnitCoreParameters( properties ); + RunnerCounter counter = new RunnerCounter( 2, 3, 5 ); + ParallelComputerFactory.Concurrency concurrency = resolveConcurrency( params, counter ); + assertTrue( params.isParallelSuites() ); + assertFalse( params.isParallelClasses() ); + assertTrue( params.isParallelMethods() ); + assertThat( concurrency.capacity, is( 3 * cpu ) ); + assertThat( concurrency.suites, is( (int) Math.min( ( 3d / 2 ) * cpu, 2 ) ) ); + assertThat( concurrency.classes, is( 0 ) ); + assertThat( concurrency.methods, is( Integer.MAX_VALUE ) ); + } + + @Theory + public void threadCountSuitesAndClasses( int cpu ) + throws TestSetFailedException + { + ParallelComputerFactory.overrideAvailableProcessors( cpu ); + Properties properties = new Properties(); + properties.setProperty( PARALLEL_KEY, "suitesAndClasses" ); + properties.setProperty( THREADCOUNT_KEY, "3" ); + JUnitCoreParameters params = new JUnitCoreParameters( properties ); + RunnerCounter counter = new RunnerCounter( 2, 5, 20 ); + ParallelComputerFactory.Concurrency concurrency = resolveConcurrency( params, counter ); + assertTrue( params.isParallelSuites() ); + assertTrue( params.isParallelClasses() ); + assertFalse( params.isParallelMethods() ); + assertThat( concurrency.capacity, is( 3 * cpu ) ); + assertThat( concurrency.suites, is( (int) Math.min( ( 2d * 3 / 7 ) * cpu, 2 ) ) ); + assertThat( concurrency.classes, is( Integer.MAX_VALUE ) ); + assertThat( concurrency.methods, is( 0 ) ); + } + + @Theory + public void threadCountAll( int cpu ) + throws TestSetFailedException + { + ParallelComputerFactory.overrideAvailableProcessors( cpu ); + Properties properties = new Properties(); + properties.setProperty( PARALLEL_KEY, "all" ); + properties.setProperty( THREADCOUNT_KEY, "3" ); + JUnitCoreParameters params = new JUnitCoreParameters( properties ); + RunnerCounter counter = new RunnerCounter( 2, 5, 20 ); + ParallelComputerFactory.Concurrency concurrency = resolveConcurrency( params, counter ); + assertTrue( params.isParallelSuites() ); + assertTrue( params.isParallelClasses() ); + assertTrue( params.isParallelMethods() ); + assertThat( concurrency.capacity, is( 3 * cpu ) ); + assertThat( concurrency.suites, is( (int) Math.min( ( 2d * 3 / 11 ) * cpu, 2 ) ) ); + assertThat( concurrency.classes, is( (int) Math.min( ( 5d * 3 / 11 ) * cpu, 5 ) ) ); + assertThat( concurrency.methods, is( Integer.MAX_VALUE ) ); + } + + @Theory + public void reusableThreadCountSuitesAndClasses( int cpu ) + throws TestSetFailedException + { + // 4 * cpu to 5 * cpu threads to run test classes + ParallelComputerFactory.overrideAvailableProcessors( cpu ); + Properties properties = new Properties(); + properties.setProperty( PARALLEL_KEY, "suitesAndClasses" ); + properties.setProperty( THREADCOUNT_KEY, "6" ); + properties.setProperty( THREADCOUNTSUITES_KEY, "2" ); + JUnitCoreParameters params = new JUnitCoreParameters( properties ); + RunnerCounter counter = new RunnerCounter( 3, 5, 20 ); + ParallelComputerFactory.Concurrency concurrency = resolveConcurrency( params, counter ); + assertTrue( params.isParallelSuites() ); + assertTrue( params.isParallelClasses() ); + assertFalse( params.isParallelMethods() ); + assertThat( concurrency.capacity, is( 6 * cpu ) ); + assertThat( concurrency.suites, is( Math.min( 2 * cpu, 3 ) ) ); + assertThat( concurrency.classes, is( Integer.MAX_VALUE ) ); + assertThat( concurrency.methods, is( 0 ) ); + } + + @Theory + public void reusableThreadCountSuitesAndMethods( int cpu ) + throws TestSetFailedException + { + // 4 * cpu to 5 * cpu threads to run test methods + ParallelComputerFactory.overrideAvailableProcessors( cpu ); + Properties properties = new Properties(); + properties.setProperty( PARALLEL_KEY, "suitesAndMethods" ); + properties.setProperty( THREADCOUNT_KEY, "6" ); + properties.setProperty( THREADCOUNTSUITES_KEY, "2" ); + JUnitCoreParameters params = new JUnitCoreParameters( properties ); + RunnerCounter counter = new RunnerCounter( 3, 5, 20 ); + ParallelComputerFactory.Concurrency concurrency = resolveConcurrency( params, counter ); + assertTrue( params.isParallelSuites() ); + assertFalse( params.isParallelClasses() ); + assertTrue( params.isParallelMethods() ); + assertThat( concurrency.capacity, is( 6 * cpu ) ); + assertThat( concurrency.suites, is( Math.min( 2 * cpu, 3 ) ) ); + assertThat( concurrency.classes, is( 0 ) ); + assertThat( concurrency.methods, is( Integer.MAX_VALUE ) ); + } + + @Theory + public void reusableThreadCountClassesAndMethods( int cpu ) + throws TestSetFailedException + { + // 4 * cpu to 5 * cpu threads to run test methods + ParallelComputerFactory.overrideAvailableProcessors( cpu ); + Properties properties = new Properties(); + properties.setProperty( PARALLEL_KEY, "classesAndMethods" ); + properties.setProperty( THREADCOUNT_KEY, "6" ); + properties.setProperty( THREADCOUNTCLASSES_KEY, "2" ); + JUnitCoreParameters params = new JUnitCoreParameters( properties ); + RunnerCounter counter = new RunnerCounter( 3, 5, 20 ); + ParallelComputerFactory.Concurrency concurrency = resolveConcurrency( params, counter ); + assertFalse( params.isParallelSuites() ); + assertTrue( params.isParallelClasses() ); + assertTrue( params.isParallelMethods() ); + assertThat( concurrency.capacity, is( 6 * cpu ) ); + assertThat( concurrency.suites, is( 0 ) ); + assertThat( concurrency.classes, is( Math.min( 2 * cpu, 5 ) ) ); + assertThat( concurrency.methods, is( Integer.MAX_VALUE ) ); + } + + @Theory + public void reusableThreadCountAll( int cpu ) + throws TestSetFailedException + { + // 8 * cpu to 13 * cpu threads to run test methods + ParallelComputerFactory.overrideAvailableProcessors( cpu ); + Properties properties = new Properties(); + properties.setProperty( PARALLEL_KEY, "all" ); + properties.setProperty( THREADCOUNT_KEY, "14" ); + properties.setProperty( THREADCOUNTSUITES_KEY, "2" ); + properties.setProperty( THREADCOUNTCLASSES_KEY, "4" ); + JUnitCoreParameters params = new JUnitCoreParameters( properties ); + RunnerCounter counter = new RunnerCounter( 3, 5, 20 ); + ParallelComputerFactory.Concurrency concurrency = resolveConcurrency( params, counter ); + assertTrue( params.isParallelSuites() ); + assertTrue( params.isParallelClasses() ); + assertTrue( params.isParallelMethods() ); + assertThat( concurrency.capacity, is( 14 * cpu ) ); + assertThat( concurrency.suites, is( Math.min( 2 * cpu, 3 ) ) ); + assertThat( concurrency.classes, is( Math.min( 4 * cpu, 5 ) ) ); + assertThat( concurrency.methods, is( Integer.MAX_VALUE ) ); + } +} \ No newline at end of file