Relationship between forkEvery, maxParallelFork and --parallel

buildship

(John Soman) #1

Hi All. I am trying to ensure that each of my test classes runs in a separate JVM, while also trying to understand relationship between forkEvery, maxParallelForks from java plugin and --parallel option

In my setup, there is always a single large test per test class (Single method with @Test annotation in a class). My current understanding is that if I configure such tests with:

forkEvery = 1    
maxParallelForks = 4

That will mean that we start 4 gradle workers and run them in parallel, each worker in separate JVM. Then we send test classes to them one by one. Every time one worker finishes with its test class, it is restarted in a new JVM process before running next test class.

But what if we also pass --parallel flag. How does this affect test runs?

From the documentation: https://guides.gradle.org/performance/
By using the --parallel switch, you can force Gradle to execute tasks in parallel as long as those tasks are in different projects

I have a multiproject setup. But I am already saying that tests should be run in parallel and I am constraining test runs, only 4 test classes can execute in parallel and each in separate JVM because of Java Plugin configuration above.

So what does --parallel flag change here? I thought it may have no effect but without --parallel switch, my tests run slower. Is it OK to use --parallel switch even though I want to make sure that each test class runs in a separate JVM?

Thanks


(Sterling Greene) #2

maxParallelForks controls the parallelism of a single Test task. --parallel controls parallelism for the entire build.

So with maxParallelForks = 4, a single Test could run up to 4 tests in parallel using separate test processes.

Without --parallel, a task in another project (like Checkstyle) wouldn’t be allowed to start until the test task was complete. With --parallel, Gradle tries to run up to --max-workers tasks at once. You’re probably seeing a speed-up because other non-Test tasks are able to run during “idle” moments.

If you’re using a sufficiently new enough version of Gradle (>3.0), Gradle constrains the total amount of work being done to --max-workers. So if you had --max-workers=4 and maxParallelForks=4 and a multi-project build, Gradle could run 1 test worker and 3 tasks or 3 test workers and 1 task or any combination thereof. This prevents a bad situation where you have max workers * max parallel fork test processes running because multiple Test tasks are running at once.

There’s another wrinkle to this. We’re actually trying to make --parallel the default, so certain tasks that are known to be parallel-safe will run in parallel without the --parallel flag. Most the built-in tasks aren’t like this yet, so this is more of a FYI.

You could try creating a build scan and compare the timelines of each build (with and without --parallel).

Regarding forkEvery, you have it right. Gradle will start and tear down a new worker for every test. This is really expensive, so you shouldn’t do this unless you have a really good reason (e.g., globally polluting tests).