-
Notifications
You must be signed in to change notification settings - Fork 916
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
[spike] Improve Kedro CLI startup time #1476
Comments
Some older issues about this topic: https://github.com/quantumblacklabs/private-kedro/issues/930 & https://github.com/quantumblacklabs/private-kedro/pull/537 |
I created PR that should solve this problem in kedro-org/kedro-viz#1196 - any help with making tests passed would be appreciated |
(From #3033) Still an issue. For example,
After warmup (i.e. executing the command again immediately after) this can go down to ~1 second. Ahead of this I did some profiling using https://github.com/joerick/pyinstrument and https://www.speedscope.app/, and this is what I found: For |
Some users are puzzled that Today with @rashidakanchwala |
I don't know what happened lately but Kedro has got unacceptably slow. I'm raising the priority of this. |
On my computer, the first time it takes 24 seconds to run As a first step, we may need a better understanding of how slow Kedro CLI startup time is, and why. Some questions I have:
Then as a next step, we'd need an assessment on what can we do about this. Ideally it shouldn't take this long to run seemingly simple commands, even with a cold cache. Can we aim for a combination of slashing the time in ~half + showing something during those initial seconds so the user knows that it didn't get stuck? |
Profile of the command Note: this is when JSON: https://github.com/ankatiyar/kedro-profiles/blob/main/registry.json From profiling various commands, there's three main things (that take up majority of the time) that happen before the code for the specific command is executed -
That is almost 3s** before the actual code of the command is actually executed. ProposalOn perusing the 1. Lazy loading of subcommands on
|
super().__init__( | |
("Global commands", self.global_groups), | |
("Project specific commands", self.project_groups), |
2. Lazy loading of subcommands of Kedro
Quick prototype: #3883
This does not seem to save too much time, on my system, sometimes it does and sometimes it doesn't. 🤔
For eg, kedro info
is sometimes faster
Profile: LazyGroup
is used for both Kedro CLI and Kedro-viz CLI
3. Use after_command_run
on kedro-telemetry
We spend ~1s sending telemetry info before we actually execute the command. This can be moved to the after_command_run
hook which will not affect the actual total time of the command that is run but the results of the command actually show up sooner. Additionally, after_command_run
hook also receives the exit code of the command which might be useful telemetry info?
Profile of kedro info
and kedro registry list
with implemented suggestions
kedro info |
current | lazy viz | lazy viz + kedro cli | telemetry after_command_run |
---|---|---|---|---|
kedro/framework/cli/init | 3.37s | 1.97s | 2.15s | 2.05s |
KedroCLI init | 579ms | 649ms | 511ms | 473ms |
telemetry hook | 981ms | 867ms | 1.02s | 1s |
time before command is executed (approx) | 3.2s | 1.80s | 2s | 1s |
kedro registry list |
current | lazy viz | lazy viz + kedro cli | telemetry after_command_run |
---|---|---|---|---|
kedro/framework/cli/init | 5s | 3.6s | 4s | 4s |
KedroCLI init | 705ms | 649ms | 417ms | 486ms |
telemetry hook | 959ms | 877ms | 1.01s | 1.02s |
time before command is executed (approx) | 3.25s | 1.80s | 1.8s | 900ms |
Please note that this is just from one run of the commands, the time varies a little bit between each run of the command ^
Conclusion
Of the above suggestions, I think we would benefit greatly from making the Kedro-viz CLI either lazy or lighter. Moving to after_command_run
hook on kedro-telemetry
would also make the apparent time taken by the commands much faster.
On Kedro side, it's not super beneficial to make the subcommands lazy but we could do it to make things like kedro info
slightly faster
ALSO:
The JSON files if you want to open them in speedscope.app
yourself - https://github.com/ankatiyar/kedro-profiles
Miro board with the above screenshots + also same thing for kedro info
- https://miro.com/app/board/uXjVKFQAxA4=/?share_link_id=239496676079
Thanks a lot @ankatiyar, this is an awesome summary. There is one thing I think might be preventing us from getting useful results though. Consider this comparison between how much time it took to run First thing in the morning: Right after: These is my environment. Notice that I have a different one (with
I don't know if it's something specific to my computer (2021 MacBook Pro, Apple M1 Max, 32 GB of RAM), but I anticipate that this will probably make effective performance measurements quite hard. Some pointers, in case it helps: |
Having said that, if at least the times are ~proportional in the cold & hot cache situations, then this doesn't affect anything and we can proceed with confidence. |
I don't know if the architecture of pluggy or kedro allows this, but if we don't expect plugins to be able to add pipelines to the registry, maybe we should try to delay the plugin discovery process as much as possible. If one runs |
Update re: Lazy Loading of PluginsTLDR: It's possible to lazy load plugins and their commands on Kedro side Prototype PR: #3901 Profile of regular
|
class CommandCollection(click.CommandCollection): |
CommandCollection.list_commands()
, add plugins till it is.Profile of kedro registry list
with lazy loading of plugins
Send telemetry info in after_command_run
[Out of scope]
See: kedro-org/kedro-plugins#709
As mentioned in #1476 (comment), this would not reduce the TOTAL time taken by a command but will reduce the apparent time taken by the command.
Profile of kedro registry list
with lazy loading of plugins + telemetry after_command_run
Profile data
kedro registry list |
regular | with lazy plugin loading | lazy + telemetry after |
---|---|---|---|
initialisation of CLI module | 858ms | 576ms | 553 |
KedroCLI init | 4.11s | 270ms | 287ms |
sending telemetry | 1s | 0.8s | 1s |
time before the main code runs | ~6s | ~1.7s | ~0.8s |
total | 6.96s | 3.76s | 3.8s |
kedro info |
regular | with lazy plugin loading | lazy + telemetry after |
---|---|---|---|
initialisation of CLI module | 860ms | 737ms | 846ms |
KedroCLI init | 3.97s | 292ms | 304ms |
sending telemetry | 1.05s | 880ms | 858ms |
time before the main code runs | ~5.7s | ~1.9s | ~0.8s |
total | 5.99s | 2.03s | 2.12s |
Things to note
- It might take same or more time to run plugin commands - there might be a better way to load only the plugin for which the command we're running than just iterating through the entrypoints till we load the plugin which has the command
- There'll also be some delay when the command is wrong or doesn't exist. For eg
kedro infroo
will take a while before the error message is displayed because we'll spend some time loading plugins. I don't think this is too bad since we eagerly load these commands already right now. - We could still consider combining this with the
LazyGroup
strategy in Refactor CLI with lazy subcommands and deferring imports kedro-viz#1920 and Lazy load click subcommands #3883 or just look into improving the CLI setup onkedro-viz
in general. Kedro viz could be sped up a little bit by delaying imports at least 🤔
I'm amazed |
Yeah in this case it would make sense to make it async, but... pytest-dev/pluggy#320 |
I was just testing the switch to I'll create a separate issue for |
We still have the project hook that send telemetry immediately after. We should combine the two hooks to avoid checking consent twice as well. |
For now, shall we then proceed with ? How does kedro-org/kedro-viz#1920 interact or conflict with #3901 ? |
These solutions can be used together of course,
I think it's definitely worth refactoring CLI code on There's another thing to note - After lazy plugin loading (i.e after #3901), we lose the plugin commands from the top-level help text: But you can always do |
Good point about losing visibility of the full list in |
Are there any contraindications to:
This way, once loaded, the process with libraries would be ready to fork, unless stopped using cli command. |
@znfgnu IPython essentially? |
I think - and correct me if I'm wrong - the suggestion is about creating a long living kedro process and then a client process expose the CLI and can interact with it without the start-up penalty |
Would the user need to do anything differently? If we can make this almost invisible to the users then it's great. Is there any examples of Python base CLI doing this? |
The current notion of Kedro is that it's a library and a framework. I don't think we should underestimate the consequences of making it a service, in terms of software architecture, reusability, perception etc. Feel free to open a new discussion https://github.com/kedro-org/kedro/discussions/ |
Discussed in Tech Design on 19th June: Two approaches discussed:
The drawbacks of second approach:
Decision: To go with approach 1 for now - lazy subcommands on Kedro and Kedro Viz with delayed imports, and make sure that the help texts still show up. |
Dropping this here as a interesting historical reference.
https://peps.python.org/pep-0690/#motivation (rejected) This is just a hard problem in Python in general. |
Any follow-up tasks here @ankatiyar? Should we then encourage plugins to make their CLI groups lazy, do we need any documentation updates, are we going with the |
kedro-org/kedro-plugins#707 Same question as above, are we still planning to move telemetry to |
Thanks, I had lost track of that PR. The other questions stand |
@noklam @astrojuanlu
Both are in current sprints of framework and viz respectively. Not sure about docs, maybe we can add a recommended way to define CLI commands i.e. with |
yes! |
Description
Currently, Kedro CLI startup time can be slow even if very little work is done, for example, doing
kedro
to show the available command or help can take a few seconds. These commands should feel instant since it is just printing out some help text without any heavy work.Useful tool to profile import time
python -X importtime run.py
kedro
command itself takes 0.7s, which isn't fast but still an acceptable response time. Initial investigation suggests that it can take few seconds mainly due to a slow import during plugin registration.Kedro startup time with plugin installed
(0.7s, removed screenshot)
Kedro startup time with no plugin installed (telemetry + viz)
Causes:
kedro
itselfpkg_resource
(something that is run withconsole_script
)Context
Why is this change important to you? How would you use it? How can it benefit other users?
The Kedro CLI can be slow sometimes and lead to a bad user experience. It should be the most common way that users interact with kedro.
Possible Implementation
(Optional) Suggest an idea for implementing the addition or change.
The first improvement that can be done is to do lazy loading in plugin registration to address (1). (2) & (3) will requires more time to study.
Possible Alternatives
(Optional) Describe any alternative solutions or features you've considered.
Compile some of the kedro CLI, so it prints out help message without actually loading any python code.
e.g.
kedro
-> Load some pre-compiled text files and print, it may be tricky with plugins though.The text was updated successfully, but these errors were encountered: