-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Imports: Speed improvement for importing subpackages #5100
Comments
This a good direction, I've done similar analysis in the past and agree we can do better. For your proposed steps:
The other thing which I think we can do here which was going to be a follow-up from #4958 as a multi-step process is to move matplotlib to not be imported at import time. The problem is which I found during #4958 is that doing this as I did there removes |
As laid out in Qiskit#5100, ``qiskit.visualization.transition_visualization`` is on the critical path for any ``qiskit`` import. This means that the imports in this file will always be imported. Profiling of import time showed that ``matplotlib`` was a slow import, and so should be deferred from the critical path.
As laid out in #5100, ``qiskit.visualization.transition_visualization`` is on the critical path for any ``qiskit`` import. This means that the imports in this file will always be imported. Profiling of import time showed that ``matplotlib`` was a slow import, and so should be deferred from the critical path. Co-authored-by: Kevin Krsulich <[email protected]>
This isn't a top priority, but I found another leaf import that could potentially be removed/delayed. |
Did you consider using lazy imports? Sometimes it can make troubleshooting more tricky. But the behaviour could be controlled by env variable. |
The scipy.stats submodule is a relatively slow import and takes up roughly 9% of our total import time. This is disproportionately large compares to its single use in the random operator generator functions which is not critical to any of the core functionality or performance critical. This commit shifts the module level import to be a runtime import to avoid this import cost, while this does add runtime overhead (and an initial cost on the first execution) that is worth the tradeoff to remove it from the default import path. Related Qiskit#5100
@drewrisinger yeah, I really want to push one to move matplotlib to be a lazy runtime import too. It'll probably meaning breaking anyone who is relying on |
Also, we should be able to remove networkx from the import path (which is surprisingly not cheap either) after #5183 merges which will speed things up a bit more |
* Move scipy.stats imports to runtime The scipy.stats submodule is a relatively slow import and takes up roughly 9% of our total import time. This is disproportionately large compares to its single use in the random operator generator functions which is not critical to any of the core functionality or performance critical. This commit shifts the module level import to be a runtime import to avoid this import cost, while this does add runtime overhead (and an initial cost on the first execution) that is worth the tradeoff to remove it from the default import path. Related #5100 * For probability_distributions circuit library too Co-authored-by: Kevin Krsulich <[email protected]>
* Move scipy.stats imports to runtime The scipy.stats submodule is a relatively slow import and takes up roughly 9% of our total import time. This is disproportionately large compares to its single use in the random operator generator functions which is not critical to any of the core functionality or performance critical. This commit shifts the module level import to be a runtime import to avoid this import cost, while this does add runtime overhead (and an initial cost on the first execution) that is worth the tradeoff to remove it from the default import path. Related #5100 * For probability_distributions circuit library too Co-authored-by: Kevin Krsulich <[email protected]> (cherry picked from commit c7c110d)
* Move scipy.stats imports to runtime The scipy.stats submodule is a relatively slow import and takes up roughly 9% of our total import time. This is disproportionately large compares to its single use in the random operator generator functions which is not critical to any of the core functionality or performance critical. This commit shifts the module level import to be a runtime import to avoid this import cost, while this does add runtime overhead (and an initial cost on the first execution) that is worth the tradeoff to remove it from the default import path. Related #5100 * For probability_distributions circuit library too Co-authored-by: Kevin Krsulich <[email protected]> (cherry picked from commit c7c110d) Co-authored-by: Matthew Treinish <[email protected]>
This commit removes the networkx usage in the ApproximateTokenSwapper to use retworkx instead. Besides being speeding up the execution of the pass what's more important here is that this was the last networkx usage in qiskit-terra (with the exeception of a couple compatibility converters in qiskit.dagcircuit). So this commit also makes networkx an optional dependency and updates the 3 methods (which are outside the common usage scenarios) to use runtime imports and emit a more detailed import error if networkx isn't installed. Fixes: Qiskit#5470 Related to: Qiskit#5100
…x optional (#5471) * Migrate ApproximateTokenSwapper to only use retworkx This commit removes the networkx usage in the ApproximateTokenSwapper to use retworkx instead. Besides being speeding up the execution of the pass what's more important here is that this was the last networkx usage in qiskit-terra (with the exeception of a couple compatibility converters in qiskit.dagcircuit). So this commit also makes networkx an optional dependency and updates the 3 methods (which are outside the common usage scenarios) to use runtime imports and emit a more detailed import error if networkx isn't installed. Fixes: #5470 Related to: #5100 * Remove unecessary duplicate None check * Add networkx to requirements-dev.txt There is a single dagcircuit test that uses the to_networkx() method. So we need to install networkx in test environments. * Remove _T type * Update releasenotes/notes/nx-optional-6b8ad63529fe32ca.yaml Co-authored-by: Lauren Capelluto <[email protected]> * Remove _V type Co-authored-by: Lauren Capelluto <[email protected]>
After #5471 and #5485 the import performance here is a lot better. The only 2 things after #5485 is finished and merges that will be good to do is remove the fastjsonschema import time compilation (which is deprecated and is just a matter of time) and then something for |
This commit moves the import of pydot and pillow import that were happening at the module level to be runtime imports. Both of these imports are only used if you're visualizing an equivalence library, which is normally only used for debugging the transpiler and basis translator which is not a common usage scenario. While pillow is pretty quick to import since it's mostly a C FFI package with a bit of stdlib xml. pydot on the other hand is a bit slower to import taking ~3% of the import time. While neither is a a huge bottleneck it's something we can remove from the default import path unless they're actually needed. Related to: Qiskit#5100
* Move equivalence drawer visualization imports to runtime This commit moves the import of pydot and pillow import that were happening at the module level to be runtime imports. Both of these imports are only used if you're visualizing an equivalence library, which is normally only used for debugging the transpiler and basis translator which is not a common usage scenario. While pillow is pretty quick to import since it's mostly a C FFI package with a bit of stdlib xml. pydot on the other hand is a bit slower to import taking ~3% of the import time. While neither is a a huge bottleneck it's something we can remove from the default import path unless they're actually needed. Related to: #5100 * Fix lint Co-authored-by: Kevin Krsulich <[email protected]> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit migrates the qiskit.Aer and qiskit.IBMQ module attributes to be lazy loading instances of lazy loading wrapper classes. The intent here is to avoid importing from qiskit-aer or qiskit-ibmq-provider from qiskit-terra, while this is safe while the packages share a shared namespace we've been actively working to remove the use of namespace packaging (see Qiskit#5089, Qiskit#4767, and Qiskit#559) and the circular dependency caused by re-exporting these attributes is blocking progress on this. By using a lazy loading wrapper class we avoid an import type circular dependency and opportunistically use qiskit-aer and/or qiskit-ibmq-provider at runtime only if they're present after everything is imported. This also may have some benefit for the overall import performance of qiskit (being tracked in Qiskit#5100) as it removes qiskit-aer and qiskit-ibmq-provider from the import path unless they're being used. Although the presence of qiskit.__qiskit_version__ might prevent any performance improvements as it still imports all the elements to get version information (and will be tackled in a separate PR). Fixes Qiskit#5532
This commit migrates the qiskit.Aer and qiskit.IBMQ module attributes to be lazy loading instances of lazy loading wrapper classes. The intent here is to avoid importing from qiskit-aer or qiskit-ibmq-provider from qiskit-terra, while this is safe while the packages share a shared namespace we've been actively working to remove the use of namespace packaging (see Qiskit#5089, Qiskit#4767, and Qiskit#559) and the circular dependency caused by re-exporting these attributes is blocking progress on this. By using a lazy loading wrapper class we avoid an import type circular dependency and opportunistically use qiskit-aer and/or qiskit-ibmq-provider at runtime only if they're present after everything is imported. This also may have some benefit for the overall import performance of qiskit (being tracked in Qiskit#5100) as it removes qiskit-aer and qiskit-ibmq-provider from the import path unless they're being used. Although the presence of qiskit.__qiskit_version__ might prevent any performance improvements as it still imports all the elements to get version information (and will be tackled in a separate PR). Fixes Qiskit#5532
This commit migrates the __qiskit_version__ module attribute away from using a dict constructed at import time to being an instance of a lazy loading class that will import the elements to get their version information only at run time if needed. This will improve the overall import performance and also reduce the possibility of introducing an import cycle when we remove namespace packaging. Related to Qiskit#5100 and Qiskit#5532
* Add a lazy loading wrapper class for __qiskit_version__ This commit migrates the __qiskit_version__ module attribute away from using a dict constructed at import time to being an instance of a lazy loading class that will import the elements to get their version information only at run time if needed. This will improve the overall import performance and also reduce the possibility of introducing an import cycle when we remove namespace packaging. Related to #5100 and #5532 * Rename qiskit.execute module to qiskit.execute_function The qiskit.execute module has a name conflict with the re-exported path to it's sole public function qiskit.execute(). Whether python uses the module or the function is an import time race condition and by making the element imports occur at runtime this switches the normal evaluation to use the module instead of the function. However, this was always a bug and could have been triggered in other ways too. To make the imports deterministic either the function or the module needs to be renamed and since the module is less commonly used than the function that is renamed. * Rename qiskit.compiler inner modules to avoid name conflict The qiskit.compiler module has a name conflict with the re-exported path to public functions qiskit.compiler. Whether python uses the module or the function is an import time race condition, amd could be triggered by subtle changes in import evaluation order. To make the imports deterministic either the function or the module needs to be renamed and since the module is less commonly used than the function that is renamed. * Fix docs build * Apply suggestions from code review Co-authored-by: Kevin Krsulich <[email protected]>
Thanks @mtreinish for being responsive and the tedious work that goes into this! |
* Wrap qiskit.Aer and qiskit.IBMQ with lazy loading object This commit migrates the qiskit.Aer and qiskit.IBMQ module attributes to be lazy loading instances of lazy loading wrapper classes. The intent here is to avoid importing from qiskit-aer or qiskit-ibmq-provider from qiskit-terra, while this is safe while the packages share a shared namespace we've been actively working to remove the use of namespace packaging (see #5089, #4767, and #559) and the circular dependency caused by re-exporting these attributes is blocking progress on this. By using a lazy loading wrapper class we avoid an import type circular dependency and opportunistically use qiskit-aer and/or qiskit-ibmq-provider at runtime only if they're present after everything is imported. This also may have some benefit for the overall import performance of qiskit (being tracked in #5100) as it removes qiskit-aer and qiskit-ibmq-provider from the import path unless they're being used. Although the presence of qiskit.__qiskit_version__ might prevent any performance improvements as it still imports all the elements to get version information (and will be tackled in a separate PR). Fixes #5532 * Fix lint * Fix test lint * DNM: test with ignis patch * Revert "DNM: test with ignis patch" This reverts commit ac9611c. * Use ignis from source for tutorial job * Update release note to be more clear
ok, I'm going to close this as all 3 of those PRs have merged now. To wrap it I just ran an importtime profile of which I think is a good enough improvement to go from ~1.1 sec to ~0.49 sec. With all the jsonschema usage currently being deprecated, >=3 months after 0.17.0's release when we remove the jsonschema bits we'll shave another ~0.05 sec off the import time. There is also cvxpy in there which is only used in one place and takes ~0.06 sec to import. But both of those times seem pretty minor. We can open up follow up issues or PRs if they get to be a bottleneck for people. |
* Wrap qiskit.Aer and qiskit.IBMQ with lazy loading object This commit migrates the qiskit.Aer and qiskit.IBMQ module attributes to be lazy loading instances of lazy loading wrapper classes. The intent here is to avoid importing from qiskit-aer or qiskit-ibmq-provider from qiskit-terra, while this is safe while the packages share a shared namespace we've been actively working to remove the use of namespace packaging (see Qiskit#5089, Qiskit#4767, and Qiskit#559) and the circular dependency caused by re-exporting these attributes is blocking progress on this. By using a lazy loading wrapper class we avoid an import type circular dependency and opportunistically use qiskit-aer and/or qiskit-ibmq-provider at runtime only if they're present after everything is imported. This also may have some benefit for the overall import performance of qiskit (being tracked in Qiskit#5100) as it removes qiskit-aer and qiskit-ibmq-provider from the import path unless they're being used. Although the presence of qiskit.__qiskit_version__ might prevent any performance improvements as it still imports all the elements to get version information (and will be tackled in a separate PR). Fixes Qiskit#5532 * Fix lint * Fix test lint * DNM: test with ignis patch * Revert "DNM: test with ignis patch" This reverts commit ac9611c. * Use ignis from source for tutorial job * Update release note to be more clear
…it#5619) * Wrap qiskit.Aer and qiskit.IBMQ with lazy loading object This commit migrates the qiskit.Aer and qiskit.IBMQ module attributes to be lazy loading instances of lazy loading wrapper classes. The intent here is to avoid importing from qiskit-aer or qiskit-ibmq-provider from qiskit-terra, while this is safe while the packages share a shared namespace we've been actively working to remove the use of namespace packaging (see Qiskit/qiskit#5089, Qiskit/qiskit#4767, and Qiskit/qiskit#559) and the circular dependency caused by re-exporting these attributes is blocking progress on this. By using a lazy loading wrapper class we avoid an import type circular dependency and opportunistically use qiskit-aer and/or qiskit-ibmq-provider at runtime only if they're present after everything is imported. This also may have some benefit for the overall import performance of qiskit (being tracked in Qiskit/qiskit#5100) as it removes qiskit-aer and qiskit-ibmq-provider from the import path unless they're being used. Although the presence of qiskit.__qiskit_version__ might prevent any performance improvements as it still imports all the elements to get version information (and will be tackled in a separate PR). Fixes Qiskit/qiskit#5532 * Fix lint * Fix test lint * DNM: test with ignis patch * Revert "DNM: test with ignis patch" This reverts commit ac9611c3ace30d101a70bda06e1987df14662182. * Use ignis from source for tutorial job * Update release note to be more clear
…t#5620) * Add a lazy loading wrapper class for __qiskit_version__ This commit migrates the __qiskit_version__ module attribute away from using a dict constructed at import time to being an instance of a lazy loading class that will import the elements to get their version information only at run time if needed. This will improve the overall import performance and also reduce the possibility of introducing an import cycle when we remove namespace packaging. Related to Qiskit/qiskit#5100 and Qiskit/qiskit#5532 * Rename qiskit.execute module to qiskit.execute_function The qiskit.execute module has a name conflict with the re-exported path to it's sole public function qiskit.execute(). Whether python uses the module or the function is an import time race condition and by making the element imports occur at runtime this switches the normal evaluation to use the module instead of the function. However, this was always a bug and could have been triggered in other ways too. To make the imports deterministic either the function or the module needs to be renamed and since the module is less commonly used than the function that is renamed. * Rename qiskit.compiler inner modules to avoid name conflict The qiskit.compiler module has a name conflict with the re-exported path to public functions qiskit.compiler. Whether python uses the module or the function is an import time race condition, amd could be triggered by subtle changes in import evaluation order. To make the imports deterministic either the function or the module needs to be renamed and since the module is less commonly used than the function that is renamed. * Fix docs build * Apply suggestions from code review Co-authored-by: Kevin Krsulich <[email protected]>
What is the expected enhancement?
IMPORT SPEED of top-level
qiskit/__init__.py
Inspired by @mtreinish in #4958 .
Currently, it takes on the order of seconds to import just the base
qiskit
package, and that doesn't improve if you only import subpackages (e.g.qiskit.pulse
) due to the top-level import of heavy packages in./qiskit/__init__.py
, e.g.qiskit.providers.ibmq
which are always imported.Here, I am mostly looking in this issue at import speed improvements in
qiskit/__init__.py
.Possible Import Improvements
I see a few possible solutions, ranked in order of more breaking changes:
matplotlib.animation
import inqiskit.visualization.transition_visualization
to the animation functionnetworkx
import inqiskit.circuit.equivalence
to thedraw()
and_build_basis_graph()
(only used indraw()
) functions so this isn't on the critical path every import.qiskit.circuit
imports to optionally disable them. (e.g.QISKIT_DONT_IMPORT_TOP_LEVEL
)Import Time visualization
This can be checked visually with:
Which yields (
qiskit-terra==0.15.1, qiskit-ibmq-provider==0.8.0
):which is similar to that in #4958 (I must have a slower computer/not be running on SSD):
We see that import
qiskit.pulse
ends up importing the top-levelqiskit
init file anyways. As a side note, I'd really prefer not to spend ~3 seconds importingqiskit-terra
every time.The text was updated successfully, but these errors were encountered: