Skip to content

Commit 89785fa

Browse files
bdracopatchback[bot]
authored andcommitted
Add benchmarks for the URL dispatcher (#9910)
(cherry picked from commit 4a9bbf9)
1 parent d4acbd6 commit 89785fa

File tree

1 file changed

+187
-0
lines changed

1 file changed

+187
-0
lines changed
+187
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
"""codspeed benchmarks for the URL dispatcher."""
2+
3+
import asyncio
4+
import pathlib
5+
from typing import NoReturn
6+
from unittest import mock
7+
8+
from multidict import CIMultiDict, CIMultiDictProxy
9+
from pytest_codspeed import BenchmarkFixture
10+
from yarl import URL
11+
12+
import aiohttp
13+
from aiohttp import web
14+
from aiohttp.http import HttpVersion, RawRequestMessage
15+
16+
17+
def _mock_request(method: str, path: str) -> web.Request:
18+
message = RawRequestMessage(
19+
method,
20+
path,
21+
HttpVersion(1, 1),
22+
CIMultiDictProxy(CIMultiDict()),
23+
(),
24+
False,
25+
None,
26+
False,
27+
False,
28+
URL(path),
29+
)
30+
31+
return web.Request(
32+
message, mock.Mock(), mock.Mock(), mock.Mock(), mock.Mock(), mock.Mock()
33+
)
34+
35+
36+
def test_resolve_root_route(
37+
loop: asyncio.AbstractEventLoop,
38+
benchmark: BenchmarkFixture,
39+
) -> None:
40+
"""Resolve top level PlainResources route 100 times."""
41+
resolve_count = 100
42+
43+
async def handler(request: web.Request) -> NoReturn:
44+
assert False
45+
46+
app = web.Application()
47+
app.router.add_route("GET", "/", handler)
48+
request = _mock_request(method="GET", path="/")
49+
50+
async def run_url_dispatcher_benchmark() -> None:
51+
for _ in range(resolve_count):
52+
await app._router.resolve(request)
53+
54+
@benchmark
55+
def _run() -> None:
56+
loop.run_until_complete(run_url_dispatcher_benchmark())
57+
58+
59+
def test_resolve_static_root_route(
60+
loop: asyncio.AbstractEventLoop,
61+
benchmark: BenchmarkFixture,
62+
) -> None:
63+
"""Resolve top level StaticResource route 100 times."""
64+
resolve_count = 100
65+
66+
app = web.Application()
67+
app.router.add_static("/", pathlib.Path(aiohttp.__file__).parent)
68+
request = _mock_request(method="GET", path="/")
69+
70+
async def run_url_dispatcher_benchmark() -> None:
71+
for _ in range(resolve_count):
72+
await app._router.resolve(request)
73+
74+
@benchmark
75+
def _run() -> None:
76+
loop.run_until_complete(run_url_dispatcher_benchmark())
77+
78+
79+
def test_resolve_single_fixed_url_with_many_routes(
80+
loop: asyncio.AbstractEventLoop,
81+
benchmark: BenchmarkFixture,
82+
) -> None:
83+
"""Resolve PlainResources route 100 times."""
84+
resolve_count = 100
85+
86+
async def handler(request: web.Request) -> NoReturn:
87+
assert False
88+
89+
app = web.Application()
90+
for count in range(250):
91+
app.router.add_route("GET", f"/api/server/dispatch/{count}/update", handler)
92+
request = _mock_request(method="GET", path="/api/server/dispatch/1/update")
93+
94+
async def run_url_dispatcher_benchmark() -> None:
95+
for _ in range(resolve_count):
96+
await app._router.resolve(request)
97+
98+
@benchmark
99+
def _run() -> None:
100+
loop.run_until_complete(run_url_dispatcher_benchmark())
101+
102+
103+
def test_resolve_multiple_fixed_url_with_many_routes(
104+
loop: asyncio.AbstractEventLoop,
105+
benchmark: BenchmarkFixture,
106+
) -> None:
107+
"""Resolve 250 different PlainResources routes."""
108+
109+
async def handler(request: web.Request) -> NoReturn:
110+
assert False
111+
112+
app = web.Application()
113+
for count in range(250):
114+
app.router.add_route("GET", f"/api/server/dispatch/{count}/update", handler)
115+
116+
requests = [
117+
_mock_request(method="GET", path=f"/api/server/dispatch/{count}/update")
118+
for count in range(250)
119+
]
120+
121+
async def run_url_dispatcher_benchmark() -> None:
122+
for request in requests:
123+
await app._router.resolve(request)
124+
125+
@benchmark
126+
def _run() -> None:
127+
loop.run_until_complete(run_url_dispatcher_benchmark())
128+
129+
130+
def test_resolve_multiple_level_fixed_url_with_many_routes(
131+
loop: asyncio.AbstractEventLoop,
132+
benchmark: BenchmarkFixture,
133+
) -> None:
134+
"""Resolve 1024 different PlainResources routes."""
135+
136+
async def handler(request: web.Request) -> NoReturn:
137+
assert False
138+
139+
app = web.Application()
140+
urls = [
141+
f"/api/{a}/{b}/{c}/{d}/{e}/update"
142+
for a in ("a", "b", "c", "d")
143+
for b in ("e", "f", "g", "h")
144+
for c in ("i", "j", "k", "l")
145+
for d in ("m", "n", "o", "p")
146+
for e in ("n", "o", "p", "q")
147+
]
148+
for url in urls:
149+
app.router.add_route("GET", url, handler)
150+
151+
requests = [_mock_request(method="GET", path=url) for url in urls]
152+
153+
async def run_url_dispatcher_benchmark() -> None:
154+
for request in requests:
155+
await app._router.resolve(request)
156+
157+
@benchmark
158+
def _run() -> None:
159+
loop.run_until_complete(run_url_dispatcher_benchmark())
160+
161+
162+
def test_resolve_dynamic_resource_url_with_many_routes(
163+
loop: asyncio.AbstractEventLoop,
164+
benchmark: BenchmarkFixture,
165+
) -> None:
166+
"""Resolve different a DynamicResource when there are 250 PlainResources registered."""
167+
168+
async def handler(request: web.Request) -> NoReturn:
169+
assert False
170+
171+
app = web.Application()
172+
for count in range(250):
173+
app.router.add_route("GET", f"/api/server/other/{count}/update", handler)
174+
app.router.add_route("GET", "/api/server/dispatch/{customer}/update", handler)
175+
176+
requests = [
177+
_mock_request(method="GET", path=f"/api/server/dispatch/{customer}/update")
178+
for customer in range(250)
179+
]
180+
181+
async def run_url_dispatcher_benchmark() -> None:
182+
for request in requests:
183+
await app._router.resolve(request)
184+
185+
@benchmark
186+
def _run() -> None:
187+
loop.run_until_complete(run_url_dispatcher_benchmark())

0 commit comments

Comments
 (0)