This message was deleted.
# community-support
s
This message was deleted.
j
Gradle repo itself is a monorepo with multiple gradle modules which has more than 1 million of lines.
r
Yep. But as an Android project, the whole build process has many serial actions, e.g. Android Transform. So theoretically it’s impossible for us to build as fast as Gradle. And now we are facing many build performance problems in our monorepo. Maybe it’s Google’s responsibility to optimize this?
t
how is your project currently structured? what do you mean by "make into a monorepo"?
r
For now, we have different gradle modules in different git repos. On CI, all the library modules are artifacts(jars and aars). On the local PC, we use dependency substitution to transform some artifacts into source code so we can change the code in library modules. As for “make into a monorepo”, we’re going to put all of the code into one git repo and structure the whole project as one Android Gradle project. To build the app, all the library modules will participate as source code. So it becomes much more slower than before. Because most modules are artifacts before.
c
What were separate tepid before would become sub projects (modules) in a Gradle multi module project. Gradle will only build what is necessary (what had changed), and run module builds in parallel. As noted earlier the Gradle project itself is an example of this. Modules still create (but don't necessarily publish) artifacts that are consumed by other modules.
r
Yep. For “Gradle will only build what is necessary”, I think you mean Build Cache or Incremental Build. As we have Java and Kotlin in our project, many compile task will not
UP_TO_DATE
or
FROM_CACHE
if we change some code in base modules, even if the changes are non-abi changes. For “builds in parallel”, as I mentioned before, there are many tasks can not be built in parallel in Android build process. And the configuration phase spends much more time than before, too. And it’s hard for us to use configuration cache. And if there’s no cache, it will be really painful.
In Bazel, scripts are run in parallel, too. Maybe Gradle can do initializing and configuration in parallel to optimize these phases?
And is it possible for Gradle to support distributed build so we can build faster even there is no build cache
s
You are misreading that doc imo. You would split the project into modules (subprojects) when there is a natural split (common, client, server e.g.)
☝️ 1
I do not do Andoid development so I cannot speak to the feasibility of breaking things down into separate jars. But Android aside, that decision is a function of your project, not lines of code
Shoot should have used lmgtfy 😉
Oh, and that doc even has a specific discussion for Android = https://docs.gradle.org/current/userguide/performance.html#suggestions_for_android_builds
We use parallel builds in Hibernate - they work well. But if you have just one single module you are not going to be able to leverage parallelism nearly as much
💯 1
A corollary would be parallelizing something on a single core machine
k
FWIW, we have an Android app w/ 1000+ modules and 1.6M LoC in a monorepo...Square's repo is up to 3500+ modules last I heard too...
r
@Steve Ebersole thanks for your kind reply. We have already enabled parallel build. But for Android build, it will handle all of the ByteCode in one kind of task called Transform. Transform tasks run serially and cost lots of time.
@Ken Yee How long does it take for your project for full build and incremental build? And do all module participate in every build?
k
M1 builds are around 13min for full build..incremental is 1min, and yes, all modules. Transform runs serially on each modules AFAIK...
r
@Ken Yee Wow, that’s really fast. As for transform, we have many transforms in the application module to handle all of the bytecode, so it’s really a bottle neck for our build. Maybe we can register them in every library module to make them run in parallel?
🤷 1
s
Not sure what to tell you... Hibernate is a very complicated build. That's not why I broke things out into separate modules though. In my opinion (well not just mine, this is general best practice) you do this to properly define dependencies and get away from silly stuff like optional xdependencies
💯 1
As for parallel, you asked about parallelizing the init phase... just pointing out that that is utterly pointless when you have a single module
r
@Steve Ebersole Actually we have about 500 modules not one single module. Maybe I didn’t express clearly.
s
Awesome. Did you read the link I posted?
Build scans help immensely in identifying things you can improve
Anyway, depending on how well/poorly your modules isoltae themselves (this is different than dependencies between them) making it parallel may help or may not
r
@Steve Ebersole Yes, I read it and we have already make some optimizations in our projects using build scan. About parallelity, I agree with you. Maybe we can make our modules isolate better then. We didn’t pay much attention on it before. Thanks a lot.
@Ken Yee By the way, I wonder that do you enable configuration cache in your Android project? We find many problems when we try to enable it in our project.
👍 1
s
The easy ones to drop are (1) the use of allprojects and subprojects and (2) any other direct refs across projects
Enabling build-cache requires even more strictness to work properly
Not to mention that the tasks you use have to explicitly support it
(see
@CacheableTask
)
r
@Steve Ebersole Got it. I have read
@CacheableTask
and documents about build cache. We found that build cache doesn’t work well when we have Kotlin together with Java in our project. Kotlin didn’t adapt to Gradle’s compile avoidance and made its own way to perform compile avoidance. This may be the root cause.
s
No idea. I don't develop in Kotlin
c
^^^ that’s referring to incremental compilation; caching is still in play - when nothing has changed, pull from the cache. Incremental is about when something has changed, compile the smallest set possible.
s
@Chris Lee CacheableTask? that absolutely is about build-cache
it actually has no bearing on up-to-date
c
This:
Kotlin didn’t adapt to Gradle’s compile avoidance and made its own way to perform compile avoidance.
s
ah
The other thing I found with build-cache @Rex Sun... it is CRITICAL that you get inputs and outputs correct
💯 2
Which is harder than you might expect
E.g. tasks have to specify relative paths (absolute is the default), etc
If these are tasks you wrote... no problem (well, within having to find and verify them)
c
^^^ that for semantic correctness, plus use Property/Provider to ensure lazy evaluation of values (if at all) and inferred dependency tracking between tasks.
s
Might help to qualify
^^^
😉
c
Steve Ebersole [6:37 AM]
The other thing I found with build-cache @Rex Sun... it is CRITICAL that you get inputs and outputs correct
Steve Ebersole [6:37 AM]
Which is harder than you might expect
Steve Ebersole [6:37 AM]
E.g. tasks have to specify relative paths (absolute is the default), etc
Steve Ebersole [6:38 AM]
If these are tasks you wrote... no problem (well, within having to find and verify them)
s
I think maybe you misunderstood me? When I said it is critical to get the inputs and outputs correct what I mean is that otherwise it is very likely you get incorrect results from the build cache
c
that is correct. my comment was to layer on Provider/Property in addition to that.
s
As an example... on one
processResources
I replace text during the copy
at first we would often get bad "hits" from the cache which is hard to track down and very bad. the fix was easy once i identified the problem by manually adding that variable to
processResources
as an input
💯 2
j
I just did this exact thing recently for Kotlin project going from 3 repos into 1. What I did first was to bang out a prototype of it to see how it all works. All my separate projects were already gradle projects so its relatively straight forward to combine them and test stuff out from a performance and workflow perspective. My over all developer workflow time improve and our build time was faster that building 3 projects separately.
💯 1