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  }