-
Notifications
You must be signed in to change notification settings - Fork 155
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
Negative impact on configuration phase performance #182
Comments
I never ran any performance tests against axion-release, since we use repo-per-project, so I think there is plenty of room for improvement. Could you generate sample monorepo project for test purposes? |
@adamdubiel My totally unprofessional benchmark shows that
I ran it multiple times for each repo and picked lowest values I could get. |
Interesting.. Are you using tag with highest version mode or the default? EDIT: nevermind, i read build.gradle in the repo you provided. I will take a look at that, might be able to optimize something. |
this is the whole config we use (so the answer is "default")
|
I've dug into the code a little bit and I have an impression that retrieving I can work on that issue in my spare time but I need some guidance at the beginning. What do you think? |
I started writing JMH test to profile What are the "by the way" things that you found? |
I was in particular concerned about code starting from this point https://github.com/allegro/axion-release-plugin/blob/master/src/main/groovy/pl/allegro/tech/build/axion/release/infrastructure/git/GitRepository.groovy#L204 but after a 2nd look I get that order of tags returned isn't necessarily in the order we want. Anyway, 🤞 |
@tmszdmsk i think i just nailed the issue. I created very basic JMH test on Baseline version calculation time on repo with 1000 commits and tag located 100 commits from HEAD was 1.2 seconds. First fix was removing unnecessary call to repository in I suspected that reading and resolving all tags from the repo could be the culprit, however replacing it with dummy code did almost nothing for execution time. The only thing left was Reading Java docs of
The reason why execution time was bound to number of commits was actually reading & buffering all commits in memory. After removing topological sort and relying on default kind of "best effort", commit time based sort, execution time dropped to 300ms. Docs for default sorting state:
However all axion-release tests pass. Seeing the profits in execution time, i think it is worth giving a shot. Maybe i should add configuration flag which would force the old sorting method. Could you grab the code from |
and the winner is... |
Hmm i expected it to be a little faster, but thats a good sign anyways. I will merge all PRs, but have no idea where to look for more ms. Maybe the creation of object graph/DI? |
Also i think of adding some kind of cache on |
I remember I thought about that initially. Sounds great. Each versioned module has its own configuration with custom tag prefix. |
Hmm okay, so it will probably be bit more complicated, but sounds like a challenge :) I will be out for two weeks now, so i will get back to it in August. Should i release 1.8.0 before i disappear or it doesn't matter that much? |
it is not uber important right now ;) have a great vacations! |
another thing is that I can spend some spare time on it. Just write few words how you imagine adding cache. Some starting point would be useful! |
Okay, so on first thought i would embed all the logic somewhere in There are two things we can cache. One is calling GitRepository#tagsMatching. The cache can keep all tags and resolved commit ids (everything until Second one would be kind of incremental cache for RevWalk. The assumption is that repo will not change during build time (pretty sane one :)). So each time we call
This way we will:
I'm not sure how this cache should be shared between task executions, but if there are no hidden problems These are just quick thoughts on how to implement this kind of cache. Some things might not make sense when implementing, so treat it only as an inspiration, not the definitive guide :) And it would be great to add another simple jmh test case to see the difference easily. |
@tmszdmsk i have a first working version of cache. However i need to know one thing - is your monorepo a set of subprojects under single parent project? Or are these totally separate gradle projects? I'm wondering if cache should be kept in static field (might be risky due to Grade Demon caching whole JVMs). |
@adamdubiel we have one project with big list of includes in |
Okay, so the basic version works, but the results are not as great as i would expect. For hermes repository reconfigured to recalculate version for root project and each of the subprojects (15 times in total) cache shaves off ~50ms per run (0.7 seconds gained). However i would expect that gains in your monorepo will be much bigger. In Hermes distance from HEAD to tag is just a few commits. In repo with different versioning schemes, this distribution will vary a lot. During testing i noticed one more bottleneck: checking for uncommitted changes in repo. This takes between 100-200ms per version calculation! For Hermes repo this is the dominating factor. So, to wrap up (time is rounded to indicate order of magnitude):
Would you mind checking out the new version from |
Unfortunately, I've got exception: I don't have time right now to dig deeper. |
Looks like you repo contains commit with prefix matching configured tag prefix, which is not SemVer compatible (i.e. |
scmVersion{
tag {
prefix = 'alerting-tester'
}
}
project.version = scmVersion.version , $ git tag | grep alerting-tester
alerting-tester-0.1.0
alerting-tester-0.1.1
alerting-tester-0.1.2
alerting-tester-0.1.3
alerting-tester-0.1.4
alerting-tester-0.1.5 and works with axion-release-plugin from master. |
Damn ;) Okay, i will dig into this as well. |
I released 1.7.2 with first perf improvement (dropping TOPO sort), and here are the effects on one of my projects.
It's blazing fast now compared to the older one :) |
A brief test shows it's twice as fast for our monorepo. 👍 |
I'm sorry for pushing this even further away. I have some experimental code, but no time to actually test it and make it production-grade. You can either contribute or rely on my best-effort approach :) |
Hi @adamdubiel , do you have a PR/branch with your experimental code for Git caching? I can't promise that I'd be able to work on it, but I'd like to give it at try. Background: We have the same issue, but in addition to speed, we're running into heap memory issues on the Gradle daemon as the current way of doing things keeps a copy of the git-related objects around for every |
Yes, i do have this branch somewhere and while i'm not 100% sure, i think it would help. I can dig it up, the cache layer was pretty much finished, but i failed to integrate it with the whole project (lot of tests and constructors to change to pass it down the chain). |
If you could dig that branch up and push it, that would be greatly appreciated :) . |
I believe I am also hit by this ... experiencing long configuration phase if doing Did anyone manage to get some speedup somehow or it still needs the cache to be implemented. I am using plugin version |
@adamdubiel I did get an inspiration from your performance branch and created a PR #346 |
@adamdubiel will you get some time to look at the open PR for this issue? I would like to know if this approach is acceptable and can get to master any time soon. |
@JozoVilcek you've got some comments ;) |
We use
axion-release-plugin
in our git monorepo which consists of over 60 deployables. Profiling our build process revealed thataxion-release-plugin
is responsible for most of execution time in configuration phase. Withaxion-release-plugin
enabled it takes about 700ms, while w/o it is ~15ms. Of course if we multiply it by 60 it turns out that plugin adds ~45seconds to total build time of the whole repository.The text was updated successfully, but these errors were encountered: