Skip to content

Commit

Permalink
Merge 91b3c49 into 67b067d
Browse files Browse the repository at this point in the history
  • Loading branch information
hgrecco committed Feb 21, 2022
2 parents 67b067d + 91b3c49 commit 56f2eb1
Show file tree
Hide file tree
Showing 16 changed files with 1,244 additions and 433 deletions.
5 changes: 5 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ Pint Changelog
0.19 (unreleased)
-----------------

- Better separation between parsing and loading of definitions.
Implement a parsed "binary" version of "textual" definition files.
Infrastructure to disk cache parsed definition files and RegistryCache
resulting in a 10X speed up in registry instantiation when enabled.
(Issue #1465)
- Fix a bug for offset units of higher dimension, e.g. gauge pressure.
(Issue #1066, thanks dalito)
- Fix type hints of function wrapper (Issue #1431)
Expand Down
7 changes: 5 additions & 2 deletions benchmarks/01_registry_creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@


def time_create_registry(args):
pint.UnitRegistry(*args)
if len(args) == 2:
pint.UnitRegistry(args[0], cache_folder=args[1])
else:
pint.UnitRegistry(*args)


time_create_registry.params = [[(None,), tuple(), (util.get_tiny_def(),)]]
time_create_registry.params = [[(None,), tuple(), (util.get_tiny_def(),), ("", None)]]
53 changes: 53 additions & 0 deletions benchmarks/10_registry.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import pathlib

import pint

from . import util
Expand Down Expand Up @@ -99,3 +101,54 @@ def time_convert_from_uc(key):
time_convert_from_uc.params = [
(("uc_meter", "uc_kilometer"), ("uc_kilometer/second", "uc_angstrom/minute"))
]


def time_parse_math_expression():
ureg.parse_expression("3 + 5 * 2 + value", value=10)


# This code is duplicated with other benchmarks but simplify comparison

CACHE_FOLDER = pathlib.Path(".cache")
CACHE_FOLDER.mkdir(exist_ok=True)
pint.UnitRegistry(cache_folder=CACHE_FOLDER)


def time_load_definitions_stage_1(cache_folder):
"""empty registry creation"""
# Change this into a single part benchmark using setup
_ = pint.UnitRegistry(None, cache_folder=None)


time_load_definitions_stage_1.param_names = [
"cache_folder",
]
time_load_definitions_stage_1.params = [
None,
CACHE_FOLDER,
]


def time_load_definitions_stage_2(cache_folder, *args, **kwargs):
"""empty registry creation + parsing default files + definition object loading"""

# Change this into a single part benchmark using setup
empty_registry = pint.UnitRegistry(None, cache_folder=cache_folder)
empty_registry.load_definitions("default_en.txt", True)


time_load_definitions_stage_2.param_names = time_load_definitions_stage_1.param_names
time_load_definitions_stage_2.params = time_load_definitions_stage_1.params


def time_load_definitions_stage_3(cache_folder, *args, **kwargs):
"""empty registry creation + parsing default files + definition object loading + cache building"""

# Change this into a single part benchmark using setup
empty_registry = pint.UnitRegistry(None, cache_folder=cache_folder)
loaded_files = empty_registry.load_definitions("default_en.txt", True)
empty_registry._build_cache(loaded_files)


time_load_definitions_stage_3.param_names = time_load_definitions_stage_1.param_names
time_load_definitions_stage_3.params = time_load_definitions_stage_1.params
49 changes: 49 additions & 0 deletions docs/performance.rst
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,53 @@ A better way to use magnitudes is to use pint's wraps decorator (See :ref:`wrapp
In [9]: %timeit g(a, b)
10000 loops, best of 3: 65.4 µs per loop


Speed up registry instantiation
-------------------------------

When the registry is instantiated, the definition file is parsed, loaded and
some pre-calculations are made to speed-up certain common operations. This
process can be time consuming for a large defintion file such as the default one
(and very comprehensive) provided with pint. This can have a significant impact
in command line applications that create and drop registries.

Since version 0.19, part of this process can be cached resulting in a 5x to 20x
performance improvement for registry instantiation. This feature is experimental
and therefore disabled by default, but might be enable in future versions.

To enable this feature just use the `cache_folder` argument to provide
(as a str or pathlib.Path) the location where the cache will be saved.

.. code-block:: python
>>> import pint
>>> ureg = pint.UnitRegistry(cache_folder="/my/cache/folder") # doctest: +SKIP
If you want to use the default

.. code-block:: python
>>> import pint
>>> ureg = pint.UnitRegistry(cache_folder=":auto:") # doctest: +SKIP
In any case, you can check the location of the cache folder.

.. code-block:: python
>>> ureg.cache_folder # doctest: +SKIP
.. note:: Cached files are stored in pickle format with a unique name
generated from hashing the path of the original definition file. This
hash also includes the platform (e.g. 'Linux'), python implementation
(e.g. ‘CPython'), python version, pint version and the `non_int_type`
setting of the UnitRegistry to avoid mixing incompatible caches.
If the definition file includes another (using the `@import` directive),
this latter file will be cached independently. Finally, when a
definition file is loaded upon registry instantiation the RegistryCache
is also cached. The cache is invalidated based on the file modification
time. Therefore, if you modify the text definition file the cache file
will be regenerated.


.. _`brentq method`: http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.brentq.html

0 comments on commit 56f2eb1

Please sign in to comment.