decode_test.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // Copyright 2010 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package proto_test
  5. import (
  6. "fmt"
  7. "testing"
  8. "github.com/golang/protobuf/proto"
  9. tpb "github.com/golang/protobuf/proto/proto3_proto"
  10. )
  11. var msgBlackhole = new(tpb.Message)
  12. // BenchmarkVarint32ArraySmall shows the performance on an array of small int32 fields (1 and
  13. // 2 bytes long).
  14. func BenchmarkVarint32ArraySmall(b *testing.B) {
  15. for i := uint(1); i <= 10; i++ {
  16. dist := genInt32Dist([7]int{0, 3, 1}, 1<<i)
  17. raw, err := proto.Marshal(&tpb.Message{
  18. ShortKey: dist,
  19. })
  20. if err != nil {
  21. b.Error("wrong encode", err)
  22. }
  23. b.Run(fmt.Sprintf("Len%v", len(dist)), func(b *testing.B) {
  24. scratchBuf := proto.NewBuffer(nil)
  25. b.ResetTimer()
  26. for k := 0; k < b.N; k++ {
  27. scratchBuf.SetBuf(raw)
  28. msgBlackhole.Reset()
  29. if err := scratchBuf.Unmarshal(msgBlackhole); err != nil {
  30. b.Error("wrong decode", err)
  31. }
  32. }
  33. })
  34. }
  35. }
  36. // BenchmarkVarint32ArrayLarge shows the performance on an array of large int32 fields (3 and
  37. // 4 bytes long, with a small number of 1, 2, 5 and 10 byte long versions).
  38. func BenchmarkVarint32ArrayLarge(b *testing.B) {
  39. for i := uint(1); i <= 10; i++ {
  40. dist := genInt32Dist([7]int{0, 1, 2, 4, 8, 1, 1}, 1<<i)
  41. raw, err := proto.Marshal(&tpb.Message{
  42. ShortKey: dist,
  43. })
  44. if err != nil {
  45. b.Error("wrong encode", err)
  46. }
  47. b.Run(fmt.Sprintf("Len%v", len(dist)), func(b *testing.B) {
  48. scratchBuf := proto.NewBuffer(nil)
  49. b.ResetTimer()
  50. for k := 0; k < b.N; k++ {
  51. scratchBuf.SetBuf(raw)
  52. msgBlackhole.Reset()
  53. if err := scratchBuf.Unmarshal(msgBlackhole); err != nil {
  54. b.Error("wrong decode", err)
  55. }
  56. }
  57. })
  58. }
  59. }
  60. // BenchmarkVarint64ArraySmall shows the performance on an array of small int64 fields (1 and
  61. // 2 bytes long).
  62. func BenchmarkVarint64ArraySmall(b *testing.B) {
  63. for i := uint(1); i <= 10; i++ {
  64. dist := genUint64Dist([11]int{0, 3, 1}, 1<<i)
  65. raw, err := proto.Marshal(&tpb.Message{
  66. Key: dist,
  67. })
  68. if err != nil {
  69. b.Error("wrong encode", err)
  70. }
  71. b.Run(fmt.Sprintf("Len%v", len(dist)), func(b *testing.B) {
  72. scratchBuf := proto.NewBuffer(nil)
  73. b.ResetTimer()
  74. for k := 0; k < b.N; k++ {
  75. scratchBuf.SetBuf(raw)
  76. msgBlackhole.Reset()
  77. if err := scratchBuf.Unmarshal(msgBlackhole); err != nil {
  78. b.Error("wrong decode", err)
  79. }
  80. }
  81. })
  82. }
  83. }
  84. // BenchmarkVarint64ArrayLarge shows the performance on an array of large int64 fields (6, 7,
  85. // and 8 bytes long with a small number of the other sizes).
  86. func BenchmarkVarint64ArrayLarge(b *testing.B) {
  87. for i := uint(1); i <= 10; i++ {
  88. dist := genUint64Dist([11]int{0, 1, 1, 2, 4, 8, 16, 32, 16, 1, 1}, 1<<i)
  89. raw, err := proto.Marshal(&tpb.Message{
  90. Key: dist,
  91. })
  92. if err != nil {
  93. b.Error("wrong encode", err)
  94. }
  95. b.Run(fmt.Sprintf("Len%v", len(dist)), func(b *testing.B) {
  96. scratchBuf := proto.NewBuffer(nil)
  97. b.ResetTimer()
  98. for k := 0; k < b.N; k++ {
  99. scratchBuf.SetBuf(raw)
  100. msgBlackhole.Reset()
  101. if err := scratchBuf.Unmarshal(msgBlackhole); err != nil {
  102. b.Error("wrong decode", err)
  103. }
  104. }
  105. })
  106. }
  107. }
  108. // BenchmarkVarint64ArrayMixed shows the performance of lots of small messages, each
  109. // containing a small number of large (3, 4, and 5 byte) repeated int64s.
  110. func BenchmarkVarint64ArrayMixed(b *testing.B) {
  111. for i := uint(1); i <= 1<<5; i <<= 1 {
  112. dist := genUint64Dist([11]int{0, 0, 0, 4, 6, 4, 0, 0, 0, 0, 0}, int(i))
  113. // number of sub fields
  114. for k := uint(1); k <= 1<<10; k <<= 2 {
  115. msg := &tpb.Message{}
  116. for m := uint(0); m < k; m++ {
  117. msg.Children = append(msg.Children, &tpb.Message{
  118. Key: dist,
  119. })
  120. }
  121. raw, err := proto.Marshal(msg)
  122. if err != nil {
  123. b.Error("wrong encode", err)
  124. }
  125. b.Run(fmt.Sprintf("Fields%vLen%v", k, i), func(b *testing.B) {
  126. scratchBuf := proto.NewBuffer(nil)
  127. b.ResetTimer()
  128. for k := 0; k < b.N; k++ {
  129. scratchBuf.SetBuf(raw)
  130. msgBlackhole.Reset()
  131. if err := scratchBuf.Unmarshal(msgBlackhole); err != nil {
  132. b.Error("wrong decode", err)
  133. }
  134. }
  135. })
  136. }
  137. }
  138. }
  139. // genInt32Dist generates a slice of ints that will match the size distribution of dist.
  140. // A size of 6 corresponds to a max length varint32, which is 10 bytes. The distribution
  141. // is 1-indexed. (i.e. the value at index 1 is how many 1 byte ints to create).
  142. func genInt32Dist(dist [7]int, count int) (dest []int32) {
  143. for i := 0; i < count; i++ {
  144. for k := 0; k < len(dist); k++ {
  145. var num int32
  146. switch k {
  147. case 1:
  148. num = 1<<7 - 1
  149. case 2:
  150. num = 1<<14 - 1
  151. case 3:
  152. num = 1<<21 - 1
  153. case 4:
  154. num = 1<<28 - 1
  155. case 5:
  156. num = 1<<29 - 1
  157. case 6:
  158. num = -1
  159. }
  160. for m := 0; m < dist[k]; m++ {
  161. dest = append(dest, num)
  162. }
  163. }
  164. }
  165. return
  166. }
  167. // genUint64Dist generates a slice of ints that will match the size distribution of dist.
  168. // The distribution is 1-indexed. (i.e. the value at index 1 is how many 1 byte ints to create).
  169. func genUint64Dist(dist [11]int, count int) (dest []uint64) {
  170. for i := 0; i < count; i++ {
  171. for k := 0; k < len(dist); k++ {
  172. var num uint64
  173. switch k {
  174. case 1:
  175. num = 1<<7 - 1
  176. case 2:
  177. num = 1<<14 - 1
  178. case 3:
  179. num = 1<<21 - 1
  180. case 4:
  181. num = 1<<28 - 1
  182. case 5:
  183. num = 1<<35 - 1
  184. case 6:
  185. num = 1<<42 - 1
  186. case 7:
  187. num = 1<<49 - 1
  188. case 8:
  189. num = 1<<56 - 1
  190. case 9:
  191. num = 1<<63 - 1
  192. case 10:
  193. num = 1<<64 - 1
  194. }
  195. for m := 0; m < dist[k]; m++ {
  196. dest = append(dest, num)
  197. }
  198. }
  199. }
  200. return
  201. }
  202. // BenchmarkDecodeEmpty measures the overhead of doing the minimal possible decode.
  203. func BenchmarkDecodeEmpty(b *testing.B) {
  204. raw, err := proto.Marshal(&tpb.Message{})
  205. if err != nil {
  206. b.Error("wrong encode", err)
  207. }
  208. b.ResetTimer()
  209. for i := 0; i < b.N; i++ {
  210. if err := proto.Unmarshal(raw, msgBlackhole); err != nil {
  211. b.Error("wrong decode", err)
  212. }
  213. }
  214. }