-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Parallelize bean scanning in SmallRyeFaultToleranceProcessor #45509
Comments
/cc @Ladicek (smallrye), @jmartisk (smallrye), @phillip-kruger (smallrye), @radcortez (smallrye) |
Could you try getting us some profiling data following the instructions in https://github.com/quarkusio/quarkus/blob/main/TROUBLESHOOTING.md#profiling-application-startup-with-async-profiler ? Don't hesitate to ping me here or on Zulip if you need help. |
@gsmet sure! Is this sufficiently detailed or are you searching for something specific? |
I think it would be interesting to see what's going on in Do you have a lot of methods annotated with fault tolerance annotations? |
My wild guess is that it's going to be the |
Could you try this small patch: #45512 ? I wonder if it could help. There are instructions on how to build Quarkus here: https://github.com/quarkusio/quarkus/blob/main/CONTRIBUTING.md#building-main (but you need my PR code instead) and also instructions on how to update the version in the following paragraph. That being said, in your profiling, it doesn't look like it's Fault Tolerance taking the most time? Let me know how it goes. |
BTW, your startup looks interesting so I would really be interested in the full HTML output of Async Profiler so that we can have a look at the full details (see instructions in my first comment above). |
Agree with @gsmet that Other than that, it should be relatively straightforward to parallelize FT scanning. Just not sure if that's necessary at the moment. |
@Ladicek it might also be a good idea to drop the |
But TBH, I'm very very curious of what's going on in the two |
Good point @gsmet, we already have those |
FYI I'm working on extracting the info that was requested. Will reply here in a bit. |
@gsmet :
I'm not used to working with AsyncProfiler, so I'll first share the details from JProfiler and try the patch. Afterwards, I'll provide the details from AsyncProfiler. JProfiler export & screenshots: I'll now try with the patch and report back afterward. |
Results with your patch: The FaultTolerance step is no longer significantly slower than the other build steps: Thank you all for the prompt responses & actions! Let me know if I can help with smth else. Or if there are other tips & tricks I could check out to speed up the live reload :) |
Nice! I'm still wondering why you would get it called so many times if you have so few methods annotated with FT annotations. I would very much be interested in you getting me a picture of what's going on in the two I'm not sure we will be able to improve things but you are pushing things to the limit and it's an interesting use case to collect data as an extreme use case sometimes underlines some issues we can fix. |
I had a look at the call tree zip above. I think it would be interesting to have a closer look at the details in Do you have a lot of Panache entities? If you're coming from WildFly, I would suspect you're not using Panache yet? I'm very interested in having the details of the profiling for this one (together with the |
The JProfiler html export is indeed a static file it seems. So I can expand the full tree, but that makes the html very unreadable. I'll see if I can get async profiler up and running.
Case 1: This one is interesting ( Could be caused by this find&replace that I still need to do: Case 2: Case 3: Also an interesting one I think: |
Hmmm, it's a shame we don't have more details about what's going on in |
As for the rest:
Case 1: yeah I think this should go away once you fixed the warnings, which is good news. // - iterate over dependencyMap entries and process beans for which all dependencies were already processed
// - when a bean is processed the map entry is removed
// - if we're stuck and the map is not empty, we found a circular dependency (and throw an ISE)
Predicate<BeanInfo> isNotDependencyPredicate = new Predicate<BeanInfo>() {
@Override
public boolean test(BeanInfo b) {
return !isDependency(b, dependencyMap);
}
};
Predicate<BeanInfo> isNormalScopedOrNotDependencyPredicate = new Predicate<BeanInfo>() {
@Override
public boolean test(BeanInfo b) {
return b.getScope().isNormal() || !isDependency(b, dependencyMap);
}
};
Predicate<BeanInfo> isNotProducerOrNormalScopedOrNotDependencyPredicate = new Predicate<BeanInfo>() {
@Override
public boolean test(BeanInfo b) {
// Try to process non-producer beans first, including declaring beans of producers
if (b.isProducer()) {
return false;
}
return b.getScope().isNormal() || !isDependency(b, dependencyMap);
}
};
boolean stuck = false;
while (!dependencyMap.isEmpty()) {
if (stuck) {
throw circularDependenciesNotSupportedException(dependencyMap);
}
stuck = true;
// First try to process beans that are not dependencies
stuck = addBeans(beanAdder, dependencyMap, processed, isNotDependencyPredicate);
if (stuck) {
// It seems we're stuck but we can try to process normal scoped beans that can prevent a circular dependency
stuck = addBeans(beanAdder, dependencyMap, processed, isNotProducerOrNormalScopedOrNotDependencyPredicate);
if (stuck) {
stuck = addBeans(beanAdder, dependencyMap, processed, isNormalScopedOrNotDependencyPredicate);
}
}
} being quite heavy when you have a looooooot of beans and doing a lot of
I will ping @mkouba @manovotn and @Ladicek in case they want to poke in this area. |
I think you should probably focus on getting more info about the Hibernate ORM enhancer part. I'm not sure how easy it would be to improve things but I think it's worth trying to understand what's going on and if we can improve. |
@Sanne worked specifically on improving enhancing large models in 2024, and made very significant improvements -- at the cost of increased complexity (I don't follow what's going on, personally :) ). Which version of Quarkus are we talking about?
This class is about all enhancement except the Panache ones. It's absolutely needed, unfortunately. |
We're currently on FYI we have a single persistence unit with 159 entities. |
Okay, then you should be benefiting from the performance improvements already, added in 3.14: #40329 It's odd though, those improvements brought enhancement down to ~1s for a (presumably much larger) test model, so 159 entity types shouldn't be that slow... Though knowing Sanne, his computer is probably very, very powerful and fine-tuned, so there's that :] |
TBH I'm not sure if it's the profiling making things slow but the numbers are quite high, compared to what I would expect. |
It's been a while so I don't remember all details, but at high level: there are two different phases in which the Hibernate enhancer is applied: one for regular entities getting enhanced, and one for enhanced proxies being generated. Please bear in mind that the model that I had been optimizing (the one which should now take about 1s) was a model which had a lot of regular entities but very few cases of enhanced proxies; my optimisations had been applied for the first case but there's still room for improvement on the enhanced proxies case. I'd hope to return to that eventually, but I don't have an "interesting" user report or a benchmark to focus on; perhaps we should generate a syntetic one. |
Description
Current behavior:
Beans are scanned sequentially here: https://github.com/quarkusio/quarkus/blob/main/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/SmallRyeFaultToleranceProcessor.java#L234
According to the build metrics, this build step takes about 50% of the total build time. We have 1500 beans in our application.
Desired behavior:
Is there a way to perform bean scanning in parallel?
I'd be happy to contribute if someone could point me in the right direction. I checked other build steps, but I couldn't find any parallel behavior, so I'm not sure where to start.
Implementation ideas
No response
The text was updated successfully, but these errors were encountered: