Skip to content

Add aiofastnet to speedups extra#12822

Open
tarasko wants to merge 58 commits into
aio-libs:masterfrom
tarasko:feature/speedups_aiofastnet
Open

Add aiofastnet to speedups extra#12822
tarasko wants to merge 58 commits into
aio-libs:masterfrom
tarasko:feature/speedups_aiofastnet

Conversation

@tarasko

@tarasko tarasko commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

I've made a new PR instead of #12744

What do these changes do?

Discussion #12701

This change adds aiofastnet to speedups extras.
aiofastnet provides more efficient implementations for

  • loop.create_connection
  • loop.start_tls
  • loop.create_server
  • loop.sendfile

aiohttp will use them if aiofastnet can be imported.

On top of that, aiofastnet provides optional, transparent Kernel TLS support on Linux and native sendfile for TLS connections using SSL_sendfile. User can enable it via the standard ssl.OP_ENABLE_KTLS option in SSLContext.

Are there changes in behavior for the user?

This is an optimization change, it should not change visible behavior.

Is it a substantial burden for the maintainers to support this?

Every time when users will complain about something that sounds like a networking layer issue, it would be very important to know: is aiofastnet activate or not? So it would be good to add this question to the issue template.

aiofastnet itself is a medium size project, functionally-wise it has a limited scope, and I hope I'll be able to maintain it the next 5 years. It is relatively new, I have written a good amount of tests already and I'm currently adding more. I want to get coverage close to 100%.

One important caveat is that aiofastnet currently does NOT work with uv managed python distribution.
Attempt to import aiofastnet will result in ImportError exception with such Python.

aiofastnet uses OpenSSL directly, not through stdlib ssl module. aiofastnet locates dynamically loaded libssl.so and libcrypto.so and get addresses of OpenSSL exported functions like SSL_read and SSL_write and SSL_sendfile with dlsym. This lets aiofastnet to cut off a huge portion of python ssl plumbing.

uv managed python is linked statically against all of its stdlib modules and OpenSSL, and that makes it impossible to locate OpenSSL symbols.

Currently, all ubuntu and macos tests are run with uv standalone python.
Therefore I added 2 additional test runs with python installed by actions/setup-python on macos and ubuntu
to make sure that all tests pass when aiofastnet is importable.

Related issue number

Checklist

  • I think the code is well written
  • Unit tests for the changes exist
  • Documentation reflects the changes
  • Add yourself to CONTRIBUTORS.txt
  • Add a new news fragment: 12822.feature.rst

@tarasko tarasko marked this pull request as draft June 6, 2026 05:58
Comment thread aiohttp/connector.py Fixed
Comment thread aiohttp/web_fileresponse.py Fixed
Comment thread aiohttp/web_runner.py Fixed
@codecov

codecov Bot commented Jun 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.29730% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.94%. Comparing base (f5e63e8) to head (7a46045).
⚠️ Report is 1 commits behind head on master.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
tests/test_benchmarks_web_fileresponse.py 72.72% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #12822      +/-   ##
==========================================
- Coverage   98.95%   98.94%   -0.02%     
==========================================
  Files         131      131              
  Lines       48029    48084      +55     
  Branches     2495     2507      +12     
==========================================
+ Hits        47529    47576      +47     
- Misses        376      381       +5     
- Partials      124      127       +3     
Flag Coverage Δ
Autobahn 22.30% <42.34%> (+0.03%) ⬆️
CI-GHA 98.87% <89.18%> (-0.04%) ⬇️
OS-Linux 98.64% <89.18%> (-0.04%) ⬇️
OS-Windows 96.92% <71.17%> (-0.12%) ⬇️
OS-macOS 97.92% <89.18%> (-0.02%) ⬇️
Py-3.10 98.14% <85.58%> (+<0.01%) ⬆️
Py-3.11 98.37% <86.48%> (-0.05%) ⬇️
Py-3.12 98.46% <87.38%> (-0.04%) ⬇️
Py-3.13 98.44% <87.38%> (-0.04%) ⬇️
Py-3.14 98.46% <87.38%> (-0.04%) ⬇️
Py-3.14t 97.53% <81.08%> (-0.05%) ⬇️
Py-pypy-3.11 97.39% <80.18%> (-0.05%) ⬇️
PythonProvider-setup-python 97.57% <72.07%> (?)
PythonProvider-uv 98.87% <89.18%> (?)
VM-macos 97.92% <89.18%> (-0.02%) ⬇️
VM-ubuntu 98.64% <89.18%> (-0.04%) ⬇️
VM-windows 96.92% <71.17%> (-0.12%) ⬇️
cython-coverage 38.03% <16.21%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@tarasko tarasko changed the title Added aiofastnet to speedups extra Add aiofastnet to speedups extra Jun 6, 2026
@codspeed-hq

codspeed-hq Bot commented Jun 6, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 48.2%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 15 improved benchmarks
✅ 68 untouched benchmarks
⏩ 83 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
test_simple_web_file_sendfile_fallback_response[tcp-large] 127 ms 38.9 ms ×3.3
test_simple_web_file_response[ssl-large] 243.7 ms 76.7 ms ×3.2
test_simple_web_file_sendfile_fallback_response[ssl-large] 243.3 ms 103.5 ms ×2.4
test_one_thousand_round_trip_websocket_binary_messages[ssl-small] 39.6 ms 24.7 ms +60.36%
test_one_thousand_round_trip_websocket_binary_messages[ssl-large] 768.3 ms 485.3 ms +58.33%
test_simple_web_file_response[ssl-small] 117.1 ms 83.7 ms +39.93%
test_one_hundred_get_requests_with_1mb_chunked_payload[ssl] 1,277.7 ms 963.9 ms +32.55%
test_one_thousand_round_trip_websocket_binary_messages[tcp-small] 16.4 ms 13.1 ms +24.69%
test_one_thousand_round_trip_websocket_text_messages 16.8 ms 13.5 ms +24.52%
test_simple_web_file_sendfile_fallback_response[ssl-small] 117.3 ms 101.4 ms +15.68%
test_one_hundred_simple_get_requests[ssl] 46.8 ms 40.5 ms +15.33%
test_one_hundred_get_requests_with_1024_chunked_payload[ssl] 50.7 ms 44.2 ms +14.61%
test_simple_web_file_response[tcp-small] 83.8 ms 73.6 ms +13.91%
test_ten_streamed_responses_iter_chunked_4096 35.4 ms 32.6 ms +8.53%
test_ten_streamed_responses_iter_any 21.5 ms 19.8 ms +8.49%

Tip

Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.


Comparing tarasko:feature/speedups_aiofastnet (7a46045) with master (f5e63e8)2

Open in CodSpeed

Footnotes

  1. 83 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on master (85a150c) during the generation of this report, so f5e63e8 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@tarasko

tarasko commented Jun 6, 2026

Copy link
Copy Markdown
Contributor Author

@codspeedbot explain why this is faster

@tarasko tarasko marked this pull request as ready for review June 6, 2026 18:38
@Dreamsorcerer Dreamsorcerer added the backport-3.15 Trigger automatic backporting to the 3.15 release branch by Patchback robot label Jun 8, 2026
Comment thread aiohttp/connector.py Outdated
Comment thread aiohttp/web_fileresponse.py Outdated
_T_OnChunkSent = Optional[Callable[[bytes], Awaitable[None]]]


async def sendfile(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for these ones which are only referenced a single time, it probably makes more sense to do this inline, rather than wrapping the logic into a function.

@tarasko tarasko Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is convenient for mocking in tests. There is a fixture in test_web_sendfile_functional.py that now mocks it instead of loop.sendfile.

https://github.com/aio-libs/aiohttp/pull/12822/changes#diff-ab0c99993e60e45999a6cf0a1499f4ee5b8f04f65d738f39839d95e28927d417L83

That mock is only needed to simulate NotImplementedError() from sendfile and to run all tests both for native sendfile and _sendfile_fallback.

I preferred to keep changes in tests trivial, but of course it's possible to detect aiofastnet presence and choose what to mock: loop.sendfile or aiofastnet.sendfile directly in the fixture.

Do you want to do it this way?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As it's only one place in the tests, I'd probably just update the mocks.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment thread tests/conftest.py
Comment on lines +113 to +115
# aiofastnet is using sendfile on a non-blocking socket.
# blockbuster triggers anyway. Seems like a false positive
bb.functions["os.sendfile"].deactivate()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll let @bdraco check this one.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm unclear what all the changes in this file are about.

@tarasko tarasko Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes solve 2 problems:

  1. Load kernel tls module before running test_simple_web_file_response[ssl-*] benchmarks.
    I also dump OpenSSL version information, this is very helpful for troubleshooting in case OpenSSL refuses to use KTLS.

test_simple_web_file_response[ssl-large] is around 35% faster than test_simple_web_file_sendfile_fallback_response[ssl-large]
thanks to KTLS.

  1. With uv python, which is used now for all Test * jobs, aiofastnet is not being used.
    Attempt to import aiofastnet with such python results in ImportError and implementation falls back to native loop methods.

I wanted CI to check if all aiohttp tests pass when aiofastnet is usable/importable.
For that, I needed a regular python installed by actions/setup-python@v6

So I added 2 extra Test jobs specifically for ubuntu and macos, where python is installed with actions/setup-python@v6, and not with astral-sh/setup-uv@v8.2.0. Python version doesn't matter, so I chose 3.13.

You can see them in the latest CI run https://github.com/aio-libs/aiohttp/actions/runs/27721497815

Test (3.13, ubuntu, setup-python, false)
Test (3.13, macos, setup-python, false)

and all other jobs looks like this:

Test (3.13, ubuntu, uv, false)
Test (3.13, macos, uv, false)

There is no need to do it for windows, because uv managed python on windows is dynamically linked against openssl, AFAIK aiofastnet always work on windows, with any python.

@Dreamsorcerer

Copy link
Copy Markdown
Member

Looks to me like the PR is almost ready?

@tarasko tarasko marked this pull request as ready for review June 18, 2026 00:14
@tarasko

tarasko commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

Looks to me like the PR is almost

Yes, it is. But there is one thing that bothers me.

aiofastnet doesn't use stdlib ssl.SSLObject, instead it implements its own aiofastnet.SSLObject.
And it does NOT have some un-important (in my opinion) methods and attributes.

Users can get SSLObject via request.transport.get_extra_info('ssl_object'), and I have no idea what they are using it for. For example, there might be some very convoluted tests where people mock SSLObject read/write methods, and aiofastnet.SSLObject doesn't have them.

I'm preparing a full list of what is not available and I'll put it into aiofastnet README.

Here is what's available in the latest version:

    readonly str server_hostname
    readonly bint server_side

    cpdef object version(self)
    cpdef tuple cipher(self)
    cpdef object shared_ciphers(self)
    cpdef object getpeercert(self, binary_form=*)
    cpdef list get_verified_chain(self)
    cpdef list get_unverified_chain(self)
    cpdef object get_channel_binding(self, str cb_type=*)
    cpdef str compression(self)
    cpdef object selected_alpn_protocol(self)

Should cover all legitimate use-cases, but it is still potentially breaking.

@Dreamsorcerer

Copy link
Copy Markdown
Member

Should cover all legitimate use-cases, but it is still potentially breaking.

Probably low enough risk. Just add a breaking changenote I guess.

Comment thread tests/test_web_sendfile_functional.py Fixed
@tarasko

tarasko commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

Should cover all legitimate use-cases, but it is still potentially breaking.

Probably low enough risk. Just add a breaking changenote I guess.

Renamed CHANGES/12822.feature.rst -> 12822.breaking.rst

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-3.15 Trigger automatic backporting to the 3.15 release branch by Patchback robot bot:chronographer:provided There is a change note present in this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants