matrei opened a new pull request, #16837:
URL: https://github.com/apache/grails-core/pull/16837

   ## Description
   
   A draft to see on CI whether the unit test tasks can keep their test JVMs 
for the whole task instead of restarting them every 50 test classes. Not for 
merge as is.
   
   1. A new, unpublished module, `grails-test-listener`, registers a JUnit 
Platform `TestExecutionListener` through `META-INF/services` that calls 
`Introspector.flushCaches()` after each test class. This is the cache #16834 
flushes after each TCK spec: Groovy reads the BeanInfo of every class it builds 
a MetaClass for, and the JDK keeps it until the class is unloaded, which the 
classes of a test JVM never are. `gradle/test-config.gradle` and 
`grails-test-suite-uber` put the module on the test runtime classpath.
   2. `forkEvery` now defaults to 0 in `gradle/test-config.gradle` 
(`-PforkEveryUnitTest` still overrides it), and `grails-test-suite-uber` no 
longer sets it.
   
   ### Local measurements
   
   The largest four modules that need no Docker, at the CI values 
(`-PmaxTestParallel=4 -PtestForkHeapMb=768`). A forces `forkEvery = 50` with 
the listener off; B is `forkEvery = 0` with the listener off; C is `forkEvery = 
0` with the listener on. A probe listener (not committed) forced a full GC 
every 10 test classes and at the end of each JVM and recorded the live heap and 
the size of the Introspector's cache. Times are the median of three runs for 
uber and datamapping-core and of one run for the others.
   
   | Module | JVMs, A → B/C | Time, A / B / C | Peak live heap, A / B / C | 
Cached BeanInfos, B → C |
   |---|---|---|---|---|
   | grails-test-suite-uber | 20 → 4 | 55 s / 39 s / 38 s | 111 / 164 / 132 MB 
| 1,470 → 4 |
   | grails-datamapping-core | 8 → 4 | 52 s / 44 s / 45 s | 122 / 170 / 141 MB 
| 1,737 → 2 |
   | grails-gsp | 4 → 4 | 72 s / 73 s / 69 s | 313 / 313 / 220 MB | 3,196 → 5 |
   | grails-core | 8 → 8 | 47 s / 46 s / 47 s | 105 / 105 / 93 MB | 799 → 0 |
   
   Every run passed with the same test counts, and there was no full GC other 
than the probe's own. A JVM that runs a whole task holds 9-12 MB more metaspace.
   
   - `forkEvery` counts the top-level classes Gradle sends to a JVM, not the 
test classes JUnit runs, and Gradle deals them to the forks in turn. 
`grails-core` (187 class files, with 4 more JVMs for `testCli`) and 
`grails-gsp` (192) never reach 50 per fork, so they did not restart in A either.
   - `grails-test-suite-uber` does not apply `test-config.gradle` and so has no 
`**/*$*.class` exclude: all 910 of its class files, closures included, count, 
and its JVMs restart after about 12 test classes.
   - The `configureEach` of `test-config.gradle` runs after the settings of the 
suites that apply it: `grails-test-suite-web:execIsolatedTests` runs with 
`forkEvery = 50`, not the 1 its build script sets, and 
`grails-test-suite-persistence` loses its `forkEvery`, its local 2 GB heap and 
its three `excludes`, so the classes it isolates in their own tasks also run in 
`test`. Not changed here.
   
   ### What to look at
   
   - The durations of the `Build Grails-Core` jobs against recent 8.0.x runs.
   - New failures: a class that leaks static state now reaches every later 
class in its JVM rather than at most the next 49.
   - Out of memory errors, or heap or metaspace growth, in the larger modules.
   
   `./gradlew clean aggregateViolations --continue` passes locally. The full 
unit and integration suite (`:grails-test-report:check`) was not run locally: 
this pull request's CI run is that run.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to