ソースを参照

dns/dnsmessage: add AppendPack method to Message

Add an AppendPack method to Message that appends the message data into a
byte buffer. Reusing a buffer allows for a reduction in allocations.

name          time/op
Pack-8        5.04µs ± 1%
AppendPack-8  4.95µs ± 2%

name          alloc/op
Pack-8        6.22kB ± 0%
AppendPack-8  5.71kB ± 0%

name          allocs/op
Pack-8          21.0 ± 0%
AppendPack-8    20.0 ± 0%

Change-Id: I8bb6b07787cf2ba9ef32e1e60a3003a585ec55be
Reviewed-on: https://go-review.googlesource.com/45274
Reviewed-by: Ian Gudger <igudger@google.com>
Reviewed-by: Mikio Hara <mikioh.mikioh@gmail.com>
Run-TryBot: Mikio Hara <mikioh.mikioh@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Ben Burkert 8 年 前
コミット
c73622c772
2 ファイル変更32 行追加3 行削除
  1. 7 3
      dns/dnsmessage/message.go
  2. 25 0
      dns/dnsmessage/message_test.go

+ 7 - 3
dns/dnsmessage/message.go

@@ -789,6 +789,12 @@ func (m *Message) Unpack(msg []byte) error {
 
 // Pack packs a full Message.
 func (m *Message) Pack() ([]byte, error) {
+	return m.AppendPack(make([]byte, 0, packStartingCap))
+}
+
+// AppendPack is like Pack but appends the full Message to b and returns the
+// extended buffer.
+func (m *Message) AppendPack(b []byte) ([]byte, error) {
 	// Validate the lengths. It is very unlikely that anyone will try to
 	// pack more than 65535 of any particular type, but it is possible and
 	// we should fail gracefully.
@@ -813,9 +819,7 @@ func (m *Message) Pack() ([]byte, error) {
 	h.authorities = uint16(len(m.Authorities))
 	h.additionals = uint16(len(m.Additionals))
 
-	msg := make([]byte, 0, packStartingCap)
-
-	msg = h.pack(msg)
+	msg := h.pack(b)
 
 	// RFC 1035 allows (but does not require) compression for packing. RFC
 	// 1035 requires unpacking implementations to support compression, so

+ 25 - 0
dns/dnsmessage/message_test.go

@@ -852,6 +852,31 @@ func smallTestMsg() Message {
 	}
 }
 
+func BenchmarkPack(b *testing.B) {
+	msg := largeTestMsg()
+
+	b.ReportAllocs()
+
+	for i := 0; i < b.N; i++ {
+		if _, err := msg.Pack(); err != nil {
+			b.Fatal(err)
+		}
+	}
+}
+
+func BenchmarkAppendPack(b *testing.B) {
+	msg := largeTestMsg()
+	buf := make([]byte, 0, packStartingCap)
+
+	b.ReportAllocs()
+
+	for i := 0; i < b.N; i++ {
+		if _, err := msg.AppendPack(buf[:0]); err != nil {
+			b.Fatal(err)
+		}
+	}
+}
+
 func largeTestMsg() Message {
 	name := mustNewName("foo.bar.example.com.")
 	return Message{