Skip to content

Commit 29cc405

Browse files
authored
test: add benchmarks for cache mark-to-expire path (#1780) (#1785)
1 parent 92529f3 commit 29cc405

1 file changed

Lines changed: 124 additions & 0 deletions

File tree

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
"""Benchmarks for DNSCache.async_mark_unique_records_older_than_1s_to_expire.
2+
3+
Covers the RFC 6762 §10.2 paragraph 2 path. ``_async_set_created_ttl``
4+
mutates cached records in place, so a repeated-iteration benchmark
5+
would only measure work on the first call. Each test uses
6+
``benchmark.pedantic`` with a per-round ``setup`` that rebuilds the
7+
stale cache; the ``async_add_records`` cost stays outside the timed
8+
window.
9+
"""
10+
11+
from __future__ import annotations
12+
13+
from typing import Any
14+
15+
from pytest_codspeed import BenchmarkFixture
16+
17+
from zeroconf import DNSAddress, DNSCache, DNSPointer, current_time_millis
18+
from zeroconf.const import _CLASS_IN, _CLASS_UNIQUE, _TYPE_A, _TYPE_PTR
19+
20+
_UNIQUE_CLASS = _CLASS_IN | _CLASS_UNIQUE
21+
22+
23+
def _ipv4_bytes(i: int) -> bytes:
24+
return bytes(((i >> 24) & 0xFF, (i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF))
25+
26+
27+
def test_mark_to_expire_1000_records_all_stale(benchmark: BenchmarkFixture) -> None:
28+
"""Worst-case mark-to-expire: 1000 stale unique A records, all mutated."""
29+
now = current_time_millis()
30+
name = "stale.local."
31+
unique_types = {(name, _TYPE_A, _UNIQUE_CLASS)}
32+
# Unrelated answer keeps every cached record in the "must expire"
33+
# branch (no membership hit short-circuits the mutation).
34+
answers = [DNSAddress(name, _TYPE_A, _UNIQUE_CLASS, 120, _ipv4_bytes(0xDEAD_BEEF))]
35+
36+
def _setup() -> tuple[tuple[Any, ...], dict[str, Any]]:
37+
cache = DNSCache()
38+
cache.async_add_records(
39+
DNSAddress(
40+
name,
41+
_TYPE_A,
42+
_UNIQUE_CLASS,
43+
120,
44+
_ipv4_bytes(i),
45+
created=now - 5_000,
46+
)
47+
for i in range(1000)
48+
)
49+
return (cache,), {}
50+
51+
def _mark(cache: DNSCache) -> None:
52+
cache.async_mark_unique_records_older_than_1s_to_expire(unique_types, answers, now)
53+
54+
benchmark.pedantic(_mark, setup=_setup)
55+
56+
57+
def test_mark_to_expire_1000_records_none_stale(benchmark: BenchmarkFixture) -> None:
58+
"""Scan-only path: 1000 fresh records, no mutation."""
59+
now = current_time_millis()
60+
name = "fresh.local."
61+
unique_types = {(name, _TYPE_A, _UNIQUE_CLASS)}
62+
answers = [DNSAddress(name, _TYPE_A, _UNIQUE_CLASS, 120, _ipv4_bytes(0xDEAD_BEEF))]
63+
64+
def _setup() -> tuple[tuple[Any, ...], dict[str, Any]]:
65+
cache = DNSCache()
66+
cache.async_add_records(
67+
DNSAddress(
68+
name,
69+
_TYPE_A,
70+
_UNIQUE_CLASS,
71+
120,
72+
_ipv4_bytes(i),
73+
created=now,
74+
)
75+
for i in range(1000)
76+
)
77+
return (cache,), {}
78+
79+
def _mark(cache: DNSCache) -> None:
80+
cache.async_mark_unique_records_older_than_1s_to_expire(unique_types, answers, now)
81+
82+
benchmark.pedantic(_mark, setup=_setup)
83+
84+
85+
def test_mark_to_expire_many_unique_types(benchmark: BenchmarkFixture) -> None:
86+
"""100 distinct (name, type, class) triplets, one stale record each."""
87+
now = current_time_millis()
88+
unique_types: set[tuple[str, int, int]] = {
89+
(f"svc{i}.local.", _TYPE_PTR, _UNIQUE_CLASS) for i in range(100)
90+
}
91+
# New answers reference a different alias, so the cached entries are
92+
# not equal to anything in ``answers_rrset`` and must be expired.
93+
answers = [
94+
DNSPointer(
95+
f"svc{i}.local.",
96+
_TYPE_PTR,
97+
_UNIQUE_CLASS,
98+
120,
99+
f"new-target{i}.local.",
100+
)
101+
for i in range(100)
102+
]
103+
104+
def _setup() -> tuple[tuple[Any, ...], dict[str, Any]]:
105+
cache = DNSCache()
106+
for i in range(100):
107+
cache.async_add_records(
108+
[
109+
DNSPointer(
110+
f"svc{i}.local.",
111+
_TYPE_PTR,
112+
_UNIQUE_CLASS,
113+
120,
114+
f"target{i}.local.",
115+
created=now - 5_000,
116+
)
117+
]
118+
)
119+
return (cache,), {}
120+
121+
def _mark(cache: DNSCache) -> None:
122+
cache.async_mark_unique_records_older_than_1s_to_expire(unique_types, answers, now)
123+
124+
benchmark.pedantic(_mark, setup=_setup)

0 commit comments

Comments
 (0)