Skip to content

Commit bf2ff1f

Browse files
committed
* 'develop' of https://github.com/awslabs/aws-lambda-powertools-python: chore(test-perf): use pytest-benchmark to improve reliability (#1250)
2 parents b9447a9 + 5fbff55 commit bf2ff1f

File tree

4 files changed

+85
-106
lines changed

4 files changed

+85
-106
lines changed

Diff for: poetry.lock

+33-37
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ mypy-boto3-secretsmanager = "^1.24.0"
5959
mypy-boto3-ssm = "^1.24.0"
6060
mypy-boto3-appconfig = "^1.24.0"
6161
mypy-boto3-dynamodb = "^1.24.0"
62+
pytest-benchmark = "^3.4.1"
6263

6364

6465
[tool.poetry.extras]

Diff for: tests/performance/conftest.py

-18
This file was deleted.

Diff for: tests/performance/test_high_level_imports.py

+51-51
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,95 @@
11
import importlib
2-
import time
3-
from contextlib import contextmanager
42
from types import ModuleType
5-
from typing import Generator, Tuple
3+
from typing import Tuple
64

75
import pytest
86

97
LOGGER_INIT_SLA: float = 0.005
108
METRICS_INIT_SLA: float = 0.005
119
TRACER_INIT_SLA: float = 0.5
1210
IMPORT_INIT_SLA: float = 0.035
11+
PARENT_PACKAGE = "aws_lambda_powertools"
12+
TRACING_PACKAGE = "aws_lambda_powertools.tracing"
13+
LOGGING_PACKAGE = "aws_lambda_powertools.logging"
14+
METRICS_PACKAGE = "aws_lambda_powertools.metrics"
1315

1416

15-
@contextmanager
16-
def timing() -> Generator:
17-
""" "Generator to quickly time operations. It can add 5ms so take that into account in elapsed time
17+
def import_core_utilities() -> Tuple[ModuleType, ModuleType, ModuleType]:
18+
"""Dynamically imports and return Tracing, Logging, and Metrics modules"""
19+
return (
20+
importlib.import_module(TRACING_PACKAGE),
21+
importlib.import_module(LOGGING_PACKAGE),
22+
importlib.import_module(METRICS_PACKAGE),
23+
)
1824

19-
Examples
20-
--------
2125

22-
with timing() as t:
23-
print("something")
24-
elapsed = t()
25-
"""
26-
start = time.perf_counter()
27-
yield lambda: time.perf_counter() - start # gen as lambda to calculate elapsed time
26+
@pytest.fixture(autouse=True)
27+
def clear_cache():
28+
importlib.invalidate_caches()
2829

2930

30-
def core_utilities() -> Tuple[ModuleType, ModuleType, ModuleType]:
31-
"""Return Tracing, Logging, and Metrics module"""
32-
tracing = importlib.import_module("aws_lambda_powertools.tracing")
33-
logging = importlib.import_module("aws_lambda_powertools.logging")
34-
metrics = importlib.import_module("aws_lambda_powertools.metrics")
31+
def import_init_tracer():
32+
tracing = importlib.import_module(TRACING_PACKAGE)
33+
tracing.Tracer(disabled=True)
3534

36-
return tracing, logging, metrics
35+
36+
def import_init_metrics():
37+
metrics = importlib.import_module(METRICS_PACKAGE)
38+
metrics.Metrics()
39+
40+
41+
def import_init_logger():
42+
logging = importlib.import_module(LOGGING_PACKAGE)
43+
logging.Logger()
3744

3845

3946
@pytest.mark.perf
40-
def test_import_times_ceiling():
47+
@pytest.mark.benchmark(group="core", disable_gc=True, warmup=False)
48+
def test_import_times_ceiling(benchmark):
4149
# GIVEN Core utilities are imported
4250
# WHEN none are used
4351
# THEN import and any global initialization perf should be below 30ms
4452
# though we adjust to 35ms to take into account different CI machines, etc.
4553
# instead of re-running tests which can lead to false positives
46-
with timing() as t:
47-
core_utilities()
48-
49-
elapsed = t()
50-
if elapsed > IMPORT_INIT_SLA:
51-
pytest.fail(f"High level imports should be below ${IMPORT_INIT_SLA}s: {elapsed}")
54+
benchmark.pedantic(import_core_utilities)
55+
stat = benchmark.stats.stats.max
56+
if stat > IMPORT_INIT_SLA:
57+
pytest.fail(f"High level imports should be below {IMPORT_INIT_SLA}s: {stat}")
5258

5359

5460
@pytest.mark.perf
55-
def test_tracer_init():
61+
@pytest.mark.benchmark(group="core", disable_gc=True, warmup=False)
62+
def test_tracer_init(benchmark):
5663
# GIVEN Tracer is initialized
5764
# WHEN default options are used
5865
# THEN initialization X-Ray SDK perf should be below 450ms
5966
# though we adjust to 500ms to take into account different CI machines, etc.
6067
# instead of re-running tests which can lead to false positives
61-
with timing() as t:
62-
tracing, _, _ = core_utilities()
63-
tracing.Tracer(disabled=True) # boto3 takes ~200ms, and remaining is X-Ray SDK init
64-
65-
elapsed = t()
66-
if elapsed > TRACER_INIT_SLA:
67-
pytest.fail(f"High level imports should be below ${TRACER_INIT_SLA}s: {elapsed}")
68+
benchmark.pedantic(import_init_tracer)
69+
stat = benchmark.stats.stats.max
70+
if stat > TRACER_INIT_SLA:
71+
pytest.fail(f"High level imports should be below {TRACER_INIT_SLA}s: {stat}")
6872

6973

7074
@pytest.mark.perf
71-
def test_metrics_init():
75+
@pytest.mark.benchmark(group="core", disable_gc=True, warmup=False)
76+
def test_metrics_init(benchmark):
7277
# GIVEN Metrics is initialized
7378
# WHEN default options are used
7479
# THEN initialization perf should be below 5ms
75-
with timing() as t:
76-
_, _, metrics = core_utilities()
77-
metrics.Metrics()
78-
79-
elapsed = t()
80-
if elapsed > METRICS_INIT_SLA:
81-
pytest.fail(f"High level imports should be below ${METRICS_INIT_SLA}s: {elapsed}")
80+
benchmark.pedantic(import_init_metrics)
81+
stat = benchmark.stats.stats.max
82+
if stat > METRICS_INIT_SLA:
83+
pytest.fail(f"High level imports should be below ${METRICS_INIT_SLA}s: {stat}")
8284

8385

8486
@pytest.mark.perf
85-
def test_logger_init():
87+
@pytest.mark.benchmark(group="core", disable_gc=True, warmup=False)
88+
def test_logger_init(benchmark):
8689
# GIVEN Logger is initialized
8790
# WHEN default options are used
8891
# THEN initialization perf should be below 5ms
89-
with timing() as t:
90-
_, logging, _ = core_utilities()
91-
logging.Logger()
92-
93-
elapsed = t()
94-
if elapsed > LOGGER_INIT_SLA:
95-
pytest.fail(f"High level imports should be below ${LOGGER_INIT_SLA}s: {elapsed}")
92+
benchmark.pedantic(import_init_logger)
93+
stat = benchmark.stats.stats.max
94+
if stat > LOGGER_INIT_SLA:
95+
pytest.fail(f"High level imports should be below ${LOGGER_INIT_SLA}s: {stat}")

0 commit comments

Comments
 (0)