-
Notifications
You must be signed in to change notification settings - Fork 76
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
Improve tests performance #1027
Comments
Great initiative! 🙌 I share with you a couple of learnings in the hope it helps. I think what's good about the options proposed is that they not mutually exclusive. Tests parallelisationSeems to me one of the the most impactful in terms of raw performance, and scales horizontally. However, I'm still blocked in trying to make it work, as there's some black magic:
To make it work, we need to find a way to tell At this point I'm yet not sure There are other options like https://github.com/browsertron/pytest-parallel that could be worth the test. Parameters cachingParameters seem to be loaded just once per test suite. If that's the case, it could humbly improve performance by a fixed amount, independent of the number of tests to be run, at load time (right after launching If it's not, then it could be actually interesting. Still, big questions for me would then be:
Native YAML parserCurrently, if you have Performance gain is substantial, however, as with the caching, by an almost fixed amount, as those seem to be operations that are run just once per test suite. However having a native strategy as a default could indeed simplify things. Install libyaml in CIIt seems to already be the case, at least for core: we're using Docker's Python 3.7 container, which depends on buildpack-deps's, which installs All other suggestions to explore are welcome!Out of my head some things we've at some point considered, that could need of course further exploring. All of them are based on the hypothesis that the most expensive operation is
Hope it helps! 😃 |
Native YAML parser
Without CLoader: Average = 12m 19s With CLoader: Average = 11m 46s The outcome is not what I expected, consequently I tested
I got the following :
CircleCi parallelism
With 4 containers : Average : 6m 12s With 3 containers : Average : 8m 52s With 2 containers : Average : 10m 44s Please note that these tests ran on almost perfect conditions with no other builds running simultaneously. Obviously the more containers we use, the shorter the test time. However, the bandwidth can only be stretched so far and all the other builds will be waitlisted. A possible high cost low effort solution would be to upgrade the CircleCI plan adding more levels of parallelism Tests caching:Inspired by PR #1311. It might be interesting, as a first step, to try caching the tests before caching the parameters, since the parameter usage is more complex than that of the tests. To see if has any effect, I tested using
And I got:
Additional profiling is needed to determine how much testing time is actually spent loading the test files. |
Thanks a lot @maukoquiroga for your insights and references, super useful! And thank you so much @HAEKADI, this is great data! Conclusions
Uncertainties left to explore
I set aside all the calculations optimisation to focus on Core-level actionable improvements, as I believe such solutions forward complexity onto contributors. It is however clear that at some point this will be the way forward, and providing guidelines for performance would be useful. This would need a strong investment in profiling. Non-technical options
|
@HAEKADI could you please have a look at these first 4 items? 🙂 |
How many times parameters are loaded in a test run?In an
How many times test files are loaded in a test run?With How much would it cost to add 2 / 4 / 8 / 16 containers from CircleCI?With our current free plan, we run 4 concurrent job runs. The next tier plan is the performance plan, which offers 80 concurrent job runs. With a monthly fee of 30$ (minimum), we get 50,000 credits. I have contacted the support team at CircleCI to ask for more details pertaining to our case. I am still awaiting their reply. How long do the tests take when executed with GitHub Actions?I've tried running a simple configuration on GitHub Actions to test I only ran the build and test jobs, since the latter is the most problematic and time consuming. I did not add the linting jobs. The resulting times:
Average: 12min 12s GitHub Actions does not keep a history of successful runs, so I can only link the last run. To compare, CircleCi ran the build job in 8m 50s. With the free GitHub Actions plan, we get 20 concurrent jobs. GitHub Actions does not offer a parallelism option like CircleCI. However, jobs run in parallel by default. Consequently, in order to optimise performance, we need many jobs running simultaneously. Since yaml testing is the black sheep of the bunch, I used a strategy matrix to divide the yaml tests into 10 and then 20 jobs (20 being the limit offered by the free plan). The resulting run times: With 10 jobs:
Average: 3min 5s Just to compare, on CircleCI the build run took 8min 15s. With 20 jobs:
Average: 2min 40s On CircleCI the build run took 7min 49s. The downside of this split is that the yaml tests will not be split based on test duration, which means that some instances run longer than the others. CircleCI does store historical data of each tests duration and splits the test files based on running duration. From this initial benchmark, the results are promising. It does seem that GitHub Actions runs faster than CircleCI. And so there is a real decision to be made as to which one should be chosen. GitHub Actions hasn't been around as long as CircleCI, consequently the level of documentation and community size is not the same. Obviously, there is a lot to be said for having the code and the CI on the same platform. However we should keep in mind that with the free plan we are limited to:
|
Thank you very much @HAEKADI! I updated the table at the beginning of this discussion. Caching parameters could thus save us 4 to 5 seconds out of a 10 minutes run in a large codebase such as OpenFisca France. If I understand correctly, parallelisation seems the most relevant option. GitHub Actions would enable more parallelisation for free, but with a loss of history after 90 days, and a maximum of 2000 free minutes per month. It is also not extendable beyond 20 workers, even if paying. On the other hand, CircleCI has the advantages of years of accumulated experience and practically no limits to expansion as long as we pay accordingly. Both services seem comparable in terms of raw performance. In order to present the arbitrage properly, we need to know:
@HAEKADI can please you collect this information? 🙂 |
|
Thank you so much for this detailed, sourced comparison @HAEKADI! This is excellent work and the best decision basis we could wish for 👏 Based on it, the only downside I see with GitHub Actions is that we lose logs after 3 months. We regularly reference build runs in issues or pull requests, and some decisions are taken based on them, most of all regarding performance. I believe it can be acceptable to have only worflow-level metadata (which is kept indefinitely), and to learn to copy-paste in the issue body the subset of the logs when we make a decision based on them. This would allow us to increase parallelism (and thus test speeds) five fold. This would also increase vendor lock-in with GitHub, but this seems acceptable to me considering we can always revert to some other provider if we ever decide to migrate away from GitHub, and that this is not currently planned. I'll open an RFC for switching from CircleCI to GitHub Actions. Meanwhile, do you feel like investigating the two remaining elements:
If this is not obvious and you need more context, I unfortunately don't have enough technical knowledge to provide much more, so we can also wait for @maukoquiroga to handle this at some point in the future 🙂 |
The switch to GitHub Actions seems to have alleviated the concern with tests speed on CI. Further possible improvements, i.e. changing Python compiler and interpreter, seem to have way stronger technical consequences. While they might be considered in the future in case they are deemed necessary, the issue of tests performance seems to have been enough under control that no community member complained about tests speed since implementation of #1030. I will thus close this issue 🙂 Thanks to all the people who made this dramatic improvement a reality 👏 |
It would be useful for all country packages to improve the speed of tests, and to improve the speed of computations in general. Currently, running all tests in the most complex tax and benefits system (
OpenFisca-France
) takes 10 to 20 minutes in CI, and users report the same duration locally (#1025).This issue aims at consolidating potential venues for performance improvements, associated costs, risks and expected benefits, in order to define the best implementation strategy for a team with limited resources that cannot tackle all at once.
libyaml
libyaml
in CIDetails
Native YAML parser
The “Native YAML parser” option consists of assessing whether
libyaml
, currently suggested as an optional dependency as it speeds up parameter and tests loading by using a native compiled extension instead of the native Python YAML reader, could not be added as a systematic dependency. The last assessment dates back from a few years and revealed platform-specific incompatibilities. Maybe this has been fixed in upstream. There might be also be an alternative option that fits the same purpose with less incompatibilities.Strategy & contributions
libyaml
in CI” options.The text was updated successfully, but these errors were encountered: