Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Conversation

patchback[bot]
Copy link
Contributor

@patchback patchback bot commented Mar 30, 2025

This is a backport of PR #10601 as merged into master (f7cac7e).

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.

Screenshot 2025-03-19 at 10 21 54 AM

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.

<!-- 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 <[email protected]>
(cherry picked from commit f7cac7e)
@bdraco bdraco enabled auto-merge (squash) March 30, 2025 21:11
Copy link

codspeed-hq bot commented Mar 30, 2025

CodSpeed Performance Report

Merging #10640 will improve performances by 16.71%

Comparing patchback/backports/3.12/f7cac7e63f18691e4261af353e84f9073b16624a/pr-10601 (105229c) with 3.12 (5e20fe1)

Summary

⚡ 1 improvements
✅ 46 untouched benchmarks

Benchmarks breakdown

Benchmark BASE HEAD Change
test_read_one_hundred_websocket_text_messages[pyloop] 307 µs 263 µs +16.71%

Copy link

codecov bot commented Mar 30, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.09%. Comparing base (5e20fe1) to head (105229c).
Report is 10 commits behind head on 3.12.

✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             3.12   #10640   +/-   ##
=======================================
  Coverage   98.09%   98.09%           
=======================================
  Files         126      126           
  Lines       37531    37532    +1     
  Branches     2120     2120           
=======================================
+ Hits        36817    36818    +1     
  Misses        545      545           
  Partials      169      169           
Flag Coverage Δ
CI-GHA 97.98% <100.00%> (+<0.01%) ⬆️
OS-Linux 97.68% <100.00%> (+<0.01%) ⬆️
OS-Windows 94.74% <0.00%> (-0.01%) ⬇️
OS-macOS 96.81% <0.00%> (-0.01%) ⬇️
Py-3.10.11 96.69% <0.00%> (-0.01%) ⬇️
Py-3.10.16 97.26% <100.00%> (-0.01%) ⬇️
Py-3.11.11 97.36% <100.00%> (-0.01%) ⬇️
Py-3.11.9 96.80% <0.00%> (+<0.01%) ⬆️
Py-3.12.9 97.77% <100.00%> (+<0.01%) ⬆️
Py-3.13.2 97.76% <100.00%> (+<0.01%) ⬆️
Py-3.9.13 96.59% <0.00%> (-0.01%) ⬇️
Py-3.9.21 97.11% <100.00%> (-0.04%) ⬇️
Py-pypy7.3.16 94.02% <100.00%> (+12.63%) ⬆️
VM-macos 96.81% <0.00%> (-0.01%) ⬇️
VM-ubuntu 97.68% <100.00%> (+<0.01%) ⬆️
VM-windows 94.74% <0.00%> (-0.01%) ⬇️

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

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

@bdraco bdraco merged commit 9d4c09a into 3.12 Mar 30, 2025
36 checks passed
@bdraco bdraco deleted the patchback/backports/3.12/f7cac7e63f18691e4261af353e84f9073b16624a/pr-10601 branch March 30, 2025 22:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant