github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/istructsmem/internal/utils/bytes-bench_test.go (about) 1 /* 2 * Copyright (c) 2023-present Sigma-Soft, Ltd. 3 * @author: Nikolay Nikitin 4 */ 5 6 package utils 7 8 import ( 9 "bytes" 10 "encoding/binary" 11 "testing" 12 13 "github.com/stretchr/testify/require" 14 ) 15 16 func Benchmark_BufWriteCustomTypes(b *testing.B) { 17 18 type ( 19 synType = uint64 20 usrType uint64 21 ) 22 23 const capacity = 1000 // test slices capacity 24 25 int64slice := make([]uint64, capacity) 26 for i := range int64slice { 27 int64slice[i] = uint64(2 * i) 28 } 29 30 usrSlice := make([]usrType, capacity) 31 for i := range usrSlice { 32 usrSlice[i] = usrType(2 * i) 33 } 34 35 synSlice := make([]synType, capacity) 36 for i := range synSlice { 37 synSlice[i] = synType(2 * i) 38 } 39 40 var int64bytes []byte 41 b.Run("1. SafeWriteBuf go-type", func(b *testing.B) { 42 for i := 0; i < b.N; i++ { 43 buf := bytes.NewBuffer(nil) 44 for i := range int64slice { 45 SafeWriteBuf(buf, int64slice[i]) 46 } 47 if len(int64bytes) == 0 { 48 int64bytes = buf.Bytes() 49 } 50 } 51 }) 52 53 var usrBytes []byte 54 b.Run("2. SafeWriteBuf user type", func(b *testing.B) { 55 for i := 0; i < b.N; i++ { 56 buf := bytes.NewBuffer(nil) 57 for i := range usrSlice { 58 SafeWriteBuf(buf, usrSlice[i]) 59 } 60 if len(usrBytes) == 0 { 61 usrBytes = buf.Bytes() 62 } 63 } 64 }) 65 66 var synBytes []byte 67 b.Run("3. SafeWriteBuf synonym type", func(b *testing.B) { 68 for i := 0; i < b.N; i++ { 69 buf := bytes.NewBuffer(nil) 70 for i := range synSlice { 71 SafeWriteBuf(buf, synSlice[i]) 72 } 73 if len(synBytes) == 0 { 74 synBytes = buf.Bytes() 75 } 76 } 77 }) 78 79 var castBytes []byte 80 b.Run("4. SafeWriteBuf cast user type", func(b *testing.B) { 81 for i := 0; i < b.N; i++ { 82 buf := bytes.NewBuffer(nil) 83 for i := range usrSlice { 84 SafeWriteBuf(buf, uint64(usrSlice[i])) 85 } 86 if len(castBytes) == 0 { 87 castBytes = buf.Bytes() 88 } 89 } 90 }) 91 92 require := require.New(b) 93 require.EqualValues(int64bytes, usrBytes) 94 require.EqualValues(int64bytes, synBytes) 95 require.EqualValues(int64bytes, castBytes) 96 97 var b_ []byte 98 b.Run("5. WriteUint64, no heap escapes", func(b *testing.B) { 99 for i := 0; i < b.N; i++ { 100 buf := bytes.NewBuffer(nil) 101 for i := range int64slice { 102 WriteUint64(buf, int64slice[i]) 103 } 104 if len(b_) == 0 { 105 b_ = buf.Bytes() 106 } 107 } 108 }) 109 110 require.EqualValues(int64bytes, b_) 111 } 112 113 // Writes value to bytes buffer. 114 // 115 // Deprecated. For benchmark test purposes only 116 func old_SafeWriteBuf(b *bytes.Buffer, data any) { 117 var err error 118 switch v := data.(type) { 119 case nil: 120 case []byte: 121 _, err = b.Write(v) 122 case string: 123 _, err = b.WriteString(v) 124 default: 125 err = binary.Write(b, binary.BigEndian, v) 126 } 127 if err != nil { 128 // notest: Difficult to get an error when writing to bytes.buffer 129 panic(err) 130 } 131 } 132 133 /* 134 Running tool: D:\Go\bin\go.exe test -benchmem -run=^$ -bench ^Benchmark_BufWrite$ github.com/voedger/voedger/pkg/istructsmem/internal/utils 135 136 goos: windows 137 goarch: amd64 138 pkg: github.com/voedger/voedger/pkg/istructsmem/internal/utils 139 cpu: Intel(R) Core(TM) i5-3570 CPU @ 3.40GHz 140 Benchmark_BufWrite/old_SafeWriteBuf_via_buf.Write-4 1734220 667.9 ns/op 192 B/op 18 allocs/op 141 Benchmark_BufWrite/new_SafeWriteBuf_via_Write×××-4 3469579 347.4 ns/op 144 B/op 7 allocs/op 142 Benchmark_BufWrite/naked_Write×××-4 9676279 125.8 ns/op 64 B/op 1 allocs/op 143 PASS 144 ok github.com/voedger/voedger/pkg/istructsmem/internal/utils 4.899s 145 */ 146 func Benchmark_BufWrite(b *testing.B) { 147 148 type s struct { 149 int8 150 int16 151 int32 152 int64 153 uint8 154 uint16 155 uint32 156 uint64 157 bool 158 float32 159 float64 160 } 161 162 s1 := s{-8, -16, -32, -64, 8, 16, 32, 64, true, 3.14159265358, 3.141592653589793238} 163 164 buf := bytes.NewBuffer(nil) 165 old_SafeWriteBuf(buf, s1.int8) 166 old_SafeWriteBuf(buf, s1.int16) 167 old_SafeWriteBuf(buf, s1.int32) 168 old_SafeWriteBuf(buf, s1.int64) 169 old_SafeWriteBuf(buf, s1.uint8) 170 old_SafeWriteBuf(buf, s1.uint16) 171 old_SafeWriteBuf(buf, s1.uint32) 172 old_SafeWriteBuf(buf, s1.uint64) 173 old_SafeWriteBuf(buf, s1.bool) 174 old_SafeWriteBuf(buf, s1.float32) 175 old_SafeWriteBuf(buf, s1.float64) 176 177 data := buf.Bytes() 178 179 b.Run("old SafeWriteBuf via buf.Write", func(b *testing.B) { 180 for i := 0; i < b.N; i++ { 181 buf := bytes.NewBuffer(nil) 182 old_SafeWriteBuf(buf, s1.int8) 183 old_SafeWriteBuf(buf, s1.int16) 184 old_SafeWriteBuf(buf, s1.int32) 185 old_SafeWriteBuf(buf, s1.int64) 186 old_SafeWriteBuf(buf, s1.uint8) 187 old_SafeWriteBuf(buf, s1.uint16) 188 old_SafeWriteBuf(buf, s1.uint32) 189 old_SafeWriteBuf(buf, s1.uint64) 190 old_SafeWriteBuf(buf, s1.bool) 191 old_SafeWriteBuf(buf, s1.float32) 192 old_SafeWriteBuf(buf, s1.float64) 193 194 if i == 0 { 195 require.New(b).EqualValues(data, buf.Bytes()) 196 } 197 } 198 }) 199 200 b.Run("new SafeWriteBuf via Write×××", func(b *testing.B) { 201 for i := 0; i < b.N; i++ { 202 buf := bytes.NewBuffer(nil) 203 SafeWriteBuf(buf, s1.int8) 204 SafeWriteBuf(buf, s1.int16) 205 SafeWriteBuf(buf, s1.int32) 206 SafeWriteBuf(buf, s1.int64) 207 SafeWriteBuf(buf, s1.uint8) 208 SafeWriteBuf(buf, s1.uint16) 209 SafeWriteBuf(buf, s1.uint32) 210 SafeWriteBuf(buf, s1.uint64) 211 SafeWriteBuf(buf, s1.bool) 212 SafeWriteBuf(buf, s1.float32) 213 SafeWriteBuf(buf, s1.float64) 214 215 if i == 0 { 216 require.New(b).EqualValues(data, buf.Bytes()) 217 } 218 } 219 }) 220 221 b.Run("naked Write×××", func(b *testing.B) { 222 for i := 0; i < b.N; i++ { 223 buf := bytes.NewBuffer(nil) 224 WriteInt8(buf, s1.int8) 225 WriteInt16(buf, s1.int16) 226 WriteInt32(buf, s1.int32) 227 WriteInt64(buf, s1.int64) 228 WriteByte(buf, s1.uint8) 229 WriteUint16(buf, s1.uint16) 230 WriteUint32(buf, s1.uint32) 231 WriteUint64(buf, s1.uint64) 232 WriteBool(buf, s1.bool) 233 WriteFloat32(buf, s1.float32) 234 WriteFloat64(buf, s1.float64) 235 236 if i == 0 { 237 require.New(b).EqualValues(data, buf.Bytes()) 238 } 239 } 240 }) 241 } 242 243 /* 244 Running tool: D:\Go\bin\go.exe test -benchmem -run=^$ -bench ^Benchmark_BufRead$ github.com/voedger/voedger/pkg/istructsmem/internal/utils 245 246 goos: windows 247 goarch: amd64 248 pkg: github.com/voedger/voedger/pkg/istructsmem/internal/utils 249 cpu: Intel(R) Core(TM) i5-3570 CPU @ 3.40GHz 250 Benchmark_BufRead/buf.Read-4 2714758 479.5 ns/op 128 B/op 10 allocs/op 251 Benchmark_BufRead/Read×××-4 29999174 46.52 ns/op 0 B/op 0 allocs/op 252 Benchmark_BufRead/no_err_control-4 41306666 28.52 ns/op 0 B/op 0 allocs/op 253 PASS 254 ok github.com/voedger/voedger/pkg/istructsmem/internal/utils 4.473s 255 */ 256 func Benchmark_BufRead(b *testing.B) { 257 258 type s struct { 259 a int16 260 b int32 261 c int64 262 e uint16 263 f uint32 264 g uint64 265 h byte 266 i bool 267 } 268 269 s1 := s{-1, -2, -3, 4, 5, 6, 234, true} 270 271 buf := new(bytes.Buffer) 272 SafeWriteBuf(buf, s1.a) 273 SafeWriteBuf(buf, s1.b) 274 SafeWriteBuf(buf, s1.c) 275 SafeWriteBuf(buf, s1.e) 276 SafeWriteBuf(buf, s1.f) 277 SafeWriteBuf(buf, s1.g) 278 SafeWriteBuf(buf, s1.h) 279 SafeWriteBuf(buf, s1.i) 280 281 data := buf.Bytes() 282 283 b.Run("buf.Read", func(b *testing.B) { 284 for i := 0; i < b.N; i++ { 285 s2 := s{} 286 buf := bytes.NewBuffer(data) 287 binary.Read(buf, binary.BigEndian, &s2.a) 288 binary.Read(buf, binary.BigEndian, &s2.b) 289 binary.Read(buf, binary.BigEndian, &s2.c) 290 binary.Read(buf, binary.BigEndian, &s2.e) 291 binary.Read(buf, binary.BigEndian, &s2.f) 292 binary.Read(buf, binary.BigEndian, &s2.g) 293 binary.Read(buf, binary.BigEndian, &s2.h) 294 binary.Read(buf, binary.BigEndian, &s2.i) 295 296 if i == 0 { 297 require.New(b).EqualValues(s1, s2) 298 } 299 } 300 }) 301 302 b.Run("Read×××", func(b *testing.B) { 303 for i := 0; i < b.N; i++ { 304 s2 := s{} 305 buf := bytes.NewBuffer(data) 306 s2.a, _ = ReadInt16(buf) 307 s2.b, _ = ReadInt32(buf) 308 s2.c, _ = ReadInt64(buf) 309 s2.e, _ = ReadUInt16(buf) 310 s2.f, _ = ReadUInt32(buf) 311 s2.g, _ = ReadUInt64(buf) 312 s2.h, _ = ReadByte(buf) 313 s2.i, _ = ReadBool(buf) 314 315 if i == 0 { 316 require.New(b).EqualValues(s1, s2) 317 } 318 } 319 }) 320 321 b.Run("no err control", func(b *testing.B) { 322 for i := 0; i < b.N; i++ { 323 s2 := s{} 324 buf := bytes.NewBuffer(data) 325 s2.a = int16(binary.BigEndian.Uint16(buf.Next(2))) 326 s2.b = int32(binary.BigEndian.Uint32(buf.Next(4))) 327 s2.c = int64(binary.BigEndian.Uint64(buf.Next(8))) 328 s2.e = binary.BigEndian.Uint16(buf.Next(2)) 329 s2.f = binary.BigEndian.Uint32(buf.Next(4)) 330 s2.g = binary.BigEndian.Uint64(buf.Next(8)) 331 s2.h, _ = buf.ReadByte() 332 if i, _ := buf.ReadByte(); i > 0 { 333 s2.i = true 334 } 335 336 if i == 0 { 337 require.New(b).EqualValues(s1, s2) 338 } 339 } 340 }) 341 }