From 36ff5ab71a1f3e2efc98cc6e77139dbf7f424a9f Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 24 Apr 2017 22:27:47 +0000 Subject: [PATCH] Write psMap out directly rather than going via intermediate data structure --- extras/generate_latest_map | 18 +++-------------- report/counters.go | 5 ++++- report/edge_metadatas.go | 9 ++++----- report/latest_map_generated.go | 36 ++++++---------------------------- report/map_helpers.go | 21 +++++++++++++++++++- report/marshal.go | 4 ++++ report/sets.go | 8 +++----- 7 files changed, 44 insertions(+), 57 deletions(-) diff --git a/extras/generate_latest_map b/extras/generate_latest_map index 05051c3e8d..e738919251 100755 --- a/extras/generate_latest_map +++ b/extras/generate_latest_map @@ -155,23 +155,11 @@ function generate_latest_map() { }) } - func (m ${latest_map_type}) toIntermediate() map[string]${entry_type} { - intermediate := make(map[string]${entry_type}, m.Size()) - if m.Map != nil { - m.Map.ForEach(func(key string, val interface{}) { - intermediate[key] = *val.(*${entry_type}) - }) - } - return intermediate - } - // CodecEncodeSelf implements codec.Selfer. func (m *${latest_map_type}) CodecEncodeSelf(encoder *codec.Encoder) { - if m.Map != nil { - encoder.Encode(m.toIntermediate()) - } else { - encoder.Encode(nil) - } + mapWrite(m.Map, encoder, func(encoder *codec.Encoder, val interface{}) { + val.(*${entry_type}).CodecEncodeSelf(encoder) + }) } // CodecDecodeSelf implements codec.Selfer. diff --git a/report/counters.go b/report/counters.go index 82d2e92ef4..3ebb2729dd 100644 --- a/report/counters.go +++ b/report/counters.go @@ -155,7 +155,10 @@ func (c Counters) fromIntermediate(in map[string]int) Counters { // CodecEncodeSelf implements codec.Selfer func (c *Counters) CodecEncodeSelf(encoder *codec.Encoder) { - encoder.Encode(c.toIntermediate()) + mapWrite(c.psMap, encoder, func(encoder *codec.Encoder, val interface{}) { + i := val.(int) + encoder.Encode(i) + }) } // CodecDecodeSelf implements codec.Selfer diff --git a/report/edge_metadatas.go b/report/edge_metadatas.go index 13b0d40c0c..c0e4b8ed3e 100644 --- a/report/edge_metadatas.go +++ b/report/edge_metadatas.go @@ -168,11 +168,10 @@ func (c EdgeMetadatas) fromIntermediate(in map[string]EdgeMetadata) EdgeMetadata // CodecEncodeSelf implements codec.Selfer func (c *EdgeMetadatas) CodecEncodeSelf(encoder *codec.Encoder) { - if c.psMap != nil { - encoder.Encode(c.toIntermediate()) - } else { - encoder.Encode(nil) - } + mapWrite(c.psMap, encoder, func(encoder *codec.Encoder, val interface{}) { + e := val.(EdgeMetadata) + (&e).CodecEncodeSelf(encoder) + }) } // CodecDecodeSelf implements codec.Selfer diff --git a/report/latest_map_generated.go b/report/latest_map_generated.go index 7192cd7d6f..c17b318e6d 100644 --- a/report/latest_map_generated.go +++ b/report/latest_map_generated.go @@ -122,23 +122,11 @@ func (m StringLatestMap) DeepEqual(n StringLatestMap) bool { }) } -func (m StringLatestMap) toIntermediate() map[string]stringLatestEntry { - intermediate := make(map[string]stringLatestEntry, m.Size()) - if m.Map != nil { - m.Map.ForEach(func(key string, val interface{}) { - intermediate[key] = *val.(*stringLatestEntry) - }) - } - return intermediate -} - // CodecEncodeSelf implements codec.Selfer. func (m *StringLatestMap) CodecEncodeSelf(encoder *codec.Encoder) { - if m.Map != nil { - encoder.Encode(m.toIntermediate()) - } else { - encoder.Encode(nil) - } + mapWrite(m.Map, encoder, func(encoder *codec.Encoder, val interface{}) { + val.(*stringLatestEntry).CodecEncodeSelf(encoder) + }) } // CodecDecodeSelf implements codec.Selfer. @@ -274,23 +262,11 @@ func (m NodeControlDataLatestMap) DeepEqual(n NodeControlDataLatestMap) bool { }) } -func (m NodeControlDataLatestMap) toIntermediate() map[string]nodeControlDataLatestEntry { - intermediate := make(map[string]nodeControlDataLatestEntry, m.Size()) - if m.Map != nil { - m.Map.ForEach(func(key string, val interface{}) { - intermediate[key] = *val.(*nodeControlDataLatestEntry) - }) - } - return intermediate -} - // CodecEncodeSelf implements codec.Selfer. func (m *NodeControlDataLatestMap) CodecEncodeSelf(encoder *codec.Encoder) { - if m.Map != nil { - encoder.Encode(m.toIntermediate()) - } else { - encoder.Encode(nil) - } + mapWrite(m.Map, encoder, func(encoder *codec.Encoder, val interface{}) { + val.(*nodeControlDataLatestEntry).CodecEncodeSelf(encoder) + }) } // CodecDecodeSelf implements codec.Selfer. diff --git a/report/map_helpers.go b/report/map_helpers.go index d88175833c..f42978af4a 100644 --- a/report/map_helpers.go +++ b/report/map_helpers.go @@ -85,9 +85,10 @@ const ( containerMapKey = 2 containerMapValue = 3 containerMapEnd = 4 + // from https://github.com/ugorji/go/blob/master/codec/helper.go#L152 + cUTF8 = 2 ) -// CodecDecodeSelf implements codec.Selfer. // This implementation does not use the intermediate form as that was a // performance issue; skipping it saved almost 10% CPU. Note this means // we are using undocumented, internal APIs, which could break in the future. @@ -118,3 +119,21 @@ func mapRead(decoder *codec.Decoder, decodeValue func(isNil bool) interface{}) p z.DecSendContainerState(containerMapEnd) return out } + +// Inverse of mapRead, done for performance. Same comments about +// undocumented internal APIs apply. +func mapWrite(m ps.Map, encoder *codec.Encoder, encodeValue func(*codec.Encoder, interface{})) { + z, r := codec.GenHelperEncoder(encoder) + if m == nil { + r.EncodeNil() + return + } + r.EncodeMapStart(m.Size()) + m.ForEach(func(key string, val interface{}) { + z.EncSendContainerState(containerMapKey) + r.EncodeString(cUTF8, key) + z.EncSendContainerState(containerMapValue) + encodeValue(encoder, val) + }) + z.EncSendContainerState(containerMapEnd) +} diff --git a/report/marshal.go b/report/marshal.go index b21e01a17a..f5e2e776a5 100644 --- a/report/marshal.go +++ b/report/marshal.go @@ -17,6 +17,10 @@ func (s *dummySelfer) CodecDecodeSelf(decoder *codec.Decoder) { panic("This shouldn't happen: perhaps something has gone wrong in code generation?") } +func (s *dummySelfer) CodecEncodeSelf(encoder *codec.Encoder) { + panic("This shouldn't happen: perhaps something has gone wrong in code generation?") +} + // WriteBinary writes a Report as a gzipped msgpack. func (rep Report) WriteBinary(w io.Writer, compressionLevel int) error { gzwriter, err := gzip.NewWriterLevel(w, compressionLevel) diff --git a/report/sets.go b/report/sets.go index 821d6a2232..4ca5d755a7 100644 --- a/report/sets.go +++ b/report/sets.go @@ -168,11 +168,9 @@ func (s Sets) fromIntermediate(in map[string]StringSet) Sets { // CodecEncodeSelf implements codec.Selfer func (s *Sets) CodecEncodeSelf(encoder *codec.Encoder) { - if s.psMap != nil { - encoder.Encode(s.toIntermediate()) - } else { - encoder.Encode(nil) - } + mapWrite(s.psMap, encoder, func(encoder *codec.Encoder, val interface{}) { + encoder.Encode(val.(StringSet)) + }) } // CodecDecodeSelf implements codec.Selfer