1// Go support for Protocol Buffers - Google's data interchange format 2// 3// Copyright 2010 The Go Authors. All rights reserved. 4// https://github.com/golang/protobuf 5// 6// Redistribution and use in source and binary forms, with or without 7// modification, are permitted provided that the following conditions are 8// met: 9// 10// * Redistributions of source code must retain the above copyright 11// notice, this list of conditions and the following disclaimer. 12// * Redistributions in binary form must reproduce the above 13// copyright notice, this list of conditions and the following disclaimer 14// in the documentation and/or other materials provided with the 15// distribution. 16// * Neither the name of Google Inc. nor the names of its 17// contributors may be used to endorse or promote products derived from 18// this software without specific prior written permission. 19// 20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 32// +build go1.7 33 34package proto_test 35 36import ( 37 "testing" 38 39 "github.com/gogo/protobuf/proto" 40 tpb "github.com/gogo/protobuf/proto/proto3_proto" 41) 42 43var msgBlackhole = new(tpb.Message) 44 45// Disabled this Benchmark because it is using features (b.Run) from go1.7 and gogoprotobuf still have compatibility with go1.5 46// BenchmarkVarint32ArraySmall shows the performance on an array of small int32 fields (1 and 47// 2 bytes long). 48// func BenchmarkVarint32ArraySmall(b *testing.B) { 49// for i := uint(1); i <= 10; i++ { 50// dist := genInt32Dist([7]int{0, 3, 1}, 1<<i) 51// raw, err := proto.Marshal(&tpb.Message{ 52// ShortKey: dist, 53// }) 54// if err != nil { 55// b.Error("wrong encode", err) 56// } 57// b.Run(fmt.Sprintf("Len%v", len(dist)), func(b *testing.B) { 58// scratchBuf := proto.NewBuffer(nil) 59// b.ResetTimer() 60// for k := 0; k < b.N; k++ { 61// scratchBuf.SetBuf(raw) 62// msgBlackhole.Reset() 63// if err := scratchBuf.Unmarshal(msgBlackhole); err != nil { 64// b.Error("wrong decode", err) 65// } 66// } 67// }) 68// } 69// } 70 71// Disabled this Benchmark because it is using features (b.Run) from go1.7 and gogoprotobuf still have compatibility with go1.5 72// BenchmarkVarint32ArrayLarge shows the performance on an array of large int32 fields (3 and 73// 4 bytes long, with a small number of 1, 2, 5 and 10 byte long versions). 74// func BenchmarkVarint32ArrayLarge(b *testing.B) { 75// for i := uint(1); i <= 10; i++ { 76// dist := genInt32Dist([7]int{0, 1, 2, 4, 8, 1, 1}, 1<<i) 77// raw, err := proto.Marshal(&tpb.Message{ 78// ShortKey: dist, 79// }) 80// if err != nil { 81// b.Error("wrong encode", err) 82// } 83// b.Run(fmt.Sprintf("Len%v", len(dist)), func(b *testing.B) { 84// scratchBuf := proto.NewBuffer(nil) 85// b.ResetTimer() 86// for k := 0; k < b.N; k++ { 87// scratchBuf.SetBuf(raw) 88// msgBlackhole.Reset() 89// if err := scratchBuf.Unmarshal(msgBlackhole); err != nil { 90// b.Error("wrong decode", err) 91// } 92// } 93// }) 94// } 95// } 96 97// Disabled this Benchmark because it is using features (b.Run) from go1.7 and gogoprotobuf still have compatibility with go1.5 98// BenchmarkVarint64ArraySmall shows the performance on an array of small int64 fields (1 and 99// 2 bytes long). 100// func BenchmarkVarint64ArraySmall(b *testing.B) { 101// for i := uint(1); i <= 10; i++ { 102// dist := genUint64Dist([11]int{0, 3, 1}, 1<<i) 103// raw, err := proto.Marshal(&tpb.Message{ 104// Key: dist, 105// }) 106// if err != nil { 107// b.Error("wrong encode", err) 108// } 109// b.Run(fmt.Sprintf("Len%v", len(dist)), func(b *testing.B) { 110// scratchBuf := proto.NewBuffer(nil) 111// b.ResetTimer() 112// for k := 0; k < b.N; k++ { 113// scratchBuf.SetBuf(raw) 114// msgBlackhole.Reset() 115// if err := scratchBuf.Unmarshal(msgBlackhole); err != nil { 116// b.Error("wrong decode", err) 117// } 118// } 119// }) 120// } 121// } 122 123// Disabled this Benchmark because it is using features (b.Run) from go1.7 and gogoprotobuf still have compatibility with go1.5 124// BenchmarkVarint64ArrayLarge shows the performance on an array of large int64 fields (6, 7, 125// and 8 bytes long with a small number of the other sizes). 126// func BenchmarkVarint64ArrayLarge(b *testing.B) { 127// for i := uint(1); i <= 10; i++ { 128// dist := genUint64Dist([11]int{0, 1, 1, 2, 4, 8, 16, 32, 16, 1, 1}, 1<<i) 129// raw, err := proto.Marshal(&tpb.Message{ 130// Key: dist, 131// }) 132// if err != nil { 133// b.Error("wrong encode", err) 134// } 135// b.Run(fmt.Sprintf("Len%v", len(dist)), func(b *testing.B) { 136// scratchBuf := proto.NewBuffer(nil) 137// b.ResetTimer() 138// for k := 0; k < b.N; k++ { 139// scratchBuf.SetBuf(raw) 140// msgBlackhole.Reset() 141// if err := scratchBuf.Unmarshal(msgBlackhole); err != nil { 142// b.Error("wrong decode", err) 143// } 144// } 145// }) 146// } 147// } 148 149// Disabled this Benchmark because it is using features (b.Run) from go1.7 and gogoprotobuf still have compatibility with go1.5 150// BenchmarkVarint64ArrayMixed shows the performance of lots of small messages, each 151// containing a small number of large (3, 4, and 5 byte) repeated int64s. 152// func BenchmarkVarint64ArrayMixed(b *testing.B) { 153// for i := uint(1); i <= 1<<5; i <<= 1 { 154// dist := genUint64Dist([11]int{0, 0, 0, 4, 6, 4, 0, 0, 0, 0, 0}, int(i)) 155// // number of sub fields 156// for k := uint(1); k <= 1<<10; k <<= 2 { 157// msg := &tpb.Message{} 158// for m := uint(0); m < k; m++ { 159// msg.Children = append(msg.Children, &tpb.Message{ 160// Key: dist, 161// }) 162// } 163// raw, err := proto.Marshal(msg) 164// if err != nil { 165// b.Error("wrong encode", err) 166// } 167// b.Run(fmt.Sprintf("Fields%vLen%v", k, i), func(b *testing.B) { 168// scratchBuf := proto.NewBuffer(nil) 169// b.ResetTimer() 170// for k := 0; k < b.N; k++ { 171// scratchBuf.SetBuf(raw) 172// msgBlackhole.Reset() 173// if err := scratchBuf.Unmarshal(msgBlackhole); err != nil { 174// b.Error("wrong decode", err) 175// } 176// } 177// }) 178// } 179// } 180// } 181 182// genInt32Dist generates a slice of ints that will match the size distribution of dist. 183// A size of 6 corresponds to a max length varint32, which is 10 bytes. The distribution 184// is 1-indexed. (i.e. the value at index 1 is how many 1 byte ints to create). 185func genInt32Dist(dist [7]int, count int) (dest []int32) { 186 for i := 0; i < count; i++ { 187 for k := 0; k < len(dist); k++ { 188 var num int32 189 switch k { 190 case 1: 191 num = 1<<7 - 1 192 case 2: 193 num = 1<<14 - 1 194 case 3: 195 num = 1<<21 - 1 196 case 4: 197 num = 1<<28 - 1 198 case 5: 199 num = 1<<29 - 1 200 case 6: 201 num = -1 202 } 203 for m := 0; m < dist[k]; m++ { 204 dest = append(dest, num) 205 } 206 } 207 } 208 return 209} 210 211// genUint64Dist generates a slice of ints that will match the size distribution of dist. 212// The distribution is 1-indexed. (i.e. the value at index 1 is how many 1 byte ints to create). 213func genUint64Dist(dist [11]int, count int) (dest []uint64) { 214 for i := 0; i < count; i++ { 215 for k := 0; k < len(dist); k++ { 216 var num uint64 217 switch k { 218 case 1: 219 num = 1<<7 - 1 220 case 2: 221 num = 1<<14 - 1 222 case 3: 223 num = 1<<21 - 1 224 case 4: 225 num = 1<<28 - 1 226 case 5: 227 num = 1<<35 - 1 228 case 6: 229 num = 1<<42 - 1 230 case 7: 231 num = 1<<49 - 1 232 case 8: 233 num = 1<<56 - 1 234 case 9: 235 num = 1<<63 - 1 236 case 10: 237 num = 1<<64 - 1 238 } 239 for m := 0; m < dist[k]; m++ { 240 dest = append(dest, num) 241 } 242 } 243 } 244 return 245} 246 247// BenchmarkDecodeEmpty measures the overhead of doing the minimal possible decode. 248func BenchmarkDecodeEmpty(b *testing.B) { 249 raw, err := proto.Marshal(&tpb.Message{}) 250 if err != nil { 251 b.Error("wrong encode", err) 252 } 253 b.ResetTimer() 254 for i := 0; i < b.N; i++ { 255 if err := proto.Unmarshal(raw, msgBlackhole); err != nil { 256 b.Error("wrong decode", err) 257 } 258 } 259} 260