Skip to content

Commit 919c6bc

Browse files
evanjseankhliao
authored andcommitted
http2: use an array instead of a map in typeFrameParser
FrameType is a dense integer range, so we can store the frameParsers in an array instead of a map. This should be a very small performance win on all Go http2 servers. For high QPS gRPC services, this function is visible in the Go profiler. For example, it shows up as 0.16% of all CPU time on one production service at Datadog. Change FrameType.String() to use the same pattern. Add a test for testFrameType with unknown FrameTypes. Fixes golang/go#73613 Change-Id: I5f5b523e011a99d6b428cbdbfd97415e488169d1 Reviewed-on: https://go-review.googlesource.com/c/net/+/670415 Reviewed-by: Sean Liao <[email protected]> Reviewed-by: Cherry Mui <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent bae01a7 commit 919c6bc

File tree

2 files changed

+25
-7
lines changed

2 files changed

+25
-7
lines changed

http2/frame.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const (
3939
FrameContinuation FrameType = 0x9
4040
)
4141

42-
var frameName = map[FrameType]string{
42+
var frameNames = [...]string{
4343
FrameData: "DATA",
4444
FrameHeaders: "HEADERS",
4545
FramePriority: "PRIORITY",
@@ -53,10 +53,10 @@ var frameName = map[FrameType]string{
5353
}
5454

5555
func (t FrameType) String() string {
56-
if s, ok := frameName[t]; ok {
57-
return s
56+
if int(t) < len(frameNames) {
57+
return frameNames[t]
5858
}
59-
return fmt.Sprintf("UNKNOWN_FRAME_TYPE_%d", uint8(t))
59+
return fmt.Sprintf("UNKNOWN_FRAME_TYPE_%d", t)
6060
}
6161

6262
// Flags is a bitmask of HTTP/2 flags.
@@ -124,7 +124,7 @@ var flagName = map[FrameType]map[Flags]string{
124124
// might be 0).
125125
type frameParser func(fc *frameCache, fh FrameHeader, countError func(string), payload []byte) (Frame, error)
126126

127-
var frameParsers = map[FrameType]frameParser{
127+
var frameParsers = [...]frameParser{
128128
FrameData: parseDataFrame,
129129
FrameHeaders: parseHeadersFrame,
130130
FramePriority: parsePriorityFrame,
@@ -138,8 +138,8 @@ var frameParsers = map[FrameType]frameParser{
138138
}
139139

140140
func typeFrameParser(t FrameType) frameParser {
141-
if f := frameParsers[t]; f != nil {
142-
return f
141+
if int(t) < len(frameParsers) {
142+
return frameParsers[t]
143143
}
144144
return parseUnknownFrame
145145
}

http2/frame_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,3 +1258,21 @@ func TestSettingsDuplicates(t *testing.T) {
12581258
}
12591259

12601260
}
1261+
1262+
func TestTypeFrameParser(t *testing.T) {
1263+
if len(frameNames) != len(frameParsers) {
1264+
t.Errorf("expected len(frameNames)=%d to equal len(frameParsers)=%d",
1265+
len(frameNames), len(frameParsers))
1266+
}
1267+
1268+
// typeFrameParser() for an unknown type returns a function that returns UnknownFrame
1269+
unknownFrameType := FrameType(FrameContinuation + 1)
1270+
unknownParser := typeFrameParser(unknownFrameType)
1271+
frame, err := unknownParser(nil, FrameHeader{}, nil, nil)
1272+
if err != nil {
1273+
t.Errorf("unknownParser() must not return an error: %v", err)
1274+
}
1275+
if _, isUnknown := frame.(*UnknownFrame); !isUnknown {
1276+
t.Errorf("expected UnknownFrame, got %T", frame)
1277+
}
1278+
}

0 commit comments

Comments
 (0)