Description
Background
Currently, the tests of Java-tron are executed serially, which makes it take a long time to execute all of them. For a Macbook Pro with a 2.6 GHz six-core Intel Core i7 processor, and 16 GB 2667 MHz DDR4 memory, it takes 24 minutes to run all tests.
Technically speaking, parallel execution of the tests compared to serial execution will significantly reduce the total execution time, thus improving R&D efficiency. Meanwhile, the coverage of the tests should be maintained.
Rationale
To enable test parallelism in java-tron, you need to change the configuration of gradle.
Gradle supports parallel execution of tests, which can be achieved by using Gradle's parallel testing function.
Use the following properties to control how the test process is started Test task:
maxParallelForks — default: 1
For example, let’s configure parallel testing in the build.gradle file of gradle and configure the maxParallelForks attribute in the test task.
test {
maxParallelForks = 4
}
After this configuration, Gradle will run 4 test tasks in parallel.
Refer to Gradle's configuration documentation here: Testing in Java & JVM projects
By setting this property to a value greater than 1, tests can be run in parallel. This may make the tests run faster, especially with a multi-core CPU. When using parallel test execution, make sure your tests are properly isolated from each other. Tests that interact with the file system are particularly prone to conflicts, causing intermittent test failures.
This can be done by using the org.gradle.test.worker property, which is unique for each parallel worker. You can use this for anything you want, but it is especially useful for filenames and other resource identifiers to prevent the single-test conflicts mentioned above.
System.getProperty("org.gradle.test.worker")
Implementation
- Enable test parallelism
To enable test parallelism in Java-tron, you need to make the following Gradle configuration changes
- a. In framework/build.gradle, add the following under the test module
test {
if (System.getenv("CI") == null) {
maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1
}
}
- b. In build.gradle, add the following under the subprojects module
subprojects {
tasks.withType(JavaCompile).configureEach{
options.fork = true
}
}
- Emerging Problems
The tests of Java-tron have incurred some new problems under parallel execution. Currently, the tests with these problems have been sorted out.
project | class | method |
---|---|---|
framework | DBConvertTest.java | testRun |
plugins | DbLiteTest.java | testTools |
framework | JsonrpcServiceTest.java | testGetBlockByNumber2 |
framework | SendCoinShieldTest.java | TestCreateMultipleTxAtTheSameTime |
framework | SnapshotImplTest.java | All |
framework | SnapshotRootTest.java | All |
When these problematic tests are commented out, everything is fine when executing tests in parallel.
- Solution
After changing to parallel execution, some tests occasionally failed to execute.These tests need to be refactored so that all tests of Java-tron can be executed in parallel.
- Experiment of Parallel Execution
Experiments were conducted on an AMD EPYC 7R32 server with 64G memory and 32 core processors, and the following data were obtained:
enable test parallelism | parallel number | execution time | reduce percentage |
---|---|---|---|
no | 1 | about 18min | 0% |
yes | 32 | about 7min | about 60% |
yes | 16 | about 7min | about 60% |
yes | 8 | about 9min | about 50% |
Based on the above experiments, enabling test parallelism on a multi-core machine can indeed reduce the execution time of tests, and the test parallelism can be set to = cpu core num / 2.
- What to do in the future
After enabling parallel unit tests, the newly added unit tests need to be executed normally under parallel execution.