timing_test.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. // Copyright 2011 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 gob
  5. import (
  6. "bytes"
  7. "io"
  8. "os"
  9. "reflect"
  10. "runtime"
  11. "testing"
  12. )
  13. type Bench struct {
  14. A int
  15. B float64
  16. C string
  17. D []byte
  18. }
  19. func benchmarkEndToEnd(b *testing.B, ctor func() any, pipe func() (r io.Reader, w io.Writer, err error)) {
  20. b.RunParallel(func(pb *testing.PB) {
  21. r, w, err := pipe()
  22. if err != nil {
  23. b.Fatal("can't get pipe:", err)
  24. }
  25. v := ctor()
  26. enc := NewEncoder(w)
  27. dec := NewDecoder(r)
  28. for pb.Next() {
  29. if err := enc.Encode(v); err != nil {
  30. b.Fatal("encode error:", err)
  31. }
  32. if err := dec.Decode(v); err != nil {
  33. b.Fatal("decode error:", err)
  34. }
  35. }
  36. })
  37. }
  38. func BenchmarkEndToEndPipe(b *testing.B) {
  39. benchmarkEndToEnd(b, func() any {
  40. return &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)}
  41. }, func() (r io.Reader, w io.Writer, err error) {
  42. r, w, err = os.Pipe()
  43. return
  44. })
  45. }
  46. func BenchmarkEndToEndByteBuffer(b *testing.B) {
  47. benchmarkEndToEnd(b, func() any {
  48. return &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)}
  49. }, func() (r io.Reader, w io.Writer, err error) {
  50. var buf bytes.Buffer
  51. return &buf, &buf, nil
  52. })
  53. }
  54. func BenchmarkEndToEndSliceByteBuffer(b *testing.B) {
  55. benchmarkEndToEnd(b, func() any {
  56. v := &Bench{7, 3.2, "now is the time", nil}
  57. Register(v)
  58. arr := make([]any, 100)
  59. for i := range arr {
  60. arr[i] = v
  61. }
  62. return &arr
  63. }, func() (r io.Reader, w io.Writer, err error) {
  64. var buf bytes.Buffer
  65. return &buf, &buf, nil
  66. })
  67. }
  68. func TestCountEncodeMallocs(t *testing.T) {
  69. if testing.Short() {
  70. t.Skip("skipping malloc count in short mode")
  71. }
  72. if runtime.GOMAXPROCS(0) > 1 {
  73. t.Skip("skipping; GOMAXPROCS>1")
  74. }
  75. const N = 1000
  76. var buf bytes.Buffer
  77. enc := NewEncoder(&buf)
  78. bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
  79. allocs := testing.AllocsPerRun(N, func() {
  80. err := enc.Encode(bench)
  81. if err != nil {
  82. t.Fatal("encode:", err)
  83. }
  84. })
  85. if allocs != 0 {
  86. t.Fatalf("mallocs per encode of type Bench: %v; wanted 0\n", allocs)
  87. }
  88. }
  89. func TestCountDecodeMallocs(t *testing.T) {
  90. if testing.Short() {
  91. t.Skip("skipping malloc count in short mode")
  92. }
  93. if runtime.GOMAXPROCS(0) > 1 {
  94. t.Skip("skipping; GOMAXPROCS>1")
  95. }
  96. const N = 1000
  97. var buf bytes.Buffer
  98. enc := NewEncoder(&buf)
  99. bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
  100. // Fill the buffer with enough to decode
  101. testing.AllocsPerRun(N, func() {
  102. err := enc.Encode(bench)
  103. if err != nil {
  104. t.Fatal("encode:", err)
  105. }
  106. })
  107. dec := NewDecoder(&buf)
  108. allocs := testing.AllocsPerRun(N, func() {
  109. *bench = Bench{}
  110. err := dec.Decode(&bench)
  111. if err != nil {
  112. t.Fatal("decode:", err)
  113. }
  114. })
  115. if allocs != 3 {
  116. t.Fatalf("mallocs per decode of type Bench: %v; wanted 3\n", allocs)
  117. }
  118. }
  119. func benchmarkEncodeSlice(b *testing.B, a any) {
  120. b.ResetTimer()
  121. b.RunParallel(func(pb *testing.PB) {
  122. var buf bytes.Buffer
  123. enc := NewEncoder(&buf)
  124. for pb.Next() {
  125. buf.Reset()
  126. err := enc.Encode(a)
  127. if err != nil {
  128. b.Fatal(err)
  129. }
  130. }
  131. })
  132. }
  133. func BenchmarkEncodeComplex128Slice(b *testing.B) {
  134. a := make([]complex128, 1000)
  135. for i := range a {
  136. a[i] = 1.2 + 3.4i
  137. }
  138. benchmarkEncodeSlice(b, a)
  139. }
  140. func BenchmarkEncodeFloat64Slice(b *testing.B) {
  141. a := make([]float64, 1000)
  142. for i := range a {
  143. a[i] = 1.23e4
  144. }
  145. benchmarkEncodeSlice(b, a)
  146. }
  147. func BenchmarkEncodeInt32Slice(b *testing.B) {
  148. a := make([]int32, 1000)
  149. for i := range a {
  150. a[i] = int32(i * 100)
  151. }
  152. benchmarkEncodeSlice(b, a)
  153. }
  154. func BenchmarkEncodeStringSlice(b *testing.B) {
  155. a := make([]string, 1000)
  156. for i := range a {
  157. a[i] = "now is the time"
  158. }
  159. benchmarkEncodeSlice(b, a)
  160. }
  161. func BenchmarkEncodeInterfaceSlice(b *testing.B) {
  162. a := make([]any, 1000)
  163. for i := range a {
  164. a[i] = "now is the time"
  165. }
  166. benchmarkEncodeSlice(b, a)
  167. }
  168. // benchmarkBuf is a read buffer we can reset
  169. type benchmarkBuf struct {
  170. offset int
  171. data []byte
  172. }
  173. func (b *benchmarkBuf) Read(p []byte) (n int, err error) {
  174. n = copy(p, b.data[b.offset:])
  175. if n == 0 {
  176. return 0, io.EOF
  177. }
  178. b.offset += n
  179. return
  180. }
  181. func (b *benchmarkBuf) ReadByte() (c byte, err error) {
  182. if b.offset >= len(b.data) {
  183. return 0, io.EOF
  184. }
  185. c = b.data[b.offset]
  186. b.offset++
  187. return
  188. }
  189. func (b *benchmarkBuf) reset() {
  190. b.offset = 0
  191. }
  192. func benchmarkDecodeSlice(b *testing.B, a any) {
  193. var buf bytes.Buffer
  194. enc := NewEncoder(&buf)
  195. err := enc.Encode(a)
  196. if err != nil {
  197. b.Fatal(err)
  198. }
  199. ra := reflect.ValueOf(a)
  200. rt := ra.Type()
  201. b.ResetTimer()
  202. b.RunParallel(func(pb *testing.PB) {
  203. // TODO(#19025): Move per-thread allocation before ResetTimer.
  204. rp := reflect.New(rt)
  205. rp.Elem().Set(reflect.MakeSlice(rt, ra.Len(), ra.Cap()))
  206. p := rp.Interface()
  207. bbuf := benchmarkBuf{data: buf.Bytes()}
  208. for pb.Next() {
  209. bbuf.reset()
  210. dec := NewDecoder(&bbuf)
  211. err := dec.Decode(p)
  212. if err != nil {
  213. b.Fatal(err)
  214. }
  215. }
  216. })
  217. }
  218. func BenchmarkDecodeComplex128Slice(b *testing.B) {
  219. a := make([]complex128, 1000)
  220. for i := range a {
  221. a[i] = 1.2 + 3.4i
  222. }
  223. benchmarkDecodeSlice(b, a)
  224. }
  225. func BenchmarkDecodeFloat64Slice(b *testing.B) {
  226. a := make([]float64, 1000)
  227. for i := range a {
  228. a[i] = 1.23e4
  229. }
  230. benchmarkDecodeSlice(b, a)
  231. }
  232. func BenchmarkDecodeInt32Slice(b *testing.B) {
  233. a := make([]int32, 1000)
  234. for i := range a {
  235. a[i] = 1234
  236. }
  237. benchmarkDecodeSlice(b, a)
  238. }
  239. func BenchmarkDecodeStringSlice(b *testing.B) {
  240. a := make([]string, 1000)
  241. for i := range a {
  242. a[i] = "now is the time"
  243. }
  244. benchmarkDecodeSlice(b, a)
  245. }
  246. func BenchmarkDecodeStringsSlice(b *testing.B) {
  247. a := make([][]string, 1000)
  248. for i := range a {
  249. a[i] = []string{"now is the time"}
  250. }
  251. benchmarkDecodeSlice(b, a)
  252. }
  253. func BenchmarkDecodeBytesSlice(b *testing.B) {
  254. a := make([][]byte, 1000)
  255. for i := range a {
  256. a[i] = []byte("now is the time")
  257. }
  258. benchmarkDecodeSlice(b, a)
  259. }
  260. func BenchmarkDecodeInterfaceSlice(b *testing.B) {
  261. a := make([]any, 1000)
  262. for i := range a {
  263. a[i] = "now is the time"
  264. }
  265. benchmarkDecodeSlice(b, a)
  266. }
  267. func BenchmarkDecodeMap(b *testing.B) {
  268. count := 1000
  269. m := make(map[int]int, count)
  270. for i := 0; i < count; i++ {
  271. m[i] = i
  272. }
  273. var buf bytes.Buffer
  274. enc := NewEncoder(&buf)
  275. err := enc.Encode(m)
  276. if err != nil {
  277. b.Fatal(err)
  278. }
  279. bbuf := benchmarkBuf{data: buf.Bytes()}
  280. b.ResetTimer()
  281. for i := 0; i < b.N; i++ {
  282. var rm map[int]int
  283. bbuf.reset()
  284. dec := NewDecoder(&bbuf)
  285. err := dec.Decode(&rm)
  286. if err != nil {
  287. b.Fatal(i, err)
  288. }
  289. }
  290. }