diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index e6851f1..f1c4d52 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -126,6 +126,16 @@ The project follows a py-libp2p-style development workflow: Use ``make pr`` to run the complete workflow. +Benchmarks +---------- + +Performance benchmarks live in ``tests/test_benchmarks.py`` and are marked with +``@pytest.mark.benchmark``. They are excluded from ``make test`` / default CI. +Run them locally with:: + + make bench + # or: pytest tests -m benchmark --benchmark-only + Release Notes ------------- diff --git a/Makefile b/Makefile index a3d6dab..ce27888 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,7 @@ help: @echo "lint - run pre-commit hooks on all files" @echo "typecheck - run mypy and pyrefly type checking" @echo "test - run tests quickly with the default Python" + @echo "bench - run pytest-benchmark suite only" @echo "coverage - run tests with coverage report" @echo "docs-ci - generate docs for CI" @echo "docs - generate docs and open in browser" @@ -66,7 +67,10 @@ typecheck: pre-commit run mypy-local --all-files && pre-commit run pyrefly-local --all-files test: - python -m pytest tests + python -m pytest tests -m "not benchmark" + +bench: + python -m pytest tests -m benchmark --benchmark-only coverage: coverage run --source multiaddr -m pytest tests diff --git a/newsfragments/120.internal.rst b/newsfragments/120.internal.rst new file mode 100644 index 0000000..7ed8959 --- /dev/null +++ b/newsfragments/120.internal.rst @@ -0,0 +1 @@ +Add an opt-in pytest-benchmark suite for core multiaddr hot paths (``make bench``). diff --git a/pyproject.toml b/pyproject.toml index aee301f..ae328b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,6 +60,7 @@ dev = [ "pyrefly", "pyright", "pytest", + "pytest-benchmark", "pytest-cov", "pytest-runner", "pytest-trio>=0.5.2", @@ -84,6 +85,9 @@ include = ["multiaddr*"] [tool.pytest.ini_options] testpaths = ["tests"] +markers = [ + "benchmark: performance benchmarks (excluded from default test runs)", +] [tool.towncrier] # Read https://github.com/multiformats/py-multiaddr/blob/master/newsfragments/README.md for instructions diff --git a/tests/test_benchmarks.py b/tests/test_benchmarks.py new file mode 100644 index 0000000..d1ec215 --- /dev/null +++ b/tests/test_benchmarks.py @@ -0,0 +1,41 @@ +import pytest + +from multiaddr import Multiaddr + +BENCH_ADDR = "/ip4/127.0.0.1/tcp/4001/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC" + + +@pytest.mark.benchmark +def test_bench_from_string(benchmark): + benchmark(Multiaddr, BENCH_ADDR) + + +@pytest.mark.benchmark +def test_bench_to_string(benchmark): + ma = Multiaddr(BENCH_ADDR) + benchmark(str, ma) + + +@pytest.mark.benchmark +def test_bench_to_bytes(benchmark): + ma = Multiaddr(BENCH_ADDR) + benchmark(ma.to_bytes) + + +@pytest.mark.benchmark +def test_bench_protocols(benchmark): + ma = Multiaddr(BENCH_ADDR) + benchmark(lambda: list(ma.protocols())) + + +@pytest.mark.benchmark +def test_bench_encapsulate(benchmark): + ma1 = Multiaddr("/ip4/1.2.3.4") + ma2 = Multiaddr("/tcp/80") + benchmark(ma1.encapsulate, ma2) + + +@pytest.mark.benchmark +def test_bench_decapsulate(benchmark): + ma = Multiaddr("/ip4/1.2.3.4/tcp/80") + benchmark(ma.decapsulate, "/tcp/80")