github.com/cloudwego/dynamicgo@v0.2.6-0.20240519101509-707f41b6b834/thrift/generic/bench_test.go (about)

     1  /**
     2   * Copyright 2023 CloudWeGo Authors.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package generic
    18  
    19  import (
    20  	"os"
    21  	"runtime"
    22  	"runtime/debug"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/cloudwego/dynamicgo/testdata/kitex_gen/example2"
    27  	"github.com/cloudwego/dynamicgo/thrift"
    28  	"github.com/stretchr/testify/require"
    29  )
    30  
    31  var (
    32  	debugAsyncGC = os.Getenv("SONIC_NO_ASYNC_GC") == ""
    33  )
    34  
    35  func TestMain(m *testing.M) {
    36  	go func() {
    37  		if !debugAsyncGC {
    38  			return
    39  		}
    40  		println("Begin GC looping...")
    41  		for {
    42  			runtime.GC()
    43  			debug.FreeOSMemory()
    44  		}
    45  	}()
    46  	time.Sleep(time.Millisecond)
    47  	m.Run()
    48  }
    49  
    50  func BenchmarkSetOne_DynamicGo(b *testing.B) {
    51  	desc := getExampleDesc()
    52  	data := getExampleData()
    53  	v := NewValue(desc, data)
    54  	d := desc.Struct().FieldByKey("Base").Type().Struct().FieldByKey("Extra").Type().Elem()
    55  	p := thrift.NewBinaryProtocolBuffer()
    56  	exp := "中文"
    57  	p.WriteString(exp)
    58  	buf := p.Buf
    59  	vv := NewValue(d, buf)
    60  	ps := []Path{NewPathFieldName("Base"), NewPathFieldName("Extra"), NewPathStrKey("b")}
    61  	_, err2 := v.SetByPath(vv, ps...)
    62  	require.Nil(b, err2)
    63  	s2 := v.GetByPath(ps...)
    64  	require.Empty(b, s2.Error())
    65  	f2, _ := s2.String()
    66  	require.Equal(b, exp, f2)
    67  
    68  	b.Run("native", func(b *testing.B) {
    69  		old := UseNativeSkipForGet
    70  		UseNativeSkipForGet = true
    71  		b.ResetTimer()
    72  		for i := 0; i < b.N; i++ {
    73  			_, _ = v.SetByPath(vv, ps...)
    74  		}
    75  		UseNativeSkipForGet = old
    76  	})
    77  
    78  	b.Run("go", func(b *testing.B) {
    79  		old := UseNativeSkipForGet
    80  		UseNativeSkipForGet = false
    81  		b.ResetTimer()
    82  		for i := 0; i < b.N; i++ {
    83  			_, _ = v.SetByPath(vv, ps...)
    84  		}
    85  		UseNativeSkipForGet = old
    86  	})
    87  }
    88  
    89  func BenchmarkSetMany_DynamicGo(b *testing.B) {
    90  	desc := getExampleDesc()
    91  	data := getExampleData()
    92  	d1 := desc.Struct().FieldByKey("Msg").Type()
    93  	d2 := desc.Struct().FieldByKey("Subfix").Type()
    94  	v := NewValue(desc, data)
    95  	p := thrift.NewBinaryProtocolBuffer()
    96  
    97  	e1 := "test1"
    98  	p.WriteString(e1)
    99  	v1 := NewValue(d1, []byte(string(p.Buf)))
   100  	p.Buf = p.Buf[:0]
   101  	e2 := float64(-255.0001)
   102  	p.WriteDouble(e2)
   103  	v2 := NewValue(d2, []byte(string(p.Buf)))
   104  	p.Buf = p.Buf[:0]
   105  	v3 := v.GetByPath(NewPathFieldName("Base"))
   106  	ps := []PathNode{
   107  		{
   108  			Path: NewPathFieldId(1),
   109  			Node: v1.Node,
   110  		},
   111  		{
   112  			Path: NewPathFieldId(32767),
   113  			Node: v2.Node,
   114  		},
   115  		{
   116  			Path: NewPathFieldId(255),
   117  			Node: v3.Node,
   118  		},
   119  	}
   120  	opts := &Options{
   121  		UseNativeSkip: true,
   122  	}
   123  	err := v.SetMany(ps, opts)
   124  	require.Nil(b, err)
   125  	exp := example2.NewExampleReq()
   126  	if _, err := exp.FastRead(v.Raw()); err != nil {
   127  		b.Fatal(err)
   128  	}
   129  
   130  	b.Run("native", func(b *testing.B) {
   131  		opts := &Options{
   132  			UseNativeSkip: true,
   133  		}
   134  		b.ResetTimer()
   135  		for i := 0; i < b.N; i++ {
   136  			_ = v.SetMany(ps, opts)
   137  		}
   138  	})
   139  
   140  	b.Run("go", func(b *testing.B) {
   141  		opts := &Options{}
   142  		b.ResetTimer()
   143  		for i := 0; i < b.N; i++ {
   144  			_ = v.SetMany(ps, opts)
   145  		}
   146  	})
   147  }
   148  
   149  func BenchmarkGetOne_DynamicGo(b *testing.B) {
   150  	desc := getExampleDesc()
   151  	data := getExampleData()
   152  	v := NewValue(desc, data)
   153  	vv, err := v.FieldByName("Base").FieldByName("Extra").GetByStr("c").String()
   154  	require.Nil(b, err)
   155  	require.Equal(b, "C", vv)
   156  	vv, err = v.Field(255).Field(6).GetByStr("c").String()
   157  	require.Nil(b, err)
   158  	require.Equal(b, "C", vv)
   159  	vv, err = v.GetByPath(NewPathFieldName("Base"), NewPathFieldName("Extra"), NewPathStrKey("c")).String()
   160  	require.Nil(b, err)
   161  	require.Equal(b, "C", vv)
   162  	b.Run("ByName/native", func(b *testing.B) {
   163  		old := UseNativeSkipForGet
   164  		UseNativeSkipForGet = true
   165  		b.ResetTimer()
   166  		for i := 0; i < b.N; i++ {
   167  			_, _ = v.FieldByName("Base").FieldByName("Extra").GetByStr("c").String()
   168  		}
   169  		UseNativeSkipForGet = old
   170  	})
   171  	b.Run("ByName/go", func(b *testing.B) {
   172  		old := UseNativeSkipForGet
   173  		UseNativeSkipForGet = false
   174  		b.ResetTimer()
   175  		for i := 0; i < b.N; i++ {
   176  			_, _ = v.FieldByName("Base").FieldByName("Extra").GetByStr("c").String()
   177  		}
   178  		UseNativeSkipForGet = old
   179  	})
   180  	b.Run("ById/native", func(b *testing.B) {
   181  		old := UseNativeSkipForGet
   182  		UseNativeSkipForGet = true
   183  		b.ResetTimer()
   184  		for i := 0; i < b.N; i++ {
   185  			_, _ = v.Field(255).Field(6).GetByStr("c").String()
   186  		}
   187  		UseNativeSkipForGet = old
   188  	})
   189  	b.Run("ById/go", func(b *testing.B) {
   190  		old := UseNativeSkipForGet
   191  		UseNativeSkipForGet = false
   192  		b.ResetTimer()
   193  		for i := 0; i < b.N; i++ {
   194  			_, _ = v.Field(255).Field(6).GetByStr("c").String()
   195  		}
   196  		UseNativeSkipForGet = old
   197  	})
   198  	b.Run("ByPath/native", func(b *testing.B) {
   199  		old := UseNativeSkipForGet
   200  		UseNativeSkipForGet = true
   201  		b.ResetTimer()
   202  		for i := 0; i < b.N; i++ {
   203  			_, _ = v.GetByPath(NewPathFieldName("Base"), NewPathFieldName("Extra"), NewPathStrKey("c")).String()
   204  		}
   205  		UseNativeSkipForGet = old
   206  	})
   207  	b.Run("ByPath/go", func(b *testing.B) {
   208  		old := UseNativeSkipForGet
   209  		UseNativeSkipForGet = false
   210  		b.ResetTimer()
   211  		for i := 0; i < b.N; i++ {
   212  			_, _ = v.GetByPath(NewPathFieldName("Base"), NewPathFieldName("Extra"), NewPathStrKey("c")).String()
   213  		}
   214  		UseNativeSkipForGet = old
   215  	})
   216  }
   217  
   218  func BenchmarkGetMany_DynamicGo(b *testing.B) {
   219  	desc := getExampleDesc()
   220  	data := getExampleData()
   221  	v := NewValue(desc, data)
   222  
   223  	b.Run("ByName/native", func(b *testing.B) {
   224  		tree := GetSampleTree(v)
   225  		opts := Options{
   226  			UseNativeSkip: true,
   227  		}
   228  		if err := tree.Assgin(true, &opts); err != nil {
   229  			b.Fatal(err)
   230  		}
   231  		b.ResetTimer()
   232  		for i := 0; i < b.N; i++ {
   233  			_ = tree.Assgin(true, &opts)
   234  		}
   235  	})
   236  	b.Run("ByName/go", func(b *testing.B) {
   237  		tree := GetSampleTree(v)
   238  		opts := Options{
   239  			UseNativeSkip: false,
   240  		}
   241  		if err := tree.Assgin(true, &opts); err != nil {
   242  			b.Fatal(err)
   243  		}
   244  		b.ResetTimer()
   245  		for i := 0; i < b.N; i++ {
   246  			_ = tree.Assgin(true, &opts)
   247  		}
   248  	})
   249  
   250  	b.Run("ById/native", func(b *testing.B) {
   251  		tree := GetSampleTreeById(v)
   252  		opts := Options{
   253  			UseNativeSkip: true,
   254  		}
   255  		if err := tree.Assgin(true, &opts); err != nil {
   256  			b.Fatal(err)
   257  		}
   258  		b.ResetTimer()
   259  		for i := 0; i < b.N; i++ {
   260  			_ = tree.Assgin(true, &opts)
   261  		}
   262  	})
   263  	b.Run("ById/go", func(b *testing.B) {
   264  		tree := GetSampleTreeById(v)
   265  		opts := Options{
   266  			UseNativeSkip: false,
   267  		}
   268  		if err := tree.Assgin(true, &opts); err != nil {
   269  			b.Fatal(err)
   270  		}
   271  		b.ResetTimer()
   272  		for i := 0; i < b.N; i++ {
   273  			_ = tree.Assgin(true, &opts)
   274  		}
   275  	})
   276  }
   277  
   278  func BenchmarkUnmarshalAll_KitexFast(b *testing.B) {
   279  	data := getExampleData()
   280  	exp := example2.NewExampleReq()
   281  
   282  	b.ResetTimer()
   283  	for i := 0; i < b.N; i++ {
   284  		_, _ = exp.FastRead(data)
   285  		_ = exp.Base.Client
   286  	}
   287  }
   288  
   289  func BenchmarkMarshalMany_DynamicGo(b *testing.B) {
   290  	desc := getExampleDesc()
   291  	data := getExampleData()
   292  	v := NewValue(desc, data)
   293  
   294  	b.Run("ByName", func(b *testing.B) {
   295  		tree := GetSampleTree(v)
   296  		opts := Options{}
   297  		if err := tree.Assgin(true, &opts); err != nil {
   298  			b.Fatal(err)
   299  		}
   300  		_, err := tree.Marshal(&opts)
   301  		if err != nil {
   302  			b.Fatal(err)
   303  		}
   304  		// b.SetBytes(int64(len(out)))
   305  		b.ResetTimer()
   306  		for i := 0; i < b.N; i++ {
   307  			_, _ = tree.Marshal(&opts)
   308  		}
   309  	})
   310  
   311  	b.Run("ById", func(b *testing.B) {
   312  		tree := GetSampleTreeById(v)
   313  		opts := Options{}
   314  		if err := tree.Assgin(true, &opts); err != nil {
   315  			b.Fatal(err)
   316  		}
   317  		_, err := tree.Marshal(&opts)
   318  		if err != nil {
   319  			b.Fatal(err)
   320  		}
   321  		// b.SetBytes(int64(len(out)))
   322  		b.ResetTimer()
   323  		for i := 0; i < b.N; i++ {
   324  			_, _ = tree.Marshal(&opts)
   325  		}
   326  	})
   327  }
   328  
   329  func BenchmarkMarshalTo_DynamicGo(b *testing.B) {
   330  	desc := getExampleDesc()
   331  	data := getExampleData()
   332  	partial := getExamplePartialDesc()
   333  
   334  	exp := example2.NewExampleReq()
   335  	v := NewValue(desc, data)
   336  	_, err := exp.FastRead(data)
   337  	require.Nil(b, err)
   338  	opts := Options{
   339  		WriteDefault: true,
   340  	}
   341  	_, err = v.MarshalTo(partial, &opts)
   342  	require.Nil(b, err)
   343  
   344  	b.Run("native", func(b *testing.B) {
   345  		opts := Options{
   346  			WriteDefault:  true,
   347  			UseNativeSkip: true,
   348  		}
   349  		b.ResetTimer()
   350  		for i := 0; i < b.N; i++ {
   351  			_, _ = v.MarshalTo(partial, &opts)
   352  		}
   353  	})
   354  
   355  	b.Run("go", func(b *testing.B) {
   356  		opts := Options{
   357  			WriteDefault: true,
   358  		}
   359  		b.ResetTimer()
   360  		for i := 0; i < b.N; i++ {
   361  			_, _ = v.MarshalTo(partial, &opts)
   362  		}
   363  	})
   364  
   365  	// b.Run("ByName/native", func(b *testing.B) {
   366  	// 	opts := Options{
   367  	// 		FieldByName:   true,
   368  	// 		UseNativeSkip: true,
   369  	// 	}
   370  	// 	b.ResetTimer()
   371  	// 	for i := 0; i < b.N; i++ {
   372  	// 		_, _ = v.MarshalTo(partial, &opts)
   373  	// 	}
   374  	// })
   375  
   376  	// b.Run("ByName/go", func(b *testing.B) {
   377  	// 	opts := Options{
   378  	// 		FieldByName: true,
   379  	// 	}
   380  	// 	b.ResetTimer()
   381  	// 	for i := 0; i < b.N; i++ {
   382  	// 		_, _ = v.MarshalTo(partial, &opts)
   383  	// 	}
   384  	// })
   385  }
   386  
   387  func BenchmarkMarshalAll_KitexFast(b *testing.B) {
   388  	desc := getExampleDesc()
   389  	data := getExampleData()
   390  	v := NewValue(desc, data)
   391  	tree := GetSampleTreeById(v)
   392  	opts := Options{}
   393  	if err := tree.Assgin(true, &opts); err != nil {
   394  		b.Fatal(err)
   395  	}
   396  	_, err := tree.Marshal(&opts)
   397  	if err != nil {
   398  		b.Fatal(err)
   399  	}
   400  
   401  	exp := example2.NewExampleReq()
   402  	_, err = exp.FastRead(data)
   403  	require.Nil(b, err)
   404  	buf := make([]byte, exp.BLength())
   405  	if exp.FastWriteNocopy(buf, nil) <= 0 {
   406  		b.Fatal(buf)
   407  	}
   408  
   409  	b.ResetTimer()
   410  	for i := 0; i < b.N; i++ {
   411  		buf := make([]byte, exp.BLength())
   412  		_ = exp.FastWriteNocopy(buf, nil)
   413  	}
   414  }
   415  
   416  func BenchmarkGetAll_DynamicGo(b *testing.B) {
   417  	desc := getExampleDesc()
   418  	data := getExampleData()
   419  	v := NewValue(desc, data)
   420  	opts := Options{}
   421  	children := make([]PathNode, 0, DefaultNodeSliceCap)
   422  	p := PathNode{
   423  		Node: v.Node,
   424  		Next: children,
   425  	}
   426  	err := v.Children(&children, false, &opts)
   427  	require.Nil(b, err)
   428  
   429  	b.Run("skip/native", func(b *testing.B) {
   430  		opts := Options{
   431  			UseNativeSkip: true,
   432  		}
   433  		b.ResetTimer()
   434  		for i := 0; i < b.N; i++ {
   435  			p.ResetValue()
   436  			err = v.Children(&p.Next, false, &opts)
   437  			if err != nil {
   438  				b.Fatal(err)
   439  			}
   440  		}
   441  	})
   442  
   443  	b.Run("skip/go", func(b *testing.B) {
   444  		opts := Options{}
   445  		b.ResetTimer()
   446  		for i := 0; i < b.N; i++ {
   447  			p.ResetValue()
   448  			_ = v.Children(&p.Next, false, &opts)
   449  		}
   450  	})
   451  
   452  	b.Run("load_all/native", func(b *testing.B) {
   453  		opts := Options{
   454  			UseNativeSkip: true,
   455  		}
   456  		b.ResetTimer()
   457  		for i := 0; i < b.N; i++ {
   458  			p.ResetValue()
   459  			_ = v.Children(&p.Next, true, &opts)
   460  		}
   461  	})
   462  
   463  	b.Run("load_all/go", func(b *testing.B) {
   464  		opts := Options{}
   465  		b.ResetTimer()
   466  		for i := 0; i < b.N; i++ {
   467  			p.ResetValue()
   468  			_ = v.Children(&p.Next, true, &opts)
   469  		}
   470  	})
   471  
   472  	b.Run("only_struct/native", func(b *testing.B) {
   473  		opts := Options{
   474  			UseNativeSkip: true,
   475  			// OnlyScanStruct: true,
   476  		}
   477  		b.ResetTimer()
   478  		for i := 0; i < b.N; i++ {
   479  			p.ResetValue()
   480  			_ = v.Children(&p.Next, true, &opts)
   481  		}
   482  	})
   483  
   484  	b.Run("only_struct/go", func(b *testing.B) {
   485  		opts := Options{
   486  			// OnlyScanStruct: true,
   487  		}
   488  		b.ResetTimer()
   489  		for i := 0; i < b.N; i++ {
   490  			p.ResetValue()
   491  			_ = v.Children(&p.Next, true, &opts)
   492  		}
   493  	})
   494  }