github.com/lxt1045/json@v0.0.0-20231013032136-54d6b1d6e525/bench_test.go (about)

     1  package json_test
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"reflect"
     9  	"runtime"
    10  	"strings"
    11  	"testing"
    12  	"unsafe"
    13  
    14  	"github.com/bytedance/sonic"
    15  	lxt "github.com/lxt1045/json"
    16  	"github.com/lxt1045/json/testdata"
    17  	"github.com/tidwall/gjson"
    18  )
    19  
    20  func BenchmarkIndexByte(b *testing.B) {
    21  	b.Run("IndexByte", func(b *testing.B) {
    22  		b.ReportAllocs()
    23  		for i := 0; i < b.N; i++ {
    24  			str := testdata.TwitterJsonOut
    25  			n := 0
    26  			k := 0
    27  			for {
    28  				j := strings.IndexByte(str[k:], '"')
    29  				if j < 0 {
    30  					break
    31  				}
    32  				n++
    33  				k += j + 1
    34  			}
    35  			_ = n
    36  		}
    37  		b.SetBytes(int64(b.N))
    38  		b.StopTimer()
    39  	})
    40  	b.Run("for", func(b *testing.B) {
    41  		b.ReportAllocs()
    42  		str := testdata.TwitterJsonOut
    43  		for i := 0; i < b.N; i++ {
    44  			n := 0
    45  			for i := 0; i < len(str); i++ {
    46  				if str[i] == '"' {
    47  					n++
    48  				}
    49  			}
    50  			_ = n
    51  		}
    52  		b.SetBytes(int64(b.N))
    53  		b.StopTimer()
    54  	})
    55  }
    56  
    57  func AppendFileToContent(data []string, files ...string) []string {
    58  	for _, file := range files {
    59  		bs, err := ioutil.ReadFile(file)
    60  		if err != nil {
    61  			panic(err)
    62  		}
    63  		data = append(data, BytesToString(bs))
    64  	}
    65  	return data
    66  }
    67  
    68  func BenchmarkUnmarshal(b *testing.B) {
    69  	datas := AppendFileToContent(nil, "./testdata/twitter.json", "./testdata/twitterescaped.json")
    70  	for i, data := range datas {
    71  		b.Logf("i:%d,len:%d", i, len(data))
    72  		bs := StringToBytes(data)
    73  		runs := []struct {
    74  			name string
    75  			f    func()
    76  		}{
    77  			{"std-map",
    78  				func() {
    79  					var m map[string]interface{}
    80  					json.Unmarshal(bs, &m)
    81  				},
    82  			},
    83  			{"std-st",
    84  				func() {
    85  					var m testdata.Twitter
    86  					json.Unmarshal(bs, &m)
    87  				},
    88  			},
    89  			{"gjson-Parse",
    90  				func() {
    91  					gjson.Parse(data).Value()
    92  				},
    93  			},
    94  			{"lxt-map",
    95  				func() {
    96  					var m map[string]interface{}
    97  					lxt.UnmarshalString(data, &m)
    98  				},
    99  			},
   100  			{"lxt-st",
   101  				func() {
   102  					var m testdata.Twitter
   103  					lxt.UnmarshalString(data, &m)
   104  				},
   105  			},
   106  			{
   107  				"sonic-map",
   108  				func() {
   109  					var m map[string]interface{}
   110  					sonic.UnmarshalString(data, &m)
   111  				},
   112  			},
   113  			{
   114  				"sonic-st",
   115  				func() {
   116  					var m testdata.Twitter
   117  					sonic.UnmarshalString(data, &m)
   118  				},
   119  			},
   120  		}
   121  		var m testdata.Twitter
   122  		lxt.UnmarshalString(data, &m)
   123  		for _, r := range runs {
   124  			b.Run(r.name, func(b *testing.B) {
   125  				b.ReportAllocs()
   126  				for i := 0; i < b.N; i++ {
   127  					r.f()
   128  				}
   129  				b.SetBytes(int64(b.N))
   130  				b.StopTimer()
   131  			})
   132  		}
   133  	}
   134  }
   135  
   136  func BenchmarkMmarshal(b *testing.B) {
   137  	datas := AppendFileToContent(nil, "./testdata/twitter.json")
   138  	var m map[string]interface{}
   139  	data := datas[0]
   140  	bs := []byte(data)
   141  	json.Unmarshal(bs, &m)
   142  	var st testdata.Twitter
   143  	json.Unmarshal(bs, &st)
   144  	runs := []struct {
   145  		name string
   146  		f    func()
   147  	}{
   148  		{"std-map",
   149  			func() {
   150  				json.Marshal(&m)
   151  			},
   152  		},
   153  		{"std-st",
   154  			func() {
   155  				json.Marshal(&st)
   156  			},
   157  		},
   158  		{"lxt-map",
   159  			func() {
   160  				lxt.Marshal(&m)
   161  			},
   162  		},
   163  		{"lxt-st",
   164  			func() {
   165  				lxt.Marshal(&st)
   166  			},
   167  		},
   168  		{
   169  			"sonic-map",
   170  			func() {
   171  				sonic.Marshal(&m)
   172  			},
   173  		},
   174  		{
   175  			"sonic-st",
   176  			func() {
   177  				sonic.Marshal(&st)
   178  			},
   179  		},
   180  	}
   181  	for _, r := range runs {
   182  		b.Run(r.name, func(b *testing.B) {
   183  			b.ReportAllocs()
   184  			for i := 0; i < b.N; i++ {
   185  				r.f()
   186  			}
   187  			b.SetBytes(int64(b.N))
   188  			b.StopTimer()
   189  		})
   190  	}
   191  }
   192  
   193  //BytesToString ...
   194  func BytesToString(b []byte) string {
   195  	return *(*string)(unsafe.Pointer(&b))
   196  }
   197  
   198  //StringToBytes ...
   199  func StringToBytes(s string) []byte {
   200  	strH := (*reflect.StringHeader)(unsafe.Pointer(&s))
   201  	p := reflect.SliceHeader{
   202  		Data: strH.Data,
   203  		Len:  strH.Len,
   204  		Cap:  strH.Len,
   205  	}
   206  	return *(*[]byte)(unsafe.Pointer(&p))
   207  }
   208  
   209  /*
   210  go test -benchmem -run=^$ -v -benchtime=10000000x -bench ^BenchmarkUnmarshalType$ github.com/lxt1045/json -count=1
   211  
   212  go test -benchmem -run=^$ -bench ^BenchmarkUnmarshalType$ github.com/lxt1045/json -count=1 -v -cpuprofile cpu.prof -c
   213  go test -benchmem -run=^$ -bench ^BenchmarkUnmarshalType$ github.com/lxt1045/json -count=1 -v -memprofile cpu.prof -c
   214  go tool pprof ./json.test cpu.prof
   215  */
   216  
   217  func BenchmarkUnmarshalType(b *testing.B) {
   218  	type X struct {
   219  		A string
   220  		B string
   221  	}
   222  	type Y struct {
   223  		A bool
   224  		B bool
   225  	}
   226  	all := []struct {
   227  		V     interface{}
   228  		JsonV string
   229  	}{
   230  		{uint(0), `888888`},            // 0
   231  		{(*uint)(nil), `888888`},       // 1
   232  		{int8(0), `88`},                // 2
   233  		{int(0), `888888`},             // 3
   234  		{true, `true`},                 // 4
   235  		{"", `"asdfghjkl"`},            // 5
   236  		{[]int8{}, `[1,2,3]`},          // 6
   237  		{[]int{}, `[1,2,3]`},           // 7
   238  		{[]bool{}, `[true,true,true]`}, // 8
   239  		{[]string{}, `["1","2","3"]`},  // 9
   240  		{[]X{}, `[{"A":"aaaa","B":"bbbb"},{"A":"aaaa","B":"bbbb"},{"A":"aaaa","B":"bbbb"}]`},
   241  		{[]Y{}, `[{"A":true,"B":true},{"A":true,"B":true},{"A":true,"B":true}]`},
   242  		{(*int)(nil), `88`},             // 11
   243  		{(*bool)(nil), `true`},          // 12
   244  		{(*string)(nil), `"asdfghjkl"`}, // 13
   245  	}
   246  	N := 10
   247  	idxs := []int{}
   248  	// idxs = []int{10}
   249  	if len(idxs) > 0 {
   250  		get := all[:0]
   251  		for _, i := range idxs {
   252  			get = append(get, all[i])
   253  		}
   254  		all = get
   255  	}
   256  	var err error
   257  	for _, obj := range all {
   258  		builder := lxt.NewTypeBuilder()
   259  		buf := bytes.NewBufferString("{")
   260  		fieldType := reflect.TypeOf(obj.V)
   261  		for i := 0; i < N; i++ {
   262  			if i != 0 {
   263  				buf.WriteByte(',')
   264  			}
   265  			key := fmt.Sprintf("Field_%d", i)
   266  			builder.AddField(key, fieldType)
   267  			buf.WriteString(fmt.Sprintf(`"%s":%v`, key, obj.JsonV))
   268  		}
   269  		buf.WriteByte('}')
   270  		bs := buf.Bytes()
   271  		str := string(bs)
   272  
   273  		// b.Logf("json:%s", str)
   274  		typ := builder.Build()
   275  		value := reflect.New(typ).Interface()
   276  		// b.Logf("\ntype:%T\n", value)
   277  
   278  		runtime.GC()
   279  		b.Run(fmt.Sprintf("%s-%d-lxt", fieldType, N), func(b *testing.B) {
   280  			b.SetBytes(int64(len(str)))
   281  			b.ResetTimer()
   282  			for i := 0; i < b.N; i++ {
   283  				err := lxt.UnmarshalString(str, value)
   284  				if err != nil {
   285  					b.Fatal(err)
   286  				}
   287  			}
   288  		})
   289  		// continue
   290  		runtime.GC()
   291  		b.Run(fmt.Sprintf("%s-%d-sonic", fieldType, N), func(b *testing.B) {
   292  			b.SetBytes(int64(len(str)))
   293  			b.ResetTimer()
   294  			for i := 0; i < b.N; i++ {
   295  				err := sonic.UnmarshalString(str, value)
   296  				if err != nil {
   297  					b.Fatal(err)
   298  				}
   299  			}
   300  		})
   301  		// runtime.GC()
   302  		// b.Run(fmt.Sprintf("%s-%d-lxt", fieldType, N), func(b *testing.B) {
   303  		// 	for i := 0; i < b.N; i++ {
   304  		// 		err := lxt.UnmarshalString(str, value)
   305  		// 		if err != nil {
   306  		// 			b.Fatal(err)
   307  		// 		}
   308  		// 	}
   309  		// })
   310  
   311  		// continue
   312  		// runtime.GC()
   313  		// b.Run(fmt.Sprintf("%s-%d-std", fieldType, N), func(b *testing.B) {
   314  		// 	for i := 0; i < b.N; i++ {
   315  		// 		err := json.Unmarshal(bs, value)
   316  		// 		if err != nil {
   317  		// 			b.Fatal(err)
   318  		// 		}
   319  		// 	}
   320  		// })
   321  
   322  		runtime.GC()
   323  		b.Run(fmt.Sprintf("Marshal-%s-%d-lxt", fieldType, N), func(b *testing.B) {
   324  			b.SetBytes(int64(len(str)))
   325  			b.ResetTimer()
   326  			for i := 0; i < b.N; i++ {
   327  				bs, err = lxt.Marshal(value)
   328  				if err != nil {
   329  					b.Fatal(err)
   330  				}
   331  			}
   332  		})
   333  		runtime.GC()
   334  		b.Run(fmt.Sprintf("Marshal-%s-%d-sonic", fieldType, N), func(b *testing.B) {
   335  			b.SetBytes(int64(len(str)))
   336  			b.ResetTimer()
   337  			for i := 0; i < b.N; i++ {
   338  				bs, err = sonic.Marshal(value)
   339  				if err != nil {
   340  					b.Fatal(err)
   341  				}
   342  			}
   343  		})
   344  		// runtime.GC()
   345  		// b.Run(fmt.Sprintf("Marshal-%s-%d-std", fieldType, N), func(b *testing.B) {
   346  		// 	for i := 0; i < b.N; i++ {
   347  		// 		bs, err = json.Marshal(value)
   348  		// 		if err != nil {
   349  		// 			b.Fatal(err)
   350  		// 		}
   351  		// 	}
   352  		// })
   353  	}
   354  }
   355  
   356  //
   357  
   358  func BenchmarkSmallBinding(b *testing.B) {
   359  	bs := []byte(testdata.BookData)
   360  	str := string(bs)
   361  	d := testdata.Book{}
   362  	err := lxt.Unmarshal(bs, &d)
   363  	if err != nil {
   364  		b.Fatal(err)
   365  	}
   366  	sonic.UnmarshalString(str, &d)
   367  
   368  	runtime.GC()
   369  	b.Run("decode-lxt", func(b *testing.B) {
   370  		b.SetBytes(int64(len(bs)))
   371  		// b.ReportAllocs()
   372  		b.ResetTimer()
   373  		for i := 0; i < b.N; i++ {
   374  			d := testdata.Book{}
   375  			_ = lxt.UnmarshalString(str, &d)
   376  		}
   377  	})
   378  
   379  	runtime.GC()
   380  	b.Run("decode-sonic", func(b *testing.B) {
   381  		b.SetBytes(int64(len(bs)))
   382  		b.ResetTimer()
   383  		for i := 0; i < b.N; i++ {
   384  			d := testdata.Book{}
   385  			_ = sonic.UnmarshalString(str, &d)
   386  		}
   387  	})
   388  
   389  	runtime.GC()
   390  	b.Run("decode-parallel-lxt", func(b *testing.B) {
   391  		b.SetBytes(int64(len(bs)))
   392  		// b.ReportAllocs()
   393  		b.ResetTimer()
   394  		b.RunParallel(func(pb *testing.PB) {
   395  			for pb.Next() {
   396  				d := testdata.Book{}
   397  				_ = lxt.UnmarshalString(str, &d)
   398  			}
   399  		})
   400  	})
   401  
   402  	runtime.GC()
   403  	b.Run("decode-parallel-sonic", func(b *testing.B) {
   404  		b.SetBytes(int64(len(bs)))
   405  		b.ResetTimer()
   406  		b.RunParallel(func(pb *testing.PB) {
   407  			for pb.Next() {
   408  				d := testdata.Book{}
   409  				_ = sonic.UnmarshalString(str, &d)
   410  			}
   411  		})
   412  	})
   413  
   414  	// encode
   415  
   416  	runtime.GC()
   417  	b.Run("encode-lxt", func(b *testing.B) {
   418  		b.SetBytes(int64(len(bs)))
   419  		// b.ReportAllocs()
   420  		b.ResetTimer()
   421  		for i := 0; i < b.N; i++ {
   422  			_, _ = lxt.Marshal(&d)
   423  		}
   424  	})
   425  
   426  	runtime.GC()
   427  	b.Run("encode-sonic", func(b *testing.B) {
   428  		b.SetBytes(int64(len(bs)))
   429  		b.ResetTimer()
   430  		for i := 0; i < b.N; i++ {
   431  			_, _ = sonic.Marshal(&d)
   432  		}
   433  	})
   434  
   435  	runtime.GC()
   436  	b.Run("encode-parallel-lxt", func(b *testing.B) {
   437  		b.SetBytes(int64(len(bs)))
   438  		// b.ReportAllocs()
   439  		b.ResetTimer()
   440  		b.RunParallel(func(pb *testing.PB) {
   441  			for pb.Next() {
   442  				_, _ = lxt.Marshal(&d)
   443  			}
   444  		})
   445  	})
   446  
   447  	runtime.GC()
   448  	b.Run("encode-parallel-sonic", func(b *testing.B) {
   449  		b.SetBytes(int64(len(bs)))
   450  		b.ResetTimer()
   451  		b.RunParallel(func(pb *testing.PB) {
   452  			for pb.Next() {
   453  				_, _ = sonic.Marshal(&d)
   454  			}
   455  		})
   456  	})
   457  }
   458  
   459  func BenchmarkSmallGeneric(b *testing.B) {
   460  	bs := []byte(testdata.BookData)
   461  	str := string(bs)
   462  	var d interface{}
   463  	err := lxt.Unmarshal(bs, &d)
   464  	if err != nil {
   465  		b.Fatal(err)
   466  	}
   467  	sonic.UnmarshalString(str, &d)
   468  
   469  	runtime.GC()
   470  	b.Run("decode-lxt", func(b *testing.B) {
   471  		b.SetBytes(int64(len(bs)))
   472  		// b.ReportAllocs()
   473  		b.ResetTimer()
   474  		for i := 0; i < b.N; i++ {
   475  			var d interface{}
   476  			_ = lxt.UnmarshalString(str, &d)
   477  		}
   478  	})
   479  
   480  	runtime.GC()
   481  	b.Run("decode-sonic", func(b *testing.B) {
   482  		b.SetBytes(int64(len(bs)))
   483  		b.ResetTimer()
   484  		for i := 0; i < b.N; i++ {
   485  			var d interface{}
   486  			_ = sonic.UnmarshalString(str, &d)
   487  		}
   488  	})
   489  
   490  	runtime.GC()
   491  	b.Run("decode-parallel-lxt", func(b *testing.B) {
   492  		b.SetBytes(int64(len(bs)))
   493  		// b.ReportAllocs()
   494  		b.ResetTimer()
   495  		b.RunParallel(func(pb *testing.PB) {
   496  			for pb.Next() {
   497  				var d interface{}
   498  				_ = lxt.UnmarshalString(str, &d)
   499  			}
   500  		})
   501  	})
   502  
   503  	runtime.GC()
   504  	b.Run("decode-parallel-sonic", func(b *testing.B) {
   505  		b.SetBytes(int64(len(bs)))
   506  		b.ResetTimer()
   507  		b.RunParallel(func(pb *testing.PB) {
   508  			for pb.Next() {
   509  				var d interface{}
   510  				_ = sonic.UnmarshalString(str, &d)
   511  			}
   512  		})
   513  	})
   514  
   515  	// encode
   516  
   517  	runtime.GC()
   518  	b.Run("encode-lxt", func(b *testing.B) {
   519  		b.SetBytes(int64(len(bs)))
   520  		// b.ReportAllocs()
   521  		b.ResetTimer()
   522  		for i := 0; i < b.N; i++ {
   523  			_, _ = lxt.Marshal(&d)
   524  		}
   525  	})
   526  
   527  	runtime.GC()
   528  	b.Run("encode-sonic", func(b *testing.B) {
   529  		b.SetBytes(int64(len(bs)))
   530  		b.ResetTimer()
   531  		for i := 0; i < b.N; i++ {
   532  			_, _ = sonic.Marshal(&d)
   533  		}
   534  	})
   535  
   536  	runtime.GC()
   537  	b.Run("encode-parallel-lxt", func(b *testing.B) {
   538  		b.SetBytes(int64(len(bs)))
   539  		// b.ReportAllocs()
   540  		b.ResetTimer()
   541  		b.RunParallel(func(pb *testing.PB) {
   542  			for pb.Next() {
   543  				_, _ = lxt.Marshal(&d)
   544  			}
   545  		})
   546  	})
   547  
   548  	runtime.GC()
   549  	b.Run("encode-parallel-sonic", func(b *testing.B) {
   550  		b.SetBytes(int64(len(bs)))
   551  		b.ResetTimer()
   552  		b.RunParallel(func(pb *testing.PB) {
   553  			for pb.Next() {
   554  				_, _ = sonic.Marshal(&d)
   555  			}
   556  		})
   557  	})
   558  }
   559  
   560  func BenchmarkMediumBinding(b *testing.B) {
   561  	bs := []byte(testdata.TwitterJson)
   562  	str := string(bs)
   563  	d := testdata.TwitterStruct{}
   564  	err := lxt.Unmarshal(bs, &d)
   565  	if err != nil {
   566  		b.Fatal(err)
   567  	}
   568  	sonic.UnmarshalString(str, &d)
   569  
   570  	runtime.GC()
   571  	b.Run("decode-lxt", func(b *testing.B) {
   572  		b.SetBytes(int64(len(bs)))
   573  		// b.ReportAllocs()
   574  		b.ResetTimer()
   575  		for i := 0; i < b.N; i++ {
   576  			d := testdata.TwitterStruct{}
   577  			_ = lxt.UnmarshalString(str, &d)
   578  		}
   579  	})
   580  
   581  	runtime.GC()
   582  	b.Run("decode-sonic", func(b *testing.B) {
   583  		b.SetBytes(int64(len(bs)))
   584  		b.ResetTimer()
   585  		for i := 0; i < b.N; i++ {
   586  			d := testdata.TwitterStruct{}
   587  			_ = sonic.UnmarshalString(str, &d)
   588  		}
   589  	})
   590  
   591  	runtime.GC()
   592  	b.Run("decode-parallel-lxt", func(b *testing.B) {
   593  		b.SetBytes(int64(len(bs)))
   594  		// b.ReportAllocs()
   595  		b.ResetTimer()
   596  		b.RunParallel(func(pb *testing.PB) {
   597  			for pb.Next() {
   598  				d := testdata.TwitterStruct{}
   599  				_ = lxt.UnmarshalString(str, &d)
   600  			}
   601  		})
   602  	})
   603  
   604  	runtime.GC()
   605  	b.Run("decode-parallel-sonic", func(b *testing.B) {
   606  		b.SetBytes(int64(len(bs)))
   607  		b.ResetTimer()
   608  		b.RunParallel(func(pb *testing.PB) {
   609  			for pb.Next() {
   610  				d := testdata.TwitterStruct{}
   611  				_ = sonic.UnmarshalString(str, &d)
   612  			}
   613  		})
   614  	})
   615  
   616  	// encode
   617  
   618  	runtime.GC()
   619  	b.Run("encode-lxt", func(b *testing.B) {
   620  		b.SetBytes(int64(len(bs)))
   621  		// b.ReportAllocs()
   622  		b.ResetTimer()
   623  		for i := 0; i < b.N; i++ {
   624  			_, _ = lxt.Marshal(&d)
   625  		}
   626  	})
   627  
   628  	runtime.GC()
   629  	b.Run("encode-sonic", func(b *testing.B) {
   630  		b.SetBytes(int64(len(bs)))
   631  		b.ResetTimer()
   632  		for i := 0; i < b.N; i++ {
   633  			_, _ = sonic.Marshal(&d)
   634  		}
   635  	})
   636  
   637  	runtime.GC()
   638  	b.Run("encode-parallel-lxt", func(b *testing.B) {
   639  		b.SetBytes(int64(len(bs)))
   640  		// b.ReportAllocs()
   641  		b.ResetTimer()
   642  		b.RunParallel(func(pb *testing.PB) {
   643  			for pb.Next() {
   644  				_, _ = lxt.Marshal(&d)
   645  			}
   646  		})
   647  	})
   648  
   649  	runtime.GC()
   650  	b.Run("encode-parallel-sonic", func(b *testing.B) {
   651  		b.SetBytes(int64(len(bs)))
   652  		b.ResetTimer()
   653  		b.RunParallel(func(pb *testing.PB) {
   654  			for pb.Next() {
   655  				_, _ = sonic.Marshal(&d)
   656  			}
   657  		})
   658  	})
   659  }
   660  
   661  func BenchmarkMediumGeneric(b *testing.B) {
   662  	bs := []byte(testdata.TwitterJson)
   663  	str := string(bs)
   664  	var d interface{}
   665  	err := lxt.Unmarshal(bs, &d)
   666  	if err != nil {
   667  		b.Fatal(err)
   668  	}
   669  	sonic.UnmarshalString(str, &d)
   670  
   671  	runtime.GC()
   672  	b.Run("decode-lxt", func(b *testing.B) {
   673  		b.SetBytes(int64(len(bs)))
   674  		// b.ReportAllocs()
   675  		b.ResetTimer()
   676  		for i := 0; i < b.N; i++ {
   677  			var d interface{}
   678  			_ = lxt.UnmarshalString(str, &d)
   679  		}
   680  	})
   681  
   682  	runtime.GC()
   683  	b.Run("decode-sonic", func(b *testing.B) {
   684  		b.SetBytes(int64(len(bs)))
   685  		b.ResetTimer()
   686  		for i := 0; i < b.N; i++ {
   687  			var d interface{}
   688  			_ = sonic.UnmarshalString(str, &d)
   689  		}
   690  	})
   691  
   692  	runtime.GC()
   693  	b.Run("decode-parallel-lxt", func(b *testing.B) {
   694  		b.SetBytes(int64(len(bs)))
   695  		// b.ReportAllocs()
   696  		b.ResetTimer()
   697  		b.RunParallel(func(pb *testing.PB) {
   698  			for pb.Next() {
   699  				var d interface{}
   700  				_ = lxt.UnmarshalString(str, &d)
   701  			}
   702  		})
   703  	})
   704  
   705  	runtime.GC()
   706  	b.Run("decode-parallel-sonic", func(b *testing.B) {
   707  		b.SetBytes(int64(len(bs)))
   708  		b.ResetTimer()
   709  		b.RunParallel(func(pb *testing.PB) {
   710  			for pb.Next() {
   711  				var d interface{}
   712  				_ = sonic.UnmarshalString(str, &d)
   713  			}
   714  		})
   715  	})
   716  
   717  	// encode
   718  
   719  	runtime.GC()
   720  	b.Run("encode-lxt", func(b *testing.B) {
   721  		b.SetBytes(int64(len(bs)))
   722  		// b.ReportAllocs()
   723  		b.ResetTimer()
   724  		for i := 0; i < b.N; i++ {
   725  			_, _ = lxt.Marshal(&d)
   726  		}
   727  	})
   728  
   729  	runtime.GC()
   730  	b.Run("encode-sonic", func(b *testing.B) {
   731  		b.SetBytes(int64(len(bs)))
   732  		b.ResetTimer()
   733  		for i := 0; i < b.N; i++ {
   734  			_, _ = sonic.Marshal(&d)
   735  		}
   736  	})
   737  
   738  	runtime.GC()
   739  	b.Run("encode-parallel-lxt", func(b *testing.B) {
   740  		b.SetBytes(int64(len(bs)))
   741  		// b.ReportAllocs()
   742  		b.ResetTimer()
   743  		b.RunParallel(func(pb *testing.PB) {
   744  			for pb.Next() {
   745  				_, _ = lxt.Marshal(&d)
   746  			}
   747  		})
   748  	})
   749  
   750  	runtime.GC()
   751  	b.Run("encode-parallel-sonic", func(b *testing.B) {
   752  		b.SetBytes(int64(len(bs)))
   753  		b.ResetTimer()
   754  		b.RunParallel(func(pb *testing.PB) {
   755  			for pb.Next() {
   756  				_, _ = sonic.Marshal(&d)
   757  			}
   758  		})
   759  	})
   760  }
   761  
   762  func BenchmarkLargeBinding(b *testing.B) {
   763  	bs := []byte(testdata.TwitterJsonLarge)
   764  	str := string(bs)
   765  	d := testdata.TwitterStruct{}
   766  	err := lxt.Unmarshal(bs, &d)
   767  	if err != nil {
   768  		b.Fatal(err)
   769  	}
   770  	sonic.UnmarshalString(str, &d)
   771  
   772  	runtime.GC()
   773  	b.Run("decode-lxt", func(b *testing.B) {
   774  		b.SetBytes(int64(len(bs)))
   775  		// b.ReportAllocs()
   776  		b.ResetTimer()
   777  		for i := 0; i < b.N; i++ {
   778  			d := testdata.TwitterStruct{}
   779  			_ = lxt.UnmarshalString(str, &d)
   780  		}
   781  	})
   782  
   783  	runtime.GC()
   784  	b.Run("decode-sonic", func(b *testing.B) {
   785  		b.SetBytes(int64(len(bs)))
   786  		b.ResetTimer()
   787  		for i := 0; i < b.N; i++ {
   788  			d := testdata.TwitterStruct{}
   789  			_ = sonic.UnmarshalString(str, &d)
   790  		}
   791  	})
   792  
   793  	runtime.GC()
   794  	b.Run("decode-parallel-lxt", func(b *testing.B) {
   795  		b.SetBytes(int64(len(bs)))
   796  		// b.ReportAllocs()
   797  		b.ResetTimer()
   798  		b.RunParallel(func(pb *testing.PB) {
   799  			for pb.Next() {
   800  				d := testdata.TwitterStruct{}
   801  				_ = lxt.UnmarshalString(str, &d)
   802  			}
   803  		})
   804  	})
   805  
   806  	runtime.GC()
   807  	b.Run("decode-parallel-sonic", func(b *testing.B) {
   808  		b.SetBytes(int64(len(bs)))
   809  		b.ResetTimer()
   810  		b.RunParallel(func(pb *testing.PB) {
   811  			for pb.Next() {
   812  				d := testdata.TwitterStruct{}
   813  				_ = sonic.UnmarshalString(str, &d)
   814  			}
   815  		})
   816  	})
   817  
   818  	// encode
   819  
   820  	runtime.GC()
   821  	b.Run("encode-lxt", func(b *testing.B) {
   822  		b.SetBytes(int64(len(bs)))
   823  		// b.ReportAllocs()
   824  		b.ResetTimer()
   825  		for i := 0; i < b.N; i++ {
   826  			_, _ = lxt.Marshal(&d)
   827  		}
   828  	})
   829  
   830  	runtime.GC()
   831  	b.Run("encode-sonic", func(b *testing.B) {
   832  		b.SetBytes(int64(len(bs)))
   833  		b.ResetTimer()
   834  		for i := 0; i < b.N; i++ {
   835  			_, _ = sonic.Marshal(&d)
   836  		}
   837  	})
   838  
   839  	runtime.GC()
   840  	b.Run("encode-parallel-lxt", func(b *testing.B) {
   841  		b.SetBytes(int64(len(bs)))
   842  		// b.ReportAllocs()
   843  		b.ResetTimer()
   844  		b.RunParallel(func(pb *testing.PB) {
   845  			for pb.Next() {
   846  				_, _ = lxt.Marshal(&d)
   847  			}
   848  		})
   849  	})
   850  
   851  	runtime.GC()
   852  	b.Run("encode-parallel-sonic", func(b *testing.B) {
   853  		b.SetBytes(int64(len(bs)))
   854  		b.ResetTimer()
   855  		b.RunParallel(func(pb *testing.PB) {
   856  			for pb.Next() {
   857  				_, _ = sonic.Marshal(&d)
   858  			}
   859  		})
   860  	})
   861  }
   862  
   863  func BenchmarkLargeGeneric(b *testing.B) {
   864  	bs := []byte(testdata.TwitterJsonLarge)
   865  	str := string(bs)
   866  	var d interface{}
   867  	err := lxt.Unmarshal(bs, &d)
   868  	if err != nil {
   869  		b.Fatal(err)
   870  	}
   871  	sonic.UnmarshalString(str, &d)
   872  
   873  	runtime.GC()
   874  	b.Run("decode-lxt", func(b *testing.B) {
   875  		b.SetBytes(int64(len(bs)))
   876  		// b.ReportAllocs()
   877  		b.ResetTimer()
   878  		for i := 0; i < b.N; i++ {
   879  			var d interface{}
   880  			_ = lxt.UnmarshalString(str, &d)
   881  		}
   882  	})
   883  
   884  	runtime.GC()
   885  	b.Run("decode-sonic", func(b *testing.B) {
   886  		b.SetBytes(int64(len(bs)))
   887  		b.ResetTimer()
   888  		for i := 0; i < b.N; i++ {
   889  			var d interface{}
   890  			_ = sonic.UnmarshalString(str, &d)
   891  		}
   892  	})
   893  
   894  	runtime.GC()
   895  	b.Run("decode-parallel-lxt", func(b *testing.B) {
   896  		b.SetBytes(int64(len(bs)))
   897  		// b.ReportAllocs()
   898  		b.ResetTimer()
   899  		b.RunParallel(func(pb *testing.PB) {
   900  			for pb.Next() {
   901  				var d interface{}
   902  				_ = lxt.UnmarshalString(str, &d)
   903  			}
   904  		})
   905  	})
   906  
   907  	runtime.GC()
   908  	b.Run("decode-parallel-sonic", func(b *testing.B) {
   909  		b.SetBytes(int64(len(bs)))
   910  		b.ResetTimer()
   911  		b.RunParallel(func(pb *testing.PB) {
   912  			for pb.Next() {
   913  				var d interface{}
   914  				_ = sonic.UnmarshalString(str, &d)
   915  			}
   916  		})
   917  	})
   918  
   919  	// encode
   920  
   921  	runtime.GC()
   922  	b.Run("encode-lxt", func(b *testing.B) {
   923  		b.SetBytes(int64(len(bs)))
   924  		// b.ReportAllocs()
   925  		b.ResetTimer()
   926  		for i := 0; i < b.N; i++ {
   927  			_, _ = lxt.Marshal(&d)
   928  		}
   929  	})
   930  
   931  	runtime.GC()
   932  	b.Run("encode-sonic", func(b *testing.B) {
   933  		b.SetBytes(int64(len(bs)))
   934  		b.ResetTimer()
   935  		for i := 0; i < b.N; i++ {
   936  			_, _ = sonic.Marshal(&d)
   937  		}
   938  	})
   939  
   940  	runtime.GC()
   941  	b.Run("encode-parallel-lxt", func(b *testing.B) {
   942  		b.SetBytes(int64(len(bs)))
   943  		// b.ReportAllocs()
   944  		b.ResetTimer()
   945  		b.RunParallel(func(pb *testing.PB) {
   946  			for pb.Next() {
   947  				_, _ = lxt.Marshal(&d)
   948  			}
   949  		})
   950  	})
   951  
   952  	runtime.GC()
   953  	b.Run("encode-parallel-sonic", func(b *testing.B) {
   954  		b.SetBytes(int64(len(bs)))
   955  		b.ResetTimer()
   956  		b.RunParallel(func(pb *testing.PB) {
   957  			for pb.Next() {
   958  				_, _ = sonic.Marshal(&d)
   959  			}
   960  		})
   961  	})
   962  }
   963  
   964  //
   965  
   966  func BenchmarkUnmarshalInterface(b *testing.B) {
   967  
   968  	all := []struct {
   969  		V     interface{}
   970  		JsonV string
   971  	}{
   972  		{int(0), `888888`},
   973  		{true, `true`},
   974  		{"", `"asdfghjkl"`},
   975  	}
   976  	N := 10
   977  	var value = &struct {
   978  		Field_0 interface{}
   979  		Field_1 interface{}
   980  		Field_2 interface{}
   981  		Field_3 interface{}
   982  		Field_4 interface{}
   983  		Field_5 interface{}
   984  		Field_6 interface{}
   985  		Field_7 interface{}
   986  		Field_8 interface{}
   987  		Field_9 interface{}
   988  	}{}
   989  	for _, obj := range all {
   990  		buf := bytes.NewBufferString("{")
   991  		for i := 0; i < N; i++ {
   992  			if i != 0 {
   993  				buf.WriteByte(',')
   994  			}
   995  			key := fmt.Sprintf("Field_%d", i)
   996  			buf.WriteString(fmt.Sprintf(`"%s":%s`, key, obj.JsonV))
   997  		}
   998  		buf.WriteByte('}')
   999  		bs := buf.Bytes()
  1000  		str := string(bs)
  1001  		fieldType := reflect.TypeOf(obj.V)
  1002  
  1003  		b.Run(fmt.Sprintf("%s-%d-lxt", fieldType, N), func(b *testing.B) {
  1004  			for i := 0; i < b.N; i++ {
  1005  				err := lxt.UnmarshalString(str, value)
  1006  				if err != nil {
  1007  					b.Fatal(err)
  1008  				}
  1009  			}
  1010  		})
  1011  		b.Run(fmt.Sprintf("%s-%d-sonic", fieldType, N), func(b *testing.B) {
  1012  			for i := 0; i < b.N; i++ {
  1013  				err := sonic.UnmarshalString(str, value)
  1014  				if err != nil {
  1015  					b.Fatal(err)
  1016  				}
  1017  			}
  1018  		})
  1019  		b.Run(fmt.Sprintf("%s-%d-std", fieldType, N), func(b *testing.B) {
  1020  			for i := 0; i < b.N; i++ {
  1021  				err := json.Unmarshal(bs, value)
  1022  				if err != nil {
  1023  					b.Fatal(err)
  1024  				}
  1025  			}
  1026  		})
  1027  
  1028  		var err error
  1029  		b.Run(fmt.Sprintf("Marshal-%s-%d-lxt", fieldType, N), func(b *testing.B) {
  1030  			for i := 0; i < b.N; i++ {
  1031  				bs, err = lxt.Marshal(value)
  1032  				if err != nil {
  1033  					b.Fatal(err)
  1034  				}
  1035  			}
  1036  		})
  1037  		b.Run(fmt.Sprintf("Marshal-%s-%d-sonic", fieldType, N), func(b *testing.B) {
  1038  			for i := 0; i < b.N; i++ {
  1039  				bs, err = sonic.Marshal(value)
  1040  				if err != nil {
  1041  					b.Fatal(err)
  1042  				}
  1043  			}
  1044  		})
  1045  		b.Run(fmt.Sprintf("Marshal-%s-%d-std", fieldType, N), func(b *testing.B) {
  1046  			for i := 0; i < b.N; i++ {
  1047  				bs, err = json.Marshal(value)
  1048  				if err != nil {
  1049  					b.Fatal(err)
  1050  				}
  1051  			}
  1052  		})
  1053  	}
  1054  }
  1055  
  1056  func BenchmarkUnmarshalMapInterface(b *testing.B) {
  1057  	all := []struct {
  1058  		V     interface{}
  1059  		JsonV string
  1060  	}{
  1061  		{int(0), `888888`},
  1062  		{true, `true`},
  1063  		{"", `"asdfghjkl"`},
  1064  	}
  1065  	N := 10
  1066  	var value = &map[string]interface{}{}
  1067  	for _, obj := range all {
  1068  		buf := bytes.NewBufferString("{")
  1069  		for i := 0; i < N; i++ {
  1070  			if i != 0 {
  1071  				buf.WriteByte(',')
  1072  			}
  1073  			key := fmt.Sprintf("Field_%d", i)
  1074  			buf.WriteString(fmt.Sprintf(`"%s":%s`, key, obj.JsonV))
  1075  		}
  1076  		buf.WriteByte('}')
  1077  		bs := buf.Bytes()
  1078  		str := string(bs)
  1079  		fieldType := reflect.TypeOf(obj.V)
  1080  
  1081  		b.Run(fmt.Sprintf("%s-%d-lxt", fieldType, N), func(b *testing.B) {
  1082  			for i := 0; i < b.N; i++ {
  1083  				err := lxt.UnmarshalString(str, value)
  1084  				if err != nil {
  1085  					b.Fatal(err)
  1086  				}
  1087  			}
  1088  		})
  1089  		b.Run(fmt.Sprintf("%s-%d-sonic", fieldType, N), func(b *testing.B) {
  1090  			for i := 0; i < b.N; i++ {
  1091  				err := sonic.UnmarshalString(str, value)
  1092  				if err != nil {
  1093  					b.Fatal(err)
  1094  				}
  1095  			}
  1096  		})
  1097  		b.Run(fmt.Sprintf("%s-%d-std", fieldType, N), func(b *testing.B) {
  1098  			for i := 0; i < b.N; i++ {
  1099  				err := json.Unmarshal(bs, value)
  1100  				if err != nil {
  1101  					b.Fatal(err)
  1102  				}
  1103  			}
  1104  		})
  1105  
  1106  		var err error
  1107  		b.Run(fmt.Sprintf("Marshal-%s-%d-lxt", fieldType, N), func(b *testing.B) {
  1108  			for i := 0; i < b.N; i++ {
  1109  				bs, err = lxt.Marshal(value)
  1110  				if err != nil {
  1111  					b.Fatal(err)
  1112  				}
  1113  			}
  1114  		})
  1115  		b.Run(fmt.Sprintf("Marshal-%s-%d-sonic", fieldType, N), func(b *testing.B) {
  1116  			for i := 0; i < b.N; i++ {
  1117  				bs, err = sonic.Marshal(value)
  1118  				if err != nil {
  1119  					b.Fatal(err)
  1120  				}
  1121  			}
  1122  		})
  1123  		b.Run(fmt.Sprintf("Marshal-%s-%d-std", fieldType, N), func(b *testing.B) {
  1124  			for i := 0; i < b.N; i++ {
  1125  				bs, err = json.Marshal(value)
  1126  				if err != nil {
  1127  					b.Fatal(err)
  1128  				}
  1129  			}
  1130  		})
  1131  	}
  1132  }
  1133  
  1134  // TODO: slice
  1135  /*
  1136  go test -benchmem -run=^$ -bench ^BenchmarkObj$ github.com/lxt1045/json -count=1 -v -cpuprofile cpu.prof -c
  1137  go test -benchmem -run=^$ -bench ^BenchmarkObj$ github.com/lxt1045/json -count=1 -v -memprofile cpu.prof -c
  1138  go tool pprof ./json.test cpu.prof
  1139  //   */
  1140  func BenchmarkStrings(b *testing.B) {
  1141  	// str := `{"X0":["1","2","3"]}`
  1142  	// str := `{"X0":["1","2","3","2","3","2","3","2","3","2","3","2","3","2","3","2","3","2","3","2","3","2","3"],"X1":["1","2","3","2","3","2","3","2","3","2","3","2","3"],"X2":["1","2","3","2","3","2","3","2","3","2","3","2","3"],"X3":["1","2","3","2","3","2","3","2","3","2","3","2","3"],"X4":["1","2","3","2","3","2","3","2","3","2","3","2","3"],"X5":["1","2","3","2","3","2","3","2","3","2","3","2","3"],"X6":["1","2","3","2","3","2","3","2","3","2","3","2","3"],"X7":["1","2","3","2","3","2","3","2","3","2","3","2","3"],"X8":["1","2","3","2","3","2","3","2","3","2","3","2","3"],"X9":["1","2","3","2","3","2","3","2","3","2","3","2","3"]}`
  1143  	str := `{"X0":["1","2","3"],"X1":["1","2","3"],"X2":["1","2","3"],"X3":["1","2","3"],"X4":["1","2","3"],"X5":["1","2","3"],"X6":["1","2","3"],"X7":["1","2","3"],"X8":["1","2","3"],"X9":["1","2","3"]}`
  1144  	// str := `{"X0":["1","2","3","2","3","2","3","2","3","2","3","2","3","2","3","2","3","2","3","2","3","2","3","2","3","2","3","2","3","2","3"]}`
  1145  	// str := `{"X0":["1","2","3","2","3","1","2","3","2","3"]}`
  1146  	d := struct {
  1147  		X0 []string
  1148  		X1 []string
  1149  		X2 []string
  1150  		X3 []string
  1151  		X4 []string
  1152  		X5 []string
  1153  		X6 []string
  1154  		X7 []string
  1155  		X8 []string
  1156  		X9 []string
  1157  	}{}
  1158  	b.Run("lxt-strings", func(b *testing.B) {
  1159  		b.ReportAllocs()
  1160  		for i := 0; i < b.N; i++ {
  1161  			err := lxt.UnmarshalString(str, &d)
  1162  			if err != nil {
  1163  				b.Fatalf("[%d]:%v", i, err)
  1164  			}
  1165  		}
  1166  		b.StopTimer()
  1167  		b.SetBytes(int64(b.N))
  1168  	})
  1169  	// return
  1170  	b.Run("sonic-strings", func(b *testing.B) {
  1171  		b.ReportAllocs()
  1172  		for i := 0; i < b.N; i++ {
  1173  			err := sonic.UnmarshalString(str, &d)
  1174  			if err != nil {
  1175  				b.Fatalf("[%d]:%v", i, err)
  1176  			}
  1177  		}
  1178  		b.StopTimer()
  1179  		b.SetBytes(int64(b.N))
  1180  	})
  1181  }
  1182  
  1183  /*
  1184  
  1185  BenchmarkObj/lxt-obj
  1186  BenchmarkObj/lxt-obj-12         	  394314	      3049 ns/op	129330.79 MB/s	    1286 B/op	       0 allocs/op
  1187  BenchmarkObj/sonic-obj
  1188  BenchmarkObj/sonic-obj-12       	  357523	      2850 ns/op	125466.19 MB/s	       4 B/op	       0 allocs/op
  1189  */
  1190  func BenchmarkObj(b *testing.B) {
  1191  	str := `{"X0":[{"A":"1","B":"2"},{"A":"1","B":"2"},{"A":"1","B":"2"}],"X1":[{"A":"1","B":"2"},{"A":"1","B":"2"},{"A":"1","B":"2"}],"X2":[{"A":"1","B":"2"},{"A":"1","B":"2"},{"A":"1","B":"2"}],"X3":[{"A":"1","B":"2"},{"A":"1","B":"2"},{"A":"1","B":"2"}],"X4":[{"A":"1","B":"2"},{"A":"1","B":"2"},{"A":"1","B":"2"}],"X5":[{"A":"1","B":"2"},{"A":"1","B":"2"},{"A":"1","B":"2"}],"X6":[{"A":"1","B":"2"},{"A":"1","B":"2"},{"A":"1","B":"2"}],"X7":[{"A":"1","B":"2"},{"A":"1","B":"2"},{"A":"1","B":"2"}],"X8":[{"A":"1","B":"2"},{"A":"1","B":"2"},{"A":"1","B":"2"}],"X9":[{"A":"1","B":"2"},{"A":"1","B":"2"},{"A":"1","B":"2"}]}`
  1192  	// str := `{"X0":[{"A":"1","B":"2"},{"A":"1","B":"2"},{"A":"1","B":"2"}]}`
  1193  	type X struct {
  1194  		A string
  1195  		B string
  1196  		C *int
  1197  	}
  1198  	d := struct {
  1199  		X0 []X
  1200  		X1 []X
  1201  		X2 []X
  1202  		X3 []X
  1203  		X4 []X
  1204  		X5 []X
  1205  		X6 []X
  1206  		X7 []X
  1207  		X8 []X
  1208  		X9 []X
  1209  	}{}
  1210  	// err := lxt.UnmarshalString(str, &d)
  1211  	// if err != nil {
  1212  	// 	b.Fatalf("[%d]:%v", 0, err)
  1213  	// }
  1214  	// b.Logf("json:%+v", d)
  1215  	b.Run("lxt-obj", func(b *testing.B) {
  1216  		b.ReportAllocs()
  1217  		for i := 0; i < b.N; i++ {
  1218  			err := lxt.UnmarshalString(str, &d)
  1219  			if err != nil {
  1220  				b.Fatalf("[%d]:%v", i, err)
  1221  			}
  1222  		}
  1223  		b.StopTimer()
  1224  		b.SetBytes(int64(b.N))
  1225  	})
  1226  	// return
  1227  	b.Run("sonic-obj", func(b *testing.B) {
  1228  		b.ReportAllocs()
  1229  		for i := 0; i < b.N; i++ {
  1230  			err := sonic.UnmarshalString(str, &d)
  1231  			if err != nil {
  1232  				b.Fatalf("[%d]:%v", i, err)
  1233  			}
  1234  		}
  1235  		b.StopTimer()
  1236  		b.SetBytes(int64(b.N))
  1237  	})
  1238  }