http2/hpack: reduce memory for huffman decoding table
Reduces process-wide heap (inuse_space) by 60kB by using a pointer to
a fixed-sized array instead of a slice of a fixed size.
Before:
119.44kB 23.43% 23.43% 147.88kB 29.01% golang.org/x/net/http2/hpack.addDecoderNode
After:
59.72kB 13.28% 39.85% 87.94kB 19.56% golang.org/x/net/http2/hpack.addDecoderNode
(This is all work from an init func in http2/hpack)
Doesn't seem to affect runtime performance.
Measured with:
$ cat huffman_test.go
package main
import (
"testing"
_ "golang.org/x/net/http2"
)
func TestMem(t *testing.T) {}
$ GODEBUG=memprofilerate=1 go test -memprofilerate=1 -memprofile=mem.prof -v .
=== RUN TestMem
--- PASS: TestMem (0.00s)
PASS
ok huffmem 0.052s
$ go tool pprof --inuse_space mem.prof
Change-Id: I5e56a5a2682f1063c955b342b37e97ca4c303dab
Reviewed-on: https://go-review.googlesource.com/127235
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/http2/hpack/hpack_test.go b/http2/hpack/hpack_test.go
index 974c35f..3f22274 100644
--- a/http2/hpack/hpack_test.go
+++ b/http2/hpack/hpack_test.go
@@ -462,6 +462,27 @@
}
}
+func BenchmarkHuffmanDecode(b *testing.B) {
+ b.StopTimer()
+ enc, err := hex.DecodeString(strings.Replace("94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07",
+ " ", "", -1))
+ if err != nil {
+ b.Fatal(err)
+ }
+ b.ReportAllocs()
+ b.StartTimer()
+ var buf bytes.Buffer
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ if _, err := HuffmanDecode(&buf, enc); err != nil {
+ b.Fatalf("decode error: %v", err)
+ }
+ if string(buf.Bytes()) != "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1" {
+ b.Fatalf("bogus output %q", buf.Bytes())
+ }
+ }
+}
+
func TestAppendHuffmanString(t *testing.T) {
tests := []struct {
in, want string
diff --git a/http2/hpack/huffman.go b/http2/hpack/huffman.go
index 8850e39..87ec2aa 100644
--- a/http2/hpack/huffman.go
+++ b/http2/hpack/huffman.go
@@ -106,7 +106,7 @@
type node struct {
// children is non-nil for internal nodes
- children []*node
+ children *[256]*node
// The following are only valid if children is nil:
codeLen uint8 // number of bits that led to the output of sym
@@ -114,7 +114,7 @@
}
func newInternalNode() *node {
- return &node{children: make([]*node, 256)}
+ return &node{children: new([256]*node)}
}
var rootHuffmanNode = newInternalNode()