diff --git a/.travis.yml b/.travis.yml index 59cb0e286..3e419dc53 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,7 +46,7 @@ notifications: - sbt-dev-bot@googlegroups.com script: - - sbt -J-XX:ReservedCodeCacheSize=128m "$SBT_CMD" + - sbt -J-XX:ReservedCodeCacheSize=128m -J-Xmx1g -J-Xms1g "$SBT_CMD" before_cache: - find $HOME/.ivy2 -name "ivydata-*.properties" -print -delete diff --git a/build.sbt b/build.sbt index f9a9b46a0..e28fa2aba 100644 --- a/build.sbt +++ b/build.sbt @@ -352,7 +352,7 @@ def otherRootSettings = scriptedUnpublished := scriptedUnpublishedTask.evaluated, scriptedSource := (sourceDirectory in sbtProj).value / "sbt-test", // scriptedPrescripted := { addSbtAlternateResolver _ }, - scriptedLaunchOpts := List("-XX:MaxPermSize=256M", "-Xmx360M"), + scriptedLaunchOpts := List("-Xmx1024M", "-Xms512M"), publishAll := { val _ = (publishLocal).all(ScopeFilter(inAnyProject)).value }, publishLocalBinAll := { val _ = (publishLocalBin).all(ScopeFilter(inAnyProject)).value }, aggregate in bintrayRelease := false @@ -362,7 +362,8 @@ def otherRootSettings = () }, scriptedLaunchOpts := { - List("-Xmx512M", + List("-Xmx1024M", + "-Xms512M", "-Dsbt.override.build.repos=true", s"""-Dsbt.repository.config=${scriptedSource.value / "repo.config"}""") }, diff --git a/scripted/sbt/src/main/scala/sbt/test/ScriptedTests.scala b/scripted/sbt/src/main/scala/sbt/test/ScriptedTests.scala index 573905b88..bd2c89a6e 100644 --- a/scripted/sbt/src/main/scala/sbt/test/ScriptedTests.scala +++ b/scripted/sbt/src/main/scala/sbt/test/ScriptedTests.scala @@ -17,6 +17,7 @@ import sbt.internal.util.{ BufferedLogger, ConsoleLogger, FullLogger } import sbt.util.{ AbstractLogger, Logger } import scala.collection.mutable +import scala.collection.parallel.ForkJoinTaskSupport import scala.collection.parallel.mutable.ParSeq final class ScriptedTests(resourceBaseDirectory: File, @@ -75,6 +76,7 @@ final class ScriptedTests(resourceBaseDirectory: File, def batchScriptedRunner( testGroupAndNames: Seq[(String, String)], prescripted: File => Unit, + sbtInstances: Int, log: Logger ): Seq[TestRunner] = { // Test group and names may be file filters (like '*') @@ -95,11 +97,14 @@ final class ScriptedTests(resourceBaseDirectory: File, testLabel -> testDirectory } - val batchSeed = labelsAndDirs.size / 4 + val batchSeed = labelsAndDirs.size / sbtInstances val batchSize = if (batchSeed == 0) labelsAndDirs.size else batchSeed - Seq(labelsAndDirs).map { batch => () => - IO.withTemporaryDirectory(runBatchedTests(batch, _, prescripted, log)) - }.toList + labelsAndDirs + .grouped(batchSize) + .map { batch => () => + IO.withTemporaryDirectory(runBatchedTests(batch, _, prescripted, log)) + } + .toList } /** Defines the batch execution of scripted tests. @@ -293,7 +298,8 @@ class ScriptedRunner { logger, bootProperties, launchOpts, - addTestFile) + addTestFile, + 1) } def runInParallel( @@ -303,13 +309,17 @@ class ScriptedRunner { logger: AbstractLogger, bootProperties: File, launchOpts: Array[String], - prescripted: File => Unit + prescripted: File => Unit, + instances: Int ): Unit = { val runner = new ScriptedTests(resourceBaseDirectory, bufferLog, bootProperties, launchOpts) // The scripted tests mapped to the inputs that the user wrote after `scripted`. val scriptedTests = get(tests, resourceBaseDirectory, logger).map(st => (st.group, st.name)) - val scriptedRunners = runner.batchScriptedRunner(scriptedTests, prescripted, logger) - runAll(scriptedRunners) + val scriptedRunners = runner.batchScriptedRunner(scriptedTests, prescripted, instances, logger) + val parallelRunners = scriptedRunners.toParArray + val pool = new java.util.concurrent.ForkJoinPool(instances) + parallelRunners.tasksupport = new ForkJoinTaskSupport(pool) + runAllInParallel(parallelRunners) } private def reportErrors(errors: Seq[String]): Unit = @@ -319,8 +329,9 @@ class ScriptedRunner { reportErrors(toRun.flatMap(test => test.apply().flatten.toSeq)) // We cannot reuse `runAll` because parallel collections != collections - def runAllInParallel(tests: ParSeq[ScriptedTests.TestRunner]): Unit = + def runAllInParallel(tests: ParSeq[ScriptedTests.TestRunner]): Unit = { reportErrors(tests.flatMap(test => test.apply().flatten.toSeq).toList) + } def get(tests: Seq[String], baseDirectory: File, log: Logger): Seq[ScriptedTest] = if (tests.isEmpty) listTests(baseDirectory, log) else parseTests(tests)