Skip to content
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

Initialization of io.cucumber.core.runner.TestStep causes performance issues #2755

Closed
flowerrrr opened this issue May 16, 2023 · 5 comments
Closed

Comments

@flowerrrr
Copy link

flowerrrr commented May 16, 2023

After we upgrade our cucumber libs to a version that contained commit 5831903 we experienced a significant performance problem when running our cucumber scenarios.

Our test suite is quite big, we have ~10.000 scenarios with 5 to 30 steps. Execution time dropped from ~5 mins to ~10 mins after the version upgrade. That is, when the tests are run with Intellij. Same tests run with gradle build only shows a moderate performance decrease of about 20%, from 5 min to 6 min.

We could trace the problem to the initialization code of the class io.cucumber.core.runner.TestStep. Every time a new instance of the class is created (which happens for every step executed, ~100.000 times during a run of all scenarios) the method io.cucumber.core.runner.TestAbortedExceptions#createIsTestAbortedExceptionPredicate is executed. Since we don't have all the tested exceptions in our class path (when run in the IDE), every invocation of the method produces 3 ClassNotFoundExceptions and these seem to be the cause of our performance problems.

I see two solutions:

  • make io.cucumber.core.runner.TestStep#isTestAbortedException static, so it is initialized only once
  • defer initialization of the Predicate until it is actually needed (in case an exception has to be mapped).

If need be, i could provide a PR.

Thank you.

@mpkorstanje
Copy link
Contributor

I would be happy to accept a PR for this.

@jkronegg which of these do you think is the better option?

@jkronegg
Copy link
Contributor

@flowerrrr Are you sure this performance issue is related to the Predicate<Throwable> instance creation ? IMHO, most of the execution time comes from the Predicate<Throwable> execution (you can't get a ClassNotFoundException until the predicate is executed), see

static Predicate<Throwable> createIsTestAbortedExceptionPredicate() {

If I'm correct, you should have a lot of Exceptions that are thrown in your code. If you don't notice them, could it be possible that they are swallowed somewhere ? There are some swallowing mechanisms in Cucumber and I not sure this is working properly, e.g. see #2748

The Predicate<Throwable> execution performance has been improved through #2666 : performance can still be 2x faster by caching the classes in a static classloader, but this will change the code behavior, so I'm not sure this is the way to go.

This aside, regarding your proposed solutions, and considering that Exceptions should be exceptions, I would defer the Predicate creation until we need to evaluate it. This way, TestCase instance creation will be faster.

@flowerrrr
Copy link
Author

Oh, i see that the issue is already fixed in version v7.11.0 with this commit: f53abb6
Sorry for the confusion, i was still on an old version.

@jkronegg
Copy link
Contributor

@flowerrrr 5 minutes for 10'000 scenarios is relatively fast, but you could have even better performance with Cucumber 7.12.0 by adding the following property:

cucumber.uuid-generator=io.cucumber.core.eventbus.IncrementingUuidGenerator

see https://github.com/cucumber/cucumber-jvm/tree/main/cucumber-core#event-bus

@flowerrrr
Copy link
Author

Adding the property did produce a modest improvement of ~5%.
Thank you for the tip.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants