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

Defer importing ens._normalization to speed up web3 import by 27% #3285

Merged
merged 2 commits into from Mar 20, 2024

Conversation

szemate
Copy link
Contributor

@szemate szemate commented Mar 14, 2024

What was wrong?

As of version 7.0.0-beta.2 the import web3 command takes 375 ms to run*, which is quite long for a library import operation. This affects the usability of command-line tools built around web3.py, where import times are critical.

How was it fixed?

By deferring the import of ens._normalization until the first call of the ens.utils.normalize_name function, the execution time of import web3 is reduced to 275 ms* i.e. by 27%.

Todo:


Details

Profiling* showed that the ens._normalization module performs two lengthy operations at import time:

  • Loading ens/spec/normalization_spec.json that is 3 Mbytes in size takes 7% of the total web3 import time
  • Executing the _extract_valid_codepoints() function that performs transformations on the loaded data takes 16% of the total web3 import time

These are very costly operations to perform at every single import, with the sole purpose of initializing the ens.utils.normalize_name function.

*: Measurements were taken with timeit and pyinstrument on an AMD Ryzen 7 machine with M.2 SSD using Python 3.10.12:

>>> timeit.timeit("import web3")

and

$ pyinstrument --show-regex '.*(eth|web3|ens).*' -c 'import web3'

As of version 7.0.0-beta.2 the `import web3` command takes 375 ms to
run*, which is quite long for a library import operation. This affects
the usability of command-line tools built around web3.py, where import
times are critical.

Profiling* showed that the largest contributor to this is the
`ens._normalization` module that performs two lengthy operations at
import time:

- Loading `ens/spec/normalization_spec.json` that is 3 Mbytes in size
  takes 7% of the total import time
- Executing the `_extract_valid_codepoints()` function that performs
  transformations on the loaded data takes 16% of the total import time

These are very costly operations to perform at every single import, with
the sole purpose of initializing the `ens.utils.normalize_name`
function.

By deferring import until the first call of the function, the execution
time of `import web3` is reduced to 275 ms* i.e. by 27%.

*: Measurements were taken with `timeit` and `pyinstrument` on an AMD
   Ryzen 7 machine with M.2 SSD using Python 3.10.12:

   >>> timeit.timeit("import web3")

   and

   $ pyinstrument --show-regex '.*(eth|web3|ens).*' -c 'import web3'
Copy link
Collaborator

@kclowes kclowes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tracking this down! I'll add a newsfragment and merge.

@kclowes
Copy link
Collaborator

kclowes commented Mar 15, 2024

Just kidding, looks like I/maintainers can't add to your PR. Once you add a newsfragment I can merge. Thanks!

@szemate
Copy link
Contributor Author

szemate commented Mar 20, 2024

Newsfragment added, thank you!

@kclowes
Copy link
Collaborator

kclowes commented Mar 20, 2024

Thank you!

@kclowes kclowes merged commit e24363e into ethereum:main Mar 20, 2024
81 checks passed
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

Successfully merging this pull request may close these issues.

None yet

2 participants