]> git.feebdaed.xyz Git - 0xmirror/grpc-go.git/commit
transport: Avoid buffer copies when reading Data frames (#8657)
authorArjan Singh Bal <46515553+arjan-bal@users.noreply.github.com>
Fri, 31 Oct 2025 06:27:49 +0000 (11:57 +0530)
committerGitHub <noreply@github.com>
Fri, 31 Oct 2025 06:27:49 +0000 (11:57 +0530)
commit363018c3d687d40153225f283301d3e491e7c5a4
tree0c033a8a84aada3ebaafb7a807e7658e85f005d8
parent64cba2defcd9c52632bc37c6530951871afdc038
transport: Avoid buffer copies when reading Data frames (#8657)

This change incorporates changes from
https://github.com/golang/go/issues/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.
22 files changed:
examples/go.mod
examples/go.sum
gcp/observability/go.mod
gcp/observability/go.sum
go.mod
go.sum
internal/transport/http2_client.go
internal/transport/http2_server.go
internal/transport/http_util.go
internal/transport/http_util_test.go
internal/transport/keepalive_test.go
interop/observability/go.mod
interop/observability/go.sum
interop/xds/go.mod
interop/xds/go.sum
mem/buffer_pool.go
security/advancedtls/examples/go.mod
security/advancedtls/examples/go.sum
security/advancedtls/go.mod
security/advancedtls/go.sum
stats/opencensus/go.mod
stats/opencensus/go.sum