-
-
Notifications
You must be signed in to change notification settings - Fork 15
Speed up the gradle test invocation #37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@@ -1,6 +1,6 @@ | |||
# === Build builder image === | |||
|
|||
FROM gradle:6.8.3-jdk11 AS build | |||
FROM gradle:7.1-jdk11 AS build |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Align version with the version used in the exercises
@@ -30,4 +30,9 @@ COPY --from=build /home/builder/autotest-runner.jar ./ | |||
# Copy cached dependencies | |||
COPY --from=build /home/gradle /home/gradle | |||
|
|||
RUN pkill -f '.*GradleDaemon.*' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is one stopped gradle
daemon in the image, those two lines remove it (and the time spent to look it up)
RUN pkill -f '.*GradleDaemon.*' | ||
RUN rm -rf ~/.gradle/daemon | ||
|
||
ENV GRADLE_OPTS="--add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.invoke=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.prefs/java.util.prefs=ALL-UNNAMED --add-opens java.prefs/java.util.prefs=ALL-UNNAMED --add-opens java.base/java.nio.charset=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/java.util.concurrent.atomic=ALL-UNNAMED -Xms256m -Xmx2048M -Dfile.encoding=UTF-8 -Duser.country=US -Duser.language=en -Duser.variant" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is one core change, basically, the --no-daemon
option passed from the command line was ineffective causing the startup of a daemon every execution (it was dominating the used time).
I struggled with this for a long and the only "solution/workaround" I've found is this:
gradle/gradle#2660 (comment)
This is ugly and weak (especially maintenance-wise) but is the only thing that actually works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, my investigations pointed out that no daemon was used, but I didn't know how to fix it. Great work!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andreaTP It looks like in the above changes you're killing all Gradle daemons, right? If so, would a running Gradle daemon that can be re-used when running the tests be faster than --no-daemon
? In some tracks, what I did is to build a "dummy" project to pre-load/cache things. I have no idea if that makes sense here though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what I did is to build a "dummy" project to pre-load/cache things
do you mind elaborating or providing a link? might be interesting to investigate further this path!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure! For Purescript, we have a regular exercise https://github.com/exercism/purescript-test-runner/tree/main/pre-compiled that we copy into the Docker image and then build/compile https://github.com/exercism/purescript-test-runner/blob/main/Dockerfile#L14. Doing a build/compile forces the Docker container to at least have loaded all the infrastructure once. Whether that is beneficial depends on the runtime that is used.
I tried using this approach with the Java test runner too, as I hoped that being able to re-use an existing Daemon that had already done some work might allow things to be sped up later. I couldn't get the gradle test
command to re-use the started Gradle daemon, but I think you could with the GRADLE_OPTS specified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't get the gradle test command to re-use the started Gradle daemon, but I think you could with the GRADLE_OPTS specified.
correct but it doesn't seem to produce great results ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, that could be because there actually isn't any Gradle daemon already running, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
correct
bin/run.sh
Outdated
@@ -22,5 +22,7 @@ cp -R $input_folder/* . | |||
|
|||
find . -mindepth 1 -type f | grep 'Test.java' | xargs -I file sed -i "s/@Ignore(.*)//g;s/@Ignore//g;" file | |||
|
|||
java -jar /opt/test-runner/autotest-runner.jar $problem_slug | |||
echo -e "test {\n maxHeapSize = '2G'\n reports.html.required = false\n}" >> build.gradle |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another important change in this PR, disabling unused reporting as mentioned here:
https://docs.gradle.org/current/userguide/performance.html#report_generation
and increasing the heap for the tests makes them much faster.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -22,5 +22,7 @@ cp -R $input_folder/* . | |||
|
|||
find . -mindepth 1 -type f | grep 'Test.java' | xargs -I file sed -i "s/@Ignore(.*)//g;s/@Ignore//g;" file | |||
|
|||
java -jar /opt/test-runner/autotest-runner.jar $problem_slug | |||
echo -e "test {\n maxHeapSize = '2G'\n reports.html.required = false\n}" >> build.gradle | |||
timeout 20 gradle test --offline --no-daemon --warning-mode=none --no-watch-fs --console=plain 2> gradle-test.err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved the external process execution from Java to the command line for a couple of reasons:
- faster iteration cycles (no need to recompile to change options passed to gradle)
- easier to change
- log handling for debug purposes
I think that I prefer this here, but I can revert this change if required, not fussy about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think those are all good arguments in favor of running this in bash.
java -jar /opt/test-runner/autotest-runner.jar $problem_slug | ||
echo -e "test {\n maxHeapSize = '2G'\n reports.html.required = false\n}" >> build.gradle | ||
timeout 20 gradle test --offline --no-daemon --warning-mode=none --no-watch-fs --console=plain 2> gradle-test.err | ||
java -jar /opt/test-runner/autotest-runner.jar $? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
slug
was unused (a leftover?) and here we are passing the return code of the previous command to re-use the error handling logic.
The observed speedup on my local machine running in docker is about:
I would be happy if someone from the maintainers can confirm or deny those numbers (and maybe test in an environment similar to prod). |
Thanks a ton work for working on this! I'll have a look next week, I'm terribly busy at the moment. |
@ErikSchierboom enjoy the weekend! 🙂 |
Wow. 1/3 speed-up already is really great @andreaTP!! |
This is great :)
For those of us not au fait, would you mind explaining a little more about what this would do pls? |
Sure @iHiD ! |
@iHiD I hope this explains! (Closed by mistake, sorry for the noise) |
Quick update just to share the experience, (aka another failed experiment 🙂 ). I thought that running the |
Nice. That sounds useful indeed! |
@andreaTP If I try to test this locally, I get the following error:
Any ideas? How did you test on your machine? |
@ErikSchierboom you are right indeed: I was unconsciously relying on cached results 🙁 still this PR trim down execution times around ~ |
@andreaTP Yes, that fixes it. I've tried to benchmark the differences but could not find any on my machine. Maybe I'm doing something wrong? I've tried to benchmark it by adding |
Hey @ErikSchierboom , I was testing against |
Thanks for having a second look @ErikSchierboom ! Takeaways:
I will try to have another look but seems like you have already maxed the performance of this design ...
I'm sorry that those experiments have failed, I'm available to have a chat on Slack about possible different approaches. |
I think discussing things here is probably best, as we then have a public record of the things we've looked into, which makes it easier for other people
I have no idea what the ramifications of that change would be, but if the test results are still the same, I'm fine with that. I'll leave it to @exercism/java to judge whether or not this is something to pursue.
|
I've investigated a bit more:
Basically, the very first Given all those failed attempts I'm drafting a PR to switch to Maven, exercism's builds are simple and pretty much constrained, of course, there are trade-offs, but might be worth giving this approach a spin! |
Nice. Thanks @andreaTP! |
Great! It's definitely worth a look. |
This is the aggregated result of digging into:
exercism/exercism#6097
Feel free to ask me to split this into multiple PRs if you are uncomfortable merging such a big change, I will do it tomorrow.
I'll comment inline the motivation for the various changes.