Skip to content

Commit

Permalink
Merge pull request #259 from JiriPavela/lazy-loading
Browse files Browse the repository at this point in the history
Add support for lazy loading and imports of some expensive subpackages and modules to speed up Perun startup time
  • Loading branch information
JiriPavela authored Oct 6, 2024
2 parents 276895c + c123e13 commit 3a24630
Show file tree
Hide file tree
Showing 98 changed files with 847 additions and 680 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ repos:
rev: 24.8.0
hooks:
- id: black
types: [file, python]
types_or: [python, pyi]
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
recursive-include perun *.pyi
include perun/py.typed
2 changes: 1 addition & 1 deletion docs/_static/templates/degradation_api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""..."""

from perun.utils.structs import DegradationInfo
from perun.utils.structs.common_structs import DegradationInfo


def my_degradation_checker(baseline_profile, target_profile):
Expand Down
2 changes: 1 addition & 1 deletion docs/cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Perun Commands
Collect Commands
----------------

.. click:: perun.cli:collect
.. click:: perun.cli_groups.collect_cli:collect
:prog: perun collect

.. _cli-collect-units-ref:
Expand Down
4 changes: 2 additions & 2 deletions docs/degradation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,10 @@ just small requirements and have to `yield` the reports about degradation as a i
``DegradationInfo`` objects specified as follows:

.. currentmodule: perun.utils.structs
.. autoclass:: perun.utils.structs.DegradationInfo
.. autoclass:: perun.utils.structs.common_structs.DegradationInfo
:members:

.. autoclass:: perun.utils.structs.PerformanceChange
.. autoclass:: perun.utils.structs.common_structs.PerformanceChange
:members:

You can register your new performance change checker as follows:
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ perun_files = files(
'LICENSE',
'pyproject.toml',
'tox.ini',
'MANIFEST.in',
)

perun_dir = 'perun'
Expand Down
4 changes: 4 additions & 0 deletions perun/check/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
Contains the actual methods in isolate modules, and then a factory module,
containing helper and generic stuff."""

import lazy_loader as lazy

__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
21 changes: 21 additions & 0 deletions perun/check/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from .detection_kit import (
create_filter_by_model as create_filter_by_model,
create_model_record as create_model_record,
get_filtered_best_models_of as get_filtered_best_models_of,
get_function_values as get_function_values,
general_detection as general_detection,
)
from .factory import (
pre_collect_profiles as pre_collect_profiles,
degradation_in_minor as degradation_in_minor,
degradation_in_history as degradation_in_history,
degradation_between_profiles as degradation_between_profiles,
run_degradation_check as run_degradation_check,
degradation_between_files as degradation_between_files,
is_rule_applicable_for as is_rule_applicable_for,
run_detection_with_strategy as run_detection_with_strategy,
)
from .nonparam_kit import (
classify_change as classify_change,
preprocess_nonparam_models as preprocess_nonparam_models,
)
2 changes: 1 addition & 1 deletion perun/check/detection_kit.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from perun.postprocess.regression_analysis import regression_models
from perun.profile import query
from perun.utils.common import common_kit
from perun.utils.structs import (
from perun.utils.structs.common_structs import (
PerformanceChange,
DegradationInfo,
ModelRecord,
Expand Down
30 changes: 1 addition & 29 deletions perun/check/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
polynomial_regression,
)
from perun.utils import decorators, log
from perun.utils.structs import (
from perun.utils.structs.common_structs import (
DetectionChangeResult,
DegradationInfo,
PerformanceChange,
Expand Down Expand Up @@ -61,34 +61,6 @@ def __call__(
"""Call Function"""


def get_supported_detection_models_strategies() -> list[str]:
"""
Provides supported detection models strategies to execute
the degradation check between two profiles with different kinds
of models. The individual strategies represent the way of
executing the detection between profiles and their models:
- best-param: best parametric models from both profiles
- best-non-param: best non-parametric models from both profiles
- best-model: best models from both profiles
- all-param: all parametric models pair from both profiles
- all-non-param: all non-parametric models pair from both profiles
- all-models: all models pair from both profiles
- best-both: best parametric and non-parametric models from both profiles
:return: the names of all supported degradation models strategies
"""
return [
"best-model",
"best-param",
"best-nonparam",
"all-param",
"all-nonparam",
"all-models",
"best-both",
]


def profiles_to_queue(
minor_version: str,
) -> dict[tuple[str, str, str, str], ProfileInfo]:
Expand Down
1 change: 1 addition & 0 deletions perun/check/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ perun_check_dir = perun_dir / 'check'

perun_check_files = files(
'__init__.py',
'__init__.pyi',
'factory.py',
'detection_kit.py',
'nonparam_kit.py',
Expand Down
2 changes: 1 addition & 1 deletion perun/check/methods/abstract_base_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# Perun Imports
if TYPE_CHECKING:
from perun.profile.factory import Profile
from perun.utils.structs import DegradationInfo
from perun.utils.structs.common_structs import DegradationInfo


class AbstractBaseChecker(ABC):
Expand Down
2 changes: 1 addition & 1 deletion perun/check/methods/average_amount_threshold.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
from perun.check.methods.abstract_base_checker import AbstractBaseChecker
from perun.profile import convert
from perun.utils.common import common_kit
from perun.utils.structs import DegradationInfo, PerformanceChange
from perun.utils.structs.common_structs import DegradationInfo, PerformanceChange

if TYPE_CHECKING:
from perun.profile.factory import Profile
Expand Down
10 changes: 4 additions & 6 deletions perun/check/methods/best_model_order_equality.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@
# Third-Party Imports

# Perun Imports
from perun import check as check
from perun.check.methods.abstract_base_checker import AbstractBaseChecker
from perun.utils.structs import DegradationInfo, PerformanceChange
import perun.check.detection_kit as detection
from perun.utils.structs.common_structs import DegradationInfo, PerformanceChange

if TYPE_CHECKING:
from perun.profile.factory import Profile
Expand Down Expand Up @@ -81,10 +81,8 @@ def check(
:param _: unification with other detection methods (unused in this method)
:returns: tuple (degradation result, degradation location, degradation rate)
"""
best_baseline_models = detection.get_filtered_best_models_of(
baseline_profile, group="param"
)
best_target_models = detection.get_filtered_best_models_of(target_profile, group="param")
best_baseline_models = check.get_filtered_best_models_of(baseline_profile, group="param")
best_target_models = check.get_filtered_best_models_of(target_profile, group="param")

for uid, best_model in best_target_models.items():
best_baseline_model = best_baseline_models.get(uid)
Expand Down
2 changes: 1 addition & 1 deletion perun/check/methods/exclusive_time_outliers.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
from perun.check.methods.abstract_base_checker import AbstractBaseChecker
from perun.logic import config
from perun.profile import convert
from perun.utils.structs import DegradationInfo, PerformanceChange
from perun.utils.structs.common_structs import DegradationInfo, PerformanceChange

if TYPE_CHECKING:
from perun.profile.factory import Profile
Expand Down
6 changes: 3 additions & 3 deletions perun/check/methods/fast_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
import numpy as np

# Perun Imports
from perun import check as check
from perun.check.methods.abstract_base_checker import AbstractBaseChecker
from perun.logic import runner
from perun.utils.structs import DegradationInfo, ClassificationMethod
import perun.check.detection_kit as detect
from perun.utils.structs.common_structs import DegradationInfo, ClassificationMethod

if TYPE_CHECKING:
from perun.profile.factory import Profile
Expand All @@ -35,7 +35,7 @@ def check(
:param _: unification with other detection methods (unused in this method)
:returns: tuple (degradation result, degradation location, degradation rate, confidence)
"""
return detect.general_detection(
return check.general_detection(
baseline_profile, target_profile, ClassificationMethod.FastCheck
)

Expand Down
10 changes: 5 additions & 5 deletions perun/check/methods/integral_comparison.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@

# Perun Imports
from perun.check.methods.abstract_base_checker import AbstractBaseChecker
from perun.check import factory, nonparam_kit as nparam_helpers
from perun import check as check
from perun.postprocess.regression_analysis import regression_models
from perun.utils.common import common_kit
from perun.utils.structs import DegradationInfo, ModelRecord, DetectionChangeResult
from perun.utils.structs.common_structs import DegradationInfo, ModelRecord, DetectionChangeResult

if TYPE_CHECKING:
from perun.profile.factory import Profile
Expand Down Expand Up @@ -95,7 +95,7 @@ def execute_analysis(
:return: tuple with degradation info between a pair of models:
(deg. result, deg. location, deg. rate, confidence type and rate, etc.)
"""
x_pts, baseline_y_pts, target_y_pts = nparam_helpers.preprocess_nonparam_models(
x_pts, baseline_y_pts, target_y_pts = check.preprocess_nonparam_models(
uid, baseline_model, target_profile, target_model
)

Expand All @@ -114,7 +114,7 @@ def execute_analysis(
float(target_integral - baseline_integral), float(baseline_integral)
)

change_info = nparam_helpers.classify_change(
change_info = check.classify_change(
rel_error if np.isfinite(rel_error) else 0,
_INTEGRATE_DIFF_NO_CHANGE,
_INTEGRATE_DIFF_CHANGE,
Expand Down Expand Up @@ -142,7 +142,7 @@ def check(
:param _: other kwgargs
:returns: tuple - degradation result (structure DegradationInfo)
"""
for degradation_info in factory.run_detection_with_strategy(
for degradation_info in check.run_detection_with_strategy(
execute_analysis, baseline_profile, target_profile, models_strategy
):
yield degradation_info
16 changes: 8 additions & 8 deletions perun/check/methods/linear_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
from scipy import stats

# Perun Imports
from perun.check import detection_kit as detect
from perun import check as check
from perun.check.methods import fast_check
from perun.check.methods.abstract_base_checker import AbstractBaseChecker
from perun.utils.common import common_kit
from perun.utils.structs import DegradationInfo, ModelRecord, ClassificationMethod
from perun.utils.structs.common_structs import DegradationInfo, ModelRecord, ClassificationMethod

if TYPE_CHECKING:
import numpy
Expand All @@ -40,7 +40,7 @@ def check(
:returns: tuple (degradation result, degradation location, degradation rate, confidence)
"""

return detect.general_detection(
return check.general_detection(
baseline_profile, target_profile, ClassificationMethod.LinearRegression
)

Expand Down Expand Up @@ -107,15 +107,15 @@ def exec_linear_regression(
uid, baseline_profile, baseline_x_pts, lin_abs_error
)
# obtaining the models (linear and quadratic) from the new regressed profile
quad_err_model = detect.get_filtered_best_models_of(
quad_err_model = check.get_filtered_best_models_of(
std_err_profile,
group="param",
model_filter=detect.create_filter_by_model("quadratic"),
model_filter=check.create_filter_by_model("quadratic"),
)
linear_err_model = detect.get_filtered_best_models_of(
linear_err_model = check.get_filtered_best_models_of(
std_err_profile,
group="param",
model_filter=detect.create_filter_by_model("linear"),
model_filter=check.create_filter_by_model("linear"),
)

# check the last quadratic type of change
Expand All @@ -127,7 +127,7 @@ def exec_linear_regression(

# We did not classify the change
if not change_type:
std_err_model = detect.get_filtered_best_models_of(std_err_profile, group="param")
std_err_model = check.get_filtered_best_models_of(std_err_profile, group="param")
change_type = std_err_model[uid].type

return change_type
13 changes: 6 additions & 7 deletions perun/check/methods/local_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,11 @@
from scipy import integrate

# Perun Imports
from perun.check import factory
from perun import check as check
from perun.check.methods.abstract_base_checker import AbstractBaseChecker
from perun.profile.factory import Profile
from perun.utils.common import common_kit
from perun.utils.structs import DegradationInfo, ModelRecord, DetectionChangeResult
import perun.check.nonparam_kit as nparam_helpers
from perun.utils.structs.common_structs import DegradationInfo, ModelRecord, DetectionChangeResult

if TYPE_CHECKING:
import numpy.typing as npt
Expand Down Expand Up @@ -141,7 +140,7 @@ def classify_stats_diff(
"""
# create vectorized functions which take a np.arrays as inputs and perform actions over it
compare_diffs = np.vectorize(compare_diff_values)
classify_change = np.vectorize(nparam_helpers.classify_change)
classify_change = np.vectorize(check.classify_change)
stat_no = len(baseline_stats.keys())
stat_size = baseline_stats.get(list(baseline_stats.keys())[0])

Expand Down Expand Up @@ -227,7 +226,7 @@ def execute_analysis(
original_x_pts,
baseline_y_pts,
target_y_pts,
) = nparam_helpers.preprocess_nonparam_models(uid, baseline_model, target_profile, target_model)
) = check.preprocess_nonparam_models(uid, baseline_model, target_profile, target_model)

baseline_window_stats, _ = compute_window_stats(original_x_pts, baseline_y_pts)
target_window_stats, x_pts = compute_window_stats(original_x_pts, target_y_pts)
Expand All @@ -238,7 +237,7 @@ def execute_analysis(
x_pts_odd = x_pts[:, 1::2].reshape(-1, x_pts.size // 2)[0].round(2)
partial_intervals = list(np.array((change_info, partial_rel_error, x_pts_even, x_pts_odd)).T)

change_info_enum = nparam_helpers.classify_change(
change_info_enum = check.classify_change(
common_kit.safe_division(float(np.sum(partial_rel_error)), partial_rel_error.size),
_STATS_DIFF_NO_CHANGE,
_STATS_DIFF_CHANGE,
Expand Down Expand Up @@ -268,7 +267,7 @@ def check(
:param models_strategy: detection model strategy for obtains the relevant kind of models
:returns: tuple - degradation result
"""
for degradation_info in factory.run_detection_with_strategy(
for degradation_info in check.run_detection_with_strategy(
execute_analysis, baseline_profile, target_profile, models_strategy
):
yield degradation_info
6 changes: 3 additions & 3 deletions perun/check/methods/polynomial_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
import numpy as np

# Perun Imports
from perun import check as check
from perun.check.methods.abstract_base_checker import AbstractBaseChecker
from perun.utils.structs import DegradationInfo, ClassificationMethod
import perun.check.detection_kit as detect
from perun.utils.structs.common_structs import DegradationInfo, ClassificationMethod

if TYPE_CHECKING:
import numpy.typing as npt
Expand All @@ -37,7 +37,7 @@ def check(
:param _: unification with other detection methods (unused in this method)
:returns: tuple (degradation result, degradation location, degradation rate, confidence)
"""
return detect.general_detection(
return check.general_detection(
baseline_profile,
target_profile,
ClassificationMethod.PolynomialRegression,
Expand Down
Loading

0 comments on commit 3a24630

Please sign in to comment.