1

When I build my project with gradle, the test outputs are huge and I would like to keep them. Therefore, I activated showing the output streams:

test {
    testLogging.showStandardStreams = true
}

Unfortunately, gradle does not seem to be able to handle big standard outputs. For demonstration, I created a minimal example: https://github.com/DaGeRe/stdout-test It is a project creating big standard output in a test by

@Test
public void test() {
   long start = System.currentTimeMillis();
   for (int i = 0; i < 200; i++) {
      for (int j = 0; j < 10000; j++) {
         long current = System.currentTimeMillis() - start;
          System.out.println("This is a simple logging output: " + i + " " + j + " " + current);
      }
   }
}

If I run this in a standard maven project, it finishes in about 2 minutes:

reichelt@reichelt-desktop:~/workspaces/stdout-test$ time mvn test &> mvn.txt

real    1m34,130s
user    0m31,333s
sys     1m12,296s

If I run it in gradle by time ./gradlew test &> gradle.txt, it does not finish at all (in reasonable time) and the output contains many Expiring Daemon because JVM heap space is exhausted. A way to solve this temporarily would be increasing heap memory (like suggested here: JVM space exhausted when building a project through gradle ), but -Xmx4g does not change anything according to my experiments, and this obviously will not scale for bigger outputs. Also, running ./gradlew -i test does not change the behavior.

The project also contains example files for outputs from maven (https://github.com/DaGeRe/stdout-test/blob/master/mvn.txt) and gradle (https://github.com/DaGeRe/stdout-test/blob/master/gradle.txt - aborted process after ~10 minutes) and one of the heap dumps (https://github.com/DaGeRe/stdout-test/blob/master/java_pid10812.hprof.tar) gradle created. There are only minor increases in the current time in the gradle-log (third output number of every line). Therefore, I assume that gradle mainly has problems printing to stdout and not executing the program.

This shows that, while gradle has some problems printing to stdout, it seems to not block the test execution. Is there any switch or parameter I could give gradle, which forces gradle to directly print to stdout instead of doing its memory-intense processing? Unfortunately, I did not find any in the documentation (https://docs.gradle.org/current/dsl/org.gradle.api.tasks.testing.Test.html).

EDIT Just finished a test run on a server:

reichelt@r147:~/workspaces/dissworkspace/stdout-test$ time ./gradlew test &> gradle.txt

real    28m17,959s
user    216m37,351s
sys     0m12,410s

Ends with an exception:

    This is a simple logging output: 89 7842 1416
    This is a simple logging output: 89 7843 1416
    This is a simple logging output: 89 7844 1416
    This is a simple logging output: 89 7845 1416
    This is a simple logging output: 89 7846 1416
FAILURE: Build failed with an exception.

* What went wrong:
GC overhead limit exceeded
David Georg Reichelt
  • 963
  • 1
  • 15
  • 36
  • The standard streams should already be saved as part of the test report. Is that not the case, or does it also run out of heap space even when `showStandardStreams` is not set? – Bjørn Vester Feb 07 '20 at 11:23
  • When `showStandardStreams` is not set, the problem does occur after more executions. For me, it appears after I set change the first loop to `for (int i = 0; i < 500; i++) {` (and maven still exits after ~40 seconds). In my real-world use case, the problem unfortunately also persists because its stdout is in similiar order of magnitude. Regardless of the GC-problem, it would be nice if I could use `showStandardStreams` in order to redirect the stdout directly also for big logs (instead of executing my process and analysing `build/test-results/test/binary/output.bin`). – David Georg Reichelt Feb 07 '20 at 13:07

1 Answers1

1

I don't really have a solution for you, but I want to share a few observations that are too long to put into a comment.

First of all, I can reproduce your OutOfMemory problem from your Github repository. I googled it a bit, and while there are other reports on OOM on this out there, none had a solution. I think it is just a limitation in Gradle when enabling showStandardStreams. I tried fiddling around with the console output type and a few other parameters, but none had an effect.

However, with disabling showStandardStreams, I would not get an OOM. Not even after bumping the number of iterations from 200*10000, that you specified, to 1000*10000. It worked fine and the output got saved to both a .bin, .xml and a .html file for later inspection.

What's more, Gradle ran it more than twice as fast as Maven on my machine:

λ time ./gradlew test &> gradle.txt

real    1m23.113s
user    0m0.015s
sys     0m0.031s

λ time mvn test &> mvn.txt

real    3m6.671s
user    0m0.183s
sys     0m0.566s

Not sure why there is such a big difference between the two.

While I completely agree that it would be nice to use showStandardStreams for large outputs, just like Maven defaults to, it appears it is just not possible unless you can afford to raise the maximum heap size accordingly. On the other hand, having the output saved in the report is also rather nice, which is something you don't get from the Surefire plugin in Maven.

Bjørn Vester
  • 6,851
  • 1
  • 20
  • 20