From b1ee50d992f464fe5b7c5d2a57d5df700bdef10d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Dec 2024 15:06:01 -0600 Subject: [PATCH] Add a benchmark for web.FileResponse (#10095) We didn't have any benchmarks for file responses. From the benchmarks it turns out most of the time is creating and processing the executor jobs. If we combine the stat into a job that returns the open fileobj it will likely be faster and solve https://github.com/aio-libs/aiohttp/issues/8013 (cherry picked from commit fcce1bf6a5c339a3d63ab1678dcb6658ffc7d570) --- tests/test_benchmarks_web_fileresponse.py | 64 +++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 tests/test_benchmarks_web_fileresponse.py diff --git a/tests/test_benchmarks_web_fileresponse.py b/tests/test_benchmarks_web_fileresponse.py new file mode 100644 index 00000000000..7cdbda2efbb --- /dev/null +++ b/tests/test_benchmarks_web_fileresponse.py @@ -0,0 +1,64 @@ +"""codspeed benchmarks for the web file responses.""" + +import asyncio +import pathlib + +from pytest_codspeed import BenchmarkFixture + +from aiohttp import web +from aiohttp.pytest_plugin import AiohttpClient + + +def test_simple_web_file_response( + loop: asyncio.AbstractEventLoop, + aiohttp_client: AiohttpClient, + benchmark: BenchmarkFixture, +) -> None: + """Benchmark creating 100 simple web.FileResponse.""" + response_count = 100 + filepath = pathlib.Path(__file__).parent / "sample.txt" + + async def handler(request: web.Request) -> web.FileResponse: + return web.FileResponse(path=filepath) + + app = web.Application() + app.router.add_route("GET", "/", handler) + + async def run_file_resonse_benchmark() -> None: + client = await aiohttp_client(app) + for _ in range(response_count): + await client.get("/") + await client.close() + + @benchmark + def _run() -> None: + loop.run_until_complete(run_file_resonse_benchmark()) + + +def test_simple_web_file_sendfile_fallback_response( + loop: asyncio.AbstractEventLoop, + aiohttp_client: AiohttpClient, + benchmark: BenchmarkFixture, +) -> None: + """Benchmark creating 100 simple web.FileResponse without sendfile.""" + response_count = 100 + filepath = pathlib.Path(__file__).parent / "sample.txt" + + async def handler(request: web.Request) -> web.FileResponse: + transport = request.transport + assert transport is not None + transport._sendfile_compatible = False # type: ignore[attr-defined] + return web.FileResponse(path=filepath) + + app = web.Application() + app.router.add_route("GET", "/", handler) + + async def run_file_resonse_benchmark() -> None: + client = await aiohttp_client(app) + for _ in range(response_count): + await client.get("/") + await client.close() + + @benchmark + def _run() -> None: + loop.run_until_complete(run_file_resonse_benchmark())