Avatar for the aio-libs user
aio-libs
aiohttp
BlogDocsChangelog

[PR #10601/f7cac7e6 backport][3.12] Reduce WebSocket buffer slicing overhead

#10640Merged
Comparing
patchback/backports/3.12/f7cac7e63f18691e4261af353e84f9073b16624a/pr-10601
(
105229c
) with
3.12
(
5e20fe1
)
CodSpeed Performance Gauge
+17%
Improvements
1
Regressions
0
Untouched
46
New
0
Dropped
0
Ignored
2

Benchmarks

Improved

test_read_one_hundred_websocket_text_messages[pyloop]
tests/test_benchmarks_http_websocket.py::test_read_one_hundred_websocket_text_messages[pyloop]
CodSpeed Performance Gauge
+17%
307 µs
263 µs

Passed

test_load_cookies_into_temp_cookiejar
tests/test_benchmarks_cookiejar.py::test_load_cookies_into_temp_cookiejar
CodSpeed Performance Gauge
+1%
202 µs
200.3 µs
test_read_large_binary_websocket_messages[pyloop]
tests/test_benchmarks_http_websocket.py::test_read_large_binary_websocket_messages[pyloop]
CodSpeed Performance Gauge
+1%
9.1 ms
9 ms
test_client_request_update_cookies[pyloop]
tests/test_benchmarks_client_request.py::test_client_request_update_cookies[pyloop]
CodSpeed Performance Gauge
+1%
170.1 µs
168.9 µs
test_web_response_with_bytes_body
tests/test_benchmarks_web_response.py::test_web_response_with_bytes_body
CodSpeed Performance Gauge
+1%
540.9 µs
537.8 µs
test_resolve_static_root_route[pyloop]
tests/test_benchmarks_web_urldispatcher.py::test_resolve_static_root_route[pyloop]
CodSpeed Performance Gauge
0%
987.1 µs
983.2 µs
test_resolve_gitapi_root[pyloop]
tests/test_benchmarks_web_urldispatcher.py::test_resolve_gitapi_root[pyloop]
CodSpeed Performance Gauge
0%
2 ms
2 ms
test_resolve_dynamic_resource_url_with_many_dynamic_routes[pyloop]
tests/test_benchmarks_web_urldispatcher.py::test_resolve_dynamic_resource_url_with_many_dynamic_routes[pyloop]
CodSpeed Performance Gauge
0%
3.5 ms
3.5 ms
test_resolve_single_fixed_url_with_many_routes[pyloop]
tests/test_benchmarks_web_urldispatcher.py::test_resolve_single_fixed_url_with_many_routes[pyloop]
CodSpeed Performance Gauge
0%
891.8 µs
889.4 µs
test_resolve_multiple_level_fixed_url_with_many_routes[pyloop]
tests/test_benchmarks_web_urldispatcher.py::test_resolve_multiple_level_fixed_url_with_many_routes[pyloop]
CodSpeed Performance Gauge
0%
8.5 ms
8.5 ms
test_create_client_request_with_headers[pyloop]
tests/test_benchmarks_client_request.py::test_create_client_request_with_headers[pyloop]
CodSpeed Performance Gauge
0%
70.6 µs
70.5 µs
test_web_response_with_text_body
tests/test_benchmarks_web_response.py::test_web_response_with_text_body
CodSpeed Performance Gauge
0%
654.3 µs
653.9 µs
test_resolve_root_route_with_many_fixed_routes[pyloop]
tests/test_benchmarks_web_urldispatcher.py::test_resolve_root_route_with_many_fixed_routes[pyloop]
CodSpeed Performance Gauge
0%
881.2 µs
880.8 µs
test_resolve_multiple_fixed_url_with_many_routes[pyloop]
tests/test_benchmarks_web_urldispatcher.py::test_resolve_multiple_fixed_url_with_many_routes[pyloop]
CodSpeed Performance Gauge
0%
2.2 ms
2.2 ms
test_get_request_with_251308_compressed_chunked_payload[pyloop]
tests/test_benchmarks_client.py::test_get_request_with_251308_compressed_chunked_payload[pyloop]
CodSpeed Performance Gauge
0%
426 ms
425.9 ms
test_send_one_hundred_websocket_compressed_messages[pyloop]
tests/test_benchmarks_http_websocket.py::test_send_one_hundred_websocket_compressed_messages[pyloop]
CodSpeed Performance Gauge
0%
3 ms
3 ms
test_simple_web_stream_response
tests/test_benchmarks_web_response.py::test_simple_web_stream_response
CodSpeed Performance Gauge
0%
240 µs
240.1 µs
test_simple_web_response
tests/test_benchmarks_web_response.py::test_simple_web_response
CodSpeed Performance Gauge
0%
443.2 µs
443.5 µs
test_resolve_prefix_resources_many_prefix_many_plain[pyloop]
tests/test_benchmarks_web_urldispatcher.py::test_resolve_prefix_resources_many_prefix_many_plain[pyloop]
CodSpeed Performance Gauge
0%
4.9 ms
4.9 ms
test_send_client_request_one_hundred[pyloop]
tests/test_benchmarks_client_request.py::test_send_client_request_one_hundred[pyloop]
CodSpeed Performance Gauge
0%
2.4 ms
2.4 ms
test_send_one_hundred_large_websocket_text_messages[pyloop]
tests/test_benchmarks_http_websocket.py::test_send_one_hundred_large_websocket_text_messages[pyloop]
CodSpeed Performance Gauge
0%
533.1 µs
533.8 µs
test_resolve_dynamic_resource_url_with_many_static_routes[pyloop]
tests/test_benchmarks_web_urldispatcher.py::test_resolve_dynamic_resource_url_with_many_static_routes[pyloop]
CodSpeed Performance Gauge
0%
3.6 ms
3.6 ms
test_simple_web_file_response_not_modified[pyloop]
tests/test_benchmarks_web_fileresponse.py::test_simple_web_file_response_not_modified[pyloop]
CodSpeed Performance Gauge
0%
55.5 ms
55.5 ms
test_send_one_hundred_websocket_text_messages[pyloop]
tests/test_benchmarks_http_websocket.py::test_send_one_hundred_websocket_text_messages[pyloop]
CodSpeed Performance Gauge
0%
558.9 µs
560 µs
test_simple_web_file_sendfile_fallback_response[pyloop]
tests/test_benchmarks_web_fileresponse.py::test_simple_web_file_sendfile_fallback_response[pyloop]
CodSpeed Performance Gauge
0%
84.6 ms
84.8 ms
test_one_thousand_large_round_trip_websocket_text_messages[pyloop]
tests/test_benchmarks_client_ws.py::test_one_thousand_large_round_trip_websocket_text_messages[pyloop]
CodSpeed Performance Gauge
0%
23.2 ms
23.3 ms
test_resolve_gitapi_subapps[pyloop]
tests/test_benchmarks_web_urldispatcher.py::test_resolve_gitapi_subapps[pyloop]
CodSpeed Performance Gauge
0%
295.6 ms
296.3 ms
test_resolve_root_route[pyloop]
tests/test_benchmarks_web_urldispatcher.py::test_resolve_root_route[pyloop]
CodSpeed Performance Gauge
0%
884.7 µs
886.9 µs
test_resolve_dynamic_resource_url_with_many_dynamic_routes_with_common_prefix[pyloop]
tests/test_benchmarks_web_urldispatcher.py::test_resolve_dynamic_resource_url_with_many_dynamic_routes_with_common_prefix[pyloop]
CodSpeed Performance Gauge
0%
246 ms
246.8 ms
test_serialize_headers
tests/test_benchmarks_http_writer.py::test_serialize_headers
CodSpeed Performance Gauge
0%
1 ms
1 ms
test_one_hundred_get_requests_with_512kib_content_length_payload[pyloop]
tests/test_benchmarks_client.py::test_one_hundred_get_requests_with_512kib_content_length_payload[pyloop]
CodSpeed Performance Gauge
0%
164.7 ms
165.4 ms
test_send_one_hundred_websocket_text_messages_with_mask[pyloop]
tests/test_benchmarks_http_websocket.py::test_send_one_hundred_websocket_text_messages_with_mask[pyloop]
CodSpeed Performance Gauge
0%
795.3 µs
798.7 µs
test_one_hundred_simple_get_requests_multiple_methods_route[pyloop]
tests/test_benchmarks_client.py::test_one_hundred_simple_get_requests_multiple_methods_route[pyloop]
CodSpeed Performance Gauge
-1%
32 ms
32.2 ms
test_one_hundred_simple_get_requests[pyloop]
tests/test_benchmarks_client.py::test_one_hundred_simple_get_requests[pyloop]
CodSpeed Performance Gauge
-1%
32.2 ms
32.5 ms
test_ten_web_middlewares[pyloop]
tests/test_benchmarks_web_middleware.py::test_ten_web_middlewares[pyloop]
CodSpeed Performance Gauge
-1%
35 ms
35.3 ms
test_web_response_with_headers
tests/test_benchmarks_web_response.py::test_web_response_with_headers
CodSpeed Performance Gauge
-1%
880.9 µs
889.3 µs
test_create_client_request_with_cookies[pyloop]
tests/test_benchmarks_client_request.py::test_create_client_request_with_cookies[pyloop]
CodSpeed Performance Gauge
-1%
125.1 µs
126.3 µs
test_one_hundred_get_requests_with_30000_content_length_payload[pyloop]
tests/test_benchmarks_client.py::test_one_hundred_get_requests_with_30000_content_length_payload[pyloop]
CodSpeed Performance Gauge
-1%
39.4 ms
39.8 ms
test_one_hundred_simple_post_requests[pyloop]
tests/test_benchmarks_client.py::test_one_hundred_simple_post_requests[pyloop]
CodSpeed Performance Gauge
-1%
36.7 ms
37.1 ms
test_one_hundred_get_requests_with_1024_chunked_payload[pyloop]
tests/test_benchmarks_client.py::test_one_hundred_get_requests_with_1024_chunked_payload[pyloop]
CodSpeed Performance Gauge
-1%
35.5 ms
35.9 ms
test_one_hundred_get_requests_with_1024_content_length_payload[pyloop]
tests/test_benchmarks_client.py::test_one_hundred_get_requests_with_1024_content_length_payload[pyloop]
CodSpeed Performance Gauge
-1%
35.2 ms
35.5 ms
test_one_hundred_get_requests_with_30000_chunked_payload[pyloop]
tests/test_benchmarks_client.py::test_one_hundred_get_requests_with_30000_chunked_payload[pyloop]
CodSpeed Performance Gauge
-1%
40.6 ms
41 ms
test_resolve_gitapi[pyloop]
tests/test_benchmarks_web_urldispatcher.py::test_resolve_gitapi[pyloop]
CodSpeed Performance Gauge
-1%
293.5 ms
297.3 ms
test_simple_web_file_response[pyloop]
tests/test_benchmarks_web_fileresponse.py::test_simple_web_file_response[pyloop]
CodSpeed Performance Gauge
-1%
78.1 ms
79.1 ms
test_one_hundred_json_post_requests[pyloop]
tests/test_benchmarks_client.py::test_one_hundred_json_post_requests[pyloop]
CodSpeed Performance Gauge
-1%
38.5 ms
39.1 ms
test_one_thousand_round_trip_websocket_binary_messages[pyloop]
tests/test_benchmarks_client_ws.py::test_one_thousand_round_trip_websocket_binary_messages[pyloop]
CodSpeed Performance Gauge
-4%
17 ms
17.7 ms
test_one_thousand_round_trip_websocket_text_messages[pyloop]
tests/test_benchmarks_client_ws.py::test_one_thousand_round_trip_websocket_text_messages[pyloop]
CodSpeed Performance Gauge
-4%
17.5 ms
18.2 ms

Ignored

test_one_hundred_get_requests_iter_chunks_on_512kib_chunked_payload[pyloop]Ignored
tests/test_benchmarks_client.py::test_one_hundred_get_requests_iter_chunks_on_512kib_chunked_payload[pyloop]
CodSpeed Performance Gauge
-19%
96.9 ms
120.1 ms
test_one_hundred_get_requests_with_512kib_chunked_payload[pyloop]Ignored
tests/test_benchmarks_client.py::test_one_hundred_get_requests_with_512kib_chunked_payload[pyloop]
CodSpeed Performance Gauge
+13%
188.6 ms
167 ms

Commits

Click on a commit to change the comparison range
Base
3.12
5e20fe1
+17%
Reduce WebSocket buffer slicing overhead (#10601) <!-- Thank you for your contribution! --> ## What do these changes do? Use a `const unsigned char *` for the buffer (Cython will automatically extract is using `__Pyx_PyBytes_AsUString`) as its a lot faster than copying around `PyBytes` objects. We do need to be careful that all slices are bounded and we bound check everything to make sure we do not do an out of bounds read since Cython does not bounds check C strings. I checked that all accesses to `buf_cstr` are proceeded by a bounds check but it would be good to get another set of eyes on that to verify in the `self._state == READ_PAYLOAD` block that we will never try to read out of bounds. <img width="376" alt="Screenshot 2025-03-19 at 10 21 54 AM" src="https://github.com/user-attachments/assets/a340ffa2-f09b-4aff-a4f7-c487dae186c8" /> ## Are there changes in behavior for the user? performance improvement ## Is it a substantial burden for the maintainers to support this? no There is a small risk that someone could remove a bounds check in the future and create a memory safety issue, however in this case its likely we would already be trying to read data that wasn't there if we are missing the bounds checking so the pure python version would throw if we are testing properly. --------- Co-authored-by: Sam Bull <git@sambull.org> (cherry picked from commit f7cac7e63f18691e4261af353e84f9073b16624a)
105229c
15 days ago
by bdraco
© 2025 CodSpeed Technology
Home Terms PrivacyDocs