transport: Avoid buffer copies when reading Data frames#8657
Merged
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #8657 +/- ##
==========================================
- Coverage 83.29% 83.29% -0.01%
==========================================
Files 415 415
Lines 32134 32196 +62
==========================================
+ Hits 26767 26817 +50
- Misses 4001 4005 +4
- Partials 1366 1374 +8
🚀 New features to boost your workflow:
|
b5f777e to
ae8c8df
Compare
efe661b to
778af0a
Compare
778af0a to
45e856f
Compare
45e856f to
5ec4a4e
Compare
easwars
reviewed
Oct 16, 2025
arjan-bal
commented
Oct 21, 2025
arjan-bal
left a comment
Contributor
Author
There was a problem hiding this comment.
I realised that the changes in the std lib framer are not imported in g3 os this PR can't be merged in gRPC yet. I've added a Blocked label to indicate this.
Contributor
|
@dfawley: Moving to your plate in case you want to take a look. Thanks. |
dfawley
approved these changes
Oct 30, 2025
| t.controlBuf.put(&outgoingWindowUpdate{s.id, w}) | ||
| } | ||
| } | ||
| // TODO(bradfitz, zhaoq): A copy is required here because there is no |
Comment on lines
+413
to
+417
| if memPool == nil { | ||
| // Note that this is only supposed to be nil in tests. Otherwise, stream | ||
| // is always initialized with a BufferPool. | ||
| memPool = mem.DefaultBufferPool() | ||
| } |
Member
There was a problem hiding this comment.
Is it hard to fix the tests? Maybe we can do that as a follow-up.
Co-authored-by: Doug Fawley <dfawley@google.com>
8537f97 to
e7b6d35
Compare
arjan-bal
added a commit
to arjan-bal/grpc-go
that referenced
this pull request
Nov 3, 2025
This change incorporates changes from golang/go#73560 to split reading HTTP/2 frame headers and payloads. If the frame is not a Data frame, it's read through the standard library framer as before. For Data frames, the payload is read directly into a buffer from the buffer pool to avoid copying it from the framer's buffer. ## Testing For 1 MB payloads, this results in ~4% improvement in throughput. ```sh # test command go run benchmark/benchmain/main.go -benchtime=60s -workloads=streaming \ -compression=off -maxConcurrentCalls=120 -trace=off \ -reqSizeBytes=1000000 -respSizeBytes=1000000 -networkMode=Local -resultFile="${RUN_NAME}" # comparison go run benchmark/benchresult/main.go streaming-before streaming-after Title Before After Percentage TotalOps 87536 91120 4.09% SendOps 0 0 NaN% RecvOps 0 0 NaN% Bytes/op 4074102.92 4070489.30 -0.09% Allocs/op 83.60 76.55 -8.37% ReqT/op 11671466666.67 12149333333.33 4.09% RespT/op 11671466666.67 12149333333.33 4.09% 50th-Lat 78.209875ms 75.159943ms -3.90% 90th-Lat 117.764228ms 107.8697ms -8.40% 99th-Lat 146.935704ms 139.069685ms -5.35% Avg-Lat 82.310691ms 79.073282ms -3.93% GoVersion go1.24.7 go1.24.7 GrpcVersion 1.77.0-dev 1.77.0-dev ``` For smaller payloads, the difference in minor. ```sh go run benchmark/benchmain/main.go -benchtime=60s -workloads=streaming \ -compression=off -maxConcurrentCalls=120 -trace=off \ -reqSizeBytes=100 -respSizeBytes=100 -networkMode=Local -resultFile="${RUN_NAME}" go run benchmark/benchresult/main.go streaming-before streaming-after Title Before After Percentage TotalOps 21490752 21477822 -0.06% SendOps 0 0 NaN% RecvOps 0 0 NaN% Bytes/op 1902.92 1902.94 0.00% Allocs/op 29.21 29.21 0.00% ReqT/op 286543360.00 286370960.00 -0.06% RespT/op 286543360.00 286370960.00 -0.06% 50th-Lat 352.505µs 352.247µs -0.07% 90th-Lat 433.446µs 434.907µs 0.34% 99th-Lat 536.445µs 539.759µs 0.62% Avg-Lat 333.403µs 333.457µs 0.02% GoVersion go1.24.7 go1.24.7 GrpcVersion 1.77.0-dev 1.77.0-dev ``` RELEASE NOTES: * transport: Avoid a buffer copy when reading data.
arjan-bal
pushed a commit
that referenced
this pull request
Dec 4, 2025
- follow-up to #8657 commit 363018c updated the golang.org/x/net dependency to unclude some changes that had not yet been released. Now that v0.47.0 was released, we can switch back to released versions. full diff: golang/net@63d1a51...v0.47.0 RELEASE NOTES: N/A Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This was referenced Jan 12, 2026
eshitachandwani
added a commit
that referenced
this pull request
Jan 13, 2026
This PR remove the `grpchttp2` package since we no longer want to implement a custom http2 framer in grpc. We originally planned a custom HTTP/2 framer to get rid of internal copies. However, we have updated gRPC to control data frame I/O ([#8667](#8667), [#8657](#8657)) and will have changes that removes the bufio.Reader copy. This removes the need for a custom framer. RELEASE NOTES: None
atollena
pushed a commit
to zhiyanfoo/grpc-go
that referenced
this pull request
Jan 15, 2026
This PR remove the `grpchttp2` package since we no longer want to implement a custom http2 framer in grpc. We originally planned a custom HTTP/2 framer to get rid of internal copies. However, we have updated gRPC to control data frame I/O ([grpc#8667](grpc#8667), [grpc#8657](grpc#8657)) and will have changes that removes the bufio.Reader copy. This removes the need for a custom framer. RELEASE NOTES: None
mbissa
pushed a commit
to mbissa/grpc-go
that referenced
this pull request
Feb 16, 2026
This PR remove the `grpchttp2` package since we no longer want to implement a custom http2 framer in grpc. We originally planned a custom HTTP/2 framer to get rid of internal copies. However, we have updated gRPC to control data frame I/O ([grpc#8667](grpc#8667), [grpc#8657](grpc#8657)) and will have changes that removes the bufio.Reader copy. This removes the need for a custom framer. RELEASE NOTES: None
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This change incorporates changes from golang/go#73560 to split reading HTTP/2 frame headers and payloads. If the frame is not a Data frame, it's read through the standard library framer as before. For Data frames, the payload is read directly into a buffer from the buffer pool to avoid copying it from the framer's buffer.
Testing
For 1 MB payloads, this results in ~4% improvement in throughput.
For smaller payloads, the difference in minor.
go run benchmark/benchmain/main.go -benchtime=60s -workloads=streaming \ -compression=off -maxConcurrentCalls=120 -trace=off \ -reqSizeBytes=100 -respSizeBytes=100 -networkMode=Local -resultFile="${RUN_NAME}" go run benchmark/benchresult/main.go streaming-before streaming-after Title Before After Percentage TotalOps 21490752 21477822 -0.06% SendOps 0 0 NaN% RecvOps 0 0 NaN% Bytes/op 1902.92 1902.94 0.00% Allocs/op 29.21 29.21 0.00% ReqT/op 286543360.00 286370960.00 -0.06% RespT/op 286543360.00 286370960.00 -0.06% 50th-Lat 352.505µs 352.247µs -0.07% 90th-Lat 433.446µs 434.907µs 0.34% 99th-Lat 536.445µs 539.759µs 0.62% Avg-Lat 333.403µs 333.457µs 0.02% GoVersion go1.24.7 go1.24.7 GrpcVersion 1.77.0-dev 1.77.0-devRELEASE NOTES: