Skip to content

Commit 8420f3f

Browse files
authored
transport: avoid slice reallocation during header creation (#8547)
This PR improves the size estimate while pre-allocating `headerFields` to avoid reallocations, which pprof showed were responsible for ~4% of total memory allocations. This change improves performance, increasing QPS by 1% while reducing bytes/op by 4% and latencies by 0.3-4%. ## Tested ```sh go run benchmark/benchresult/main.go unary-before unary-after unary-networkMode_Local-bufConn_false-keepalive_false-benchTime_1m0s-trace_false-latency_0s-kbps_0-MTU_0-maxConcurrentCalls_120-reqSiz e_1024B-respSize_1024B-compressor_off-channelz_false-preloader_false-clientReadBufferSize_-1-clientWriteBufferSize_-1-serverReadBuffer Size_-1-serverWriteBufferSize_-1-sleepBetweenRPCs_0s-connections_1-recvBufferPool_simple-sharedWriteBuffer_false Title Before After Percentage TotalOps 6327736 6390728 1.00% SendOps 0 0 NaN% RecvOps 0 0 NaN% Bytes/op 13903.23 13354.55 -3.95% Allocs/op 156.22 155.23 -0.64% ReqT/op 863946888.53 872547396.27 1.00% RespT/op 863946888.53 872547396.27 1.00% 50th-Lat 1.00991ms 1.006914ms -0.30% 90th-Lat 1.678329ms 1.610331ms -4.05% 99th-Lat 2.517556ms 2.497122ms -0.81% Avg-Lat 1.136117ms 1.125311ms -0.95% GoVersion go1.24.4 go1.24.4 GrpcVersion 1.76.0-dev 1.76.0-dev ``` RELEASE NOTES: * client: Improve header slice length estimate to reduce re-allocations.
1 parent b36320e commit 8420f3f

File tree

1 file changed

+13
-1
lines changed

1 file changed

+13
-1
lines changed

internal/transport/http2_client.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,19 @@ func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr)
556556
// Make the slice of certain predictable size to reduce allocations made by append.
557557
hfLen := 7 // :method, :scheme, :path, :authority, content-type, user-agent, te
558558
hfLen += len(authData) + len(callAuthData)
559+
registeredCompressors := t.registeredCompressors
560+
if callHdr.PreviousAttempts > 0 {
561+
hfLen++
562+
}
563+
if callHdr.SendCompress != "" {
564+
hfLen++
565+
}
566+
if registeredCompressors != "" {
567+
hfLen++
568+
}
569+
if _, ok := ctx.Deadline(); ok {
570+
hfLen++
571+
}
559572
headerFields := make([]hpack.HeaderField, 0, hfLen)
560573
headerFields = append(headerFields, hpack.HeaderField{Name: ":method", Value: "POST"})
561574
headerFields = append(headerFields, hpack.HeaderField{Name: ":scheme", Value: t.scheme})
@@ -568,7 +581,6 @@ func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr)
568581
headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-previous-rpc-attempts", Value: strconv.Itoa(callHdr.PreviousAttempts)})
569582
}
570583

571-
registeredCompressors := t.registeredCompressors
572584
if callHdr.SendCompress != "" {
573585
headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-encoding", Value: callHdr.SendCompress})
574586
// Include the outgoing compressor name when compressor is not registered

0 commit comments

Comments
 (0)