From 07cec648adff4a484d1814068ae36068a5765b8c Mon Sep 17 00:00:00 2001 From: Sam Bull Date: Mon, 15 Dec 2025 22:20:57 +0000 Subject: [PATCH 1/4] Add benchmark for blocking time reading chunks --- tests/test_benchmarks_web_functional.py | 37 +++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 tests/test_benchmarks_web_functional.py diff --git a/tests/test_benchmarks_web_functional.py b/tests/test_benchmarks_web_functional.py new file mode 100644 index 00000000000..863347bad67 --- /dev/null +++ b/tests/test_benchmarks_web_functional.py @@ -0,0 +1,37 @@ +from unittest import mock + +from pytest_codspeed import BenchmarkFixture + +from aiohttp import web +from aiohttp.pytest_plugin import AiohttpClient + + +async def test_read_many_chunks( + aiohttp_client: AiohttpClient, benchmark: BenchmarkFixture +) -> None: + """Benchmark blocking time when receiving many small chunks.""" + + async def sender(): + for _ in range(200000): + yield b"x" + + async def handle(request: web.Request) -> web.Response: + # Wait until buffer is full and reading gets paused. + while not request.protocol._reading_paused: + await asyncio.sleep(0.01) + + # We want to measure the initial blocking time in this call. + # Mocking out the ._wait() call forces the method to return at the first wait, + # without waiting for more data or processing the rest of the body. + with mock.patch.object(request.content, "_wait", autospec=True): + chunk = await benchmark(request.read()) + + return web.Response(text=str(len(chunk))) + + app = web.Application() + app.router.add_post("/", handle) + client = await aiohttp_client(app) + + async with client.post("/", chunked=True, data=sender()) as resp: + assert resp.status == 200 + assert int(await resp.text()) > 100 From 29f0d5a9768df3d555a7a92249f7af1082f60d80 Mon Sep 17 00:00:00 2001 From: Sam Bull Date: Fri, 2 Jan 2026 17:52:35 +0000 Subject: [PATCH 2/4] Update tests/test_benchmarks_web_functional.py --- tests/test_benchmarks_web_functional.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_benchmarks_web_functional.py b/tests/test_benchmarks_web_functional.py index 863347bad67..8287d17b4f6 100644 --- a/tests/test_benchmarks_web_functional.py +++ b/tests/test_benchmarks_web_functional.py @@ -24,7 +24,7 @@ async def handle(request: web.Request) -> web.Response: # Mocking out the ._wait() call forces the method to return at the first wait, # without waiting for more data or processing the rest of the body. with mock.patch.object(request.content, "_wait", autospec=True): - chunk = await benchmark(request.read()) + chunk = await benchmark(request.read) return web.Response(text=str(len(chunk))) From 162f384a38a7d61d8f9985e048d2b21e1026c80b Mon Sep 17 00:00:00 2001 From: Sam Bull Date: Fri, 2 Jan 2026 17:55:23 +0000 Subject: [PATCH 3/4] Update test_benchmarks_web_functional.py --- tests/test_benchmarks_web_functional.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_benchmarks_web_functional.py b/tests/test_benchmarks_web_functional.py index 8287d17b4f6..d799d2f3805 100644 --- a/tests/test_benchmarks_web_functional.py +++ b/tests/test_benchmarks_web_functional.py @@ -1,3 +1,4 @@ +import asyncio from unittest import mock from pytest_codspeed import BenchmarkFixture From 985dc9d8707a1943c5a30d7c56761827ae716098 Mon Sep 17 00:00:00 2001 From: Sam Bull Date: Fri, 2 Jan 2026 18:35:46 +0000 Subject: [PATCH 4/4] Update test_benchmarks_web_functional.py --- tests/test_benchmarks_web_functional.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_benchmarks_web_functional.py b/tests/test_benchmarks_web_functional.py index d799d2f3805..0303d840e23 100644 --- a/tests/test_benchmarks_web_functional.py +++ b/tests/test_benchmarks_web_functional.py @@ -1,4 +1,5 @@ import asyncio +from collections.abc import Iterator from unittest import mock from pytest_codspeed import BenchmarkFixture @@ -12,7 +13,7 @@ async def test_read_many_chunks( ) -> None: """Benchmark blocking time when receiving many small chunks.""" - async def sender(): + async def sender() -> Iterator[bytes]: for _ in range(200000): yield b"x"