background
The company has recently put forward requirements for line coverage of code. Although it is said that more ut can improve the code quality to a certain extent, due to the large amount of code, the package delivery speed of maven build has been greatly affected, once increased to 40min. (our company must build before merging the code into the Master). In this case, the leaders require that the time spent in UT be greatly shortened
Increase memory
By adding and analyzing the GC log in the build process, it is found that many times of Full GC will consume a lot of time each time. Through modifying POM XML to modify
<argLine>-noverify -Xms10G -Xmx10G -XX:NewSize=3G -XX:-UseAdaptiveSizePolicy -XX:ReservedCodeCacheSize=480M -XX:MetaspaceSize=1280M</argLine>
The specific size needs to be tested several times. You should be familiar with most parameters. The special ones are - XX: - useadaptive sizepolicy and XX: reserved codecachesize, which are briefly introduced respectively
-20: - useadaptive sizepolicy. Turn off adaptive sizepolicy. JDK 1.8 uses UseParallelGC garbage collector by default. The garbage collector starts this function by default and automatically calculates the sizes of Eden, From and To areas according To the situation of GC;
While observing the GC logs, we found the following logs
SUREFIRE-859: [Full GC (Ergonomics) [PSYoungGen: 3064832K->0K(3216896K)] [ParOldGen: 6530489K->6514820K(6990848K)] 9595321K->6514820K(10207744K), [Metaspace: 1093533K->1093316K(2080768K)], 29.8133768 secs] [Times: user=102.30 sys=40.04, real=29.82 secs]
Full GC (Ergonomics) indicates that the size of several partitions has been dynamically adjusted, because it is maven build, which we modified to a fixed value.
XX:ReservedCodeCacheSize, this parameter is a setting parameter to adjust the memory size in the JvM virtual machine tuning. It is worth the size setting directly affects the size of the Code Cache, while the JVM compiled code is often stored in Code Cache, while Code Cache's space memory also supports the normal operation of JVM. If the space is insufficient, the virtual machine will have problems. And performance continues to decline. The default CodeCache of the JVM is 240M.
CodeCache: size=245760Kb used=243229Kb max_used=243298Kb free=2530Kb SUREFIRE-859: bounds [0x000000010f431000, 0x000000011e431000, 0x000000011e431000] total_blobs=64731 nmethods=63978 adapters=663 compilation: disabled (not enough contiguous free space left) Java HotSpot(TM) 64-Bit Server VM warning: CodeCache is full. Compiler has been disabled. Java HotSpot(TM) 64-Bit Server VM warning: Try increasing the code cache size using -XX:ReservedCodeCacheSize=
Through the configuration of the above parameters, our buil d time is shortened from 40 minutes to 20 minutes, and the results are remarkable. But we can further compress the time.
Concurrent execution of unit tests
As mentioned earlier, most of our build time is spent on Test. If UT can be executed concurrently, the time can also be shortened to a certain extent.
The test framework we use is TestNG. TestNG itself supports concurrent operations. We can use the configuration file suit XML. For a detailed description of suit, please refer to https://www.devtalking.com/articles/testng-powermock/ , an example is provided below,
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="site-service-test-suite-parallel"> <test name="site-service-test-queue"> <method-selectors> <method-selector> <selector-class name="QueueMethodSelector" priority="-1" /> </method-selector> </method-selectors> <packages> <package name="your.package.*"/> </packages> </test> <test name="site-service-test-parallel" parallel="classes" thread-count="8" > <method-selectors> <method-selector> <selector-class name="ParallelMethodSelector" priority="-1"/> </method-selector> </method-selectors> <packages> <package name="your.package.*"/> </packages> </test> </suite>
You can see that two tests are distinguished in our file. One uses the parallel tag and the thread count tag, which indicate the concurrency level and the number of threads used; The other one is not used to indicate serial execution. In addition, the two main differences lie in the different values in the method selector tag. Because our UT heavily depends on PowerMock, some UT cannot be executed concurrently (the PrepareForTest annotation will modify the bytecode). Therefore, we have customized a class scanner to classify UT.
public class ParallelMethodSelector implements IMethodSelector { private static final Logger logger = LoggerFactory.getLogger(ParallelMethodSelector.class); @Override public boolean includeMethod(IMethodSelectorContext context, ITestNGMethod method, boolean isTestMethod) { if (!isTestMethod) return true; Class<?> clazz = method.getRealClass(); if (clazz.isAnnotationPresent(PrepareForTest.class)) return false; Class<?> superClass = clazz.getSuperclass(); if (Objects.nonNull(superClass) && superClass.isAnnotationPresent(PrepareForTest.class)) return false; return true; } @Override public void setTestMethods(List<ITestNGMethod> testMethods) { } }
TestNG 6.9 has a Bug on concurrency. It is better to use a better version
In addition, maven also provides the - T parameter, which can build different module s concurrently.