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 34 package proto_test 35 36 import ( 37 "testing" 38 39 "github.com/gogo/protobuf/proto" 40 tpb "github.com/gogo/protobuf/proto/proto3_proto" 41 ) 42 43 var 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). 185 func 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). 213 func 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. 248 func 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