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

     1  package json
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"runtime"
     7  	"sync"
     8  	"testing"
     9  	"unsafe"
    10  )
    11  
    12  func Test_NewSlice(t *testing.T) {
    13  	top := func(in string) (p *string) {
    14  		return &in
    15  	}
    16  	type X struct {
    17  		x, y *string
    18  	}
    19  	printXs := func(xs []X) {
    20  		fmt.Printf("[ ")
    21  		for _, x := range xs {
    22  			fmt.Printf("X{x:%s,y:%s} ", *x.x, *x.y)
    23  		}
    24  		fmt.Println("]")
    25  	}
    26  
    27  	f := func() []X {
    28  		typ := UnpackEface(X{}).Type
    29  
    30  		tt := reflect.TypeOf(X{})
    31  		typ = UnpackType(tt)
    32  		p := unsafe_NewArray(typ, 1)
    33  
    34  		sh := reflect.SliceHeader{
    35  			Data: uintptr(p),
    36  			Len:  0,
    37  			Cap:  2,
    38  		}
    39  		s := *(*[]X)(unsafe.Pointer(&sh))
    40  		return s
    41  	}
    42  	s := f()
    43  	runtime.GC()
    44  	sa := append(s, X{top("1"), top("2")})
    45  	sa = append(sa, X{top("11"), top("22")})
    46  
    47  	printXs(sa)
    48  	printXs(s[:2])
    49  }
    50  
    51  func Test_CacheStruct(t *testing.T) {
    52  	b := NewTypeBuilder().
    53  		AddString("Name").
    54  		AddInt64("Age")
    55  
    56  	b.Build()
    57  	p, i := b.PInterface()
    58  	pp := UnpackEface(i).Value
    59  	fmt.Printf("typ:%T,\nvalue:%+v,\n ponter1:%d,\n ponter1:%d\n", p, i, p, pp)
    60  }
    61  
    62  func Test_CacheStructAppendField(t *testing.T) {
    63  	lazyOffsets := make([]uintptr, 0, 8)
    64  	b := NewTypeBuilder()
    65  	lazyOffsets = append(lazyOffsets, 0)
    66  	b = b.AppendString("Name", &lazyOffsets[len(lazyOffsets)-1])
    67  	lazyOffsets = append(lazyOffsets, 0)
    68  	b = b.AppendIntSlice("Slice", &lazyOffsets[len(lazyOffsets)-1])
    69  	lazyOffsets = append(lazyOffsets, 0)
    70  	b = b.AppendInt64("Age", &lazyOffsets[len(lazyOffsets)-1])
    71  	lazyOffsets = append(lazyOffsets, 0)
    72  	b = b.AppendBool("Bool", &lazyOffsets[len(lazyOffsets)-1])
    73  	lazyOffsets = append(lazyOffsets, 0)
    74  	b = b.AppendBool("Bool1", &lazyOffsets[len(lazyOffsets)-1])
    75  	lazyOffsets = append(lazyOffsets, 0)
    76  	b = b.AppendInt64("Age2", &lazyOffsets[len(lazyOffsets)-1])
    77  
    78  	b.Build()
    79  	p, i := b.PInterface()
    80  	pp := UnpackEface(i).Value
    81  	fmt.Printf("typ:%T,\nvalue:%+v,\n ponter1:%d,\n ponter1:%d,\nlazyOffsets:%+v\n",
    82  		p, i, p, pp, lazyOffsets)
    83  }
    84  
    85  var pTypeBuilderST unsafe.Pointer
    86  var ifaceTest interface{}
    87  
    88  func Benchmark_CacheStruct(b *testing.B) {
    89  	type TypeBuilderST struct {
    90  		Name string
    91  		Age  int
    92  	}
    93  	TypeBuilderSTType := reflect.TypeOf(TypeBuilderST{})
    94  
    95  	lazyOffsets := make([]uintptr, 0, 8)
    96  	builder := NewTypeBuilder()
    97  	lazyOffsets = append(lazyOffsets, 0)
    98  	builder = builder.AppendString("Name", &lazyOffsets[len(lazyOffsets)-1])
    99  	lazyOffsets = append(lazyOffsets, 0)
   100  	builder = builder.AppendIntSlice("Slice", &lazyOffsets[len(lazyOffsets)-1])
   101  	lazyOffsets = append(lazyOffsets, 0)
   102  	builder = builder.AppendInt64("Age", &lazyOffsets[len(lazyOffsets)-1])
   103  	lazyOffsets = append(lazyOffsets, 0)
   104  	builder = builder.AppendBool("Bool", &lazyOffsets[len(lazyOffsets)-1])
   105  	lazyOffsets = append(lazyOffsets, 0)
   106  	builder = builder.AppendBool("Bool1", &lazyOffsets[len(lazyOffsets)-1])
   107  	lazyOffsets = append(lazyOffsets, 0)
   108  	builder = builder.AppendInt64("Age2", &lazyOffsets[len(lazyOffsets)-1])
   109  
   110  	builder.Build()
   111  	runs := []struct {
   112  		name string
   113  		f    func()
   114  	}{
   115  		{"std.New",
   116  			func() {
   117  				pTypeBuilderST = unsafe.Pointer(new(TypeBuilderST))
   118  			},
   119  		},
   120  		{"reflect.New",
   121  			func() {
   122  				v := reflect.New(TypeBuilderSTType)
   123  				pTypeBuilderST = reflectValueToPointer(&v)
   124  			},
   125  		},
   126  		{"reflect.Interface",
   127  			func() {
   128  				ifaceTest = reflect.New(TypeBuilderSTType).Interface()
   129  			},
   130  		},
   131  		{"builder.New",
   132  			func() {
   133  				pTypeBuilderST = builder.New()
   134  			},
   135  		},
   136  		{"builder.Interface",
   137  			func() {
   138  				ifaceTest = builder.Interface()
   139  			},
   140  		},
   141  		{"builder.Build",
   142  			func() {
   143  				builder.Build()
   144  			},
   145  		},
   146  		{"builder.Build2",
   147  			func() {
   148  				builder.Type = nil
   149  				builder.Build()
   150  			},
   151  		},
   152  	}
   153  
   154  	for _, r := range runs[:] {
   155  		b.Run(r.name, func(b *testing.B) {
   156  			for i := 0; i < b.N; i++ {
   157  				r.f()
   158  			}
   159  		})
   160  	}
   161  }
   162  
   163  func Test_Map(t *testing.T) {
   164  	m := make(map[string]interface{})
   165  	var in interface{} = m
   166  	eface := UnpackEface(in)
   167  	typ := (*maptype)(unsafe.Pointer(eface.Type))
   168  	var hint int = 16
   169  	pHmap := *(**hmap)(unsafe.Pointer(&m))
   170  	B := uint8(0)
   171  	for overLoadFactor(hint, B) {
   172  		B++
   173  	}
   174  	pHmap.B = B
   175  
   176  	pHmap.buckets, _ = makeBucketArray(typ, pHmap.B, nil)
   177  
   178  	t.Logf("%+v\n", *pHmap)
   179  	t.Logf("len(m):%+v\n", len(m))
   180  }
   181  
   182  /*
   183  go test -benchmem -run=^$ -bench ^Benchmark_makeMap$ github.com/lxt1045/json -count=1 -v -cpuprofile cpu.prof -c
   184  */
   185  func Benchmark_makeMap(b *testing.B) {
   186  	b.Run("pool", func(b *testing.B) {
   187  		m := make(map[string]interface{})
   188  		var in interface{} = m
   189  		eface := UnpackEface(in)
   190  		typ := (*maptype)(unsafe.Pointer(eface.Type))
   191  		var hint int = 16
   192  		pHmap := *(**hmap)(unsafe.Pointer(&m))
   193  		B := uint8(0)
   194  		for overLoadFactor(hint, B) {
   195  			B++
   196  		}
   197  		pHmap.B = B
   198  		size := typ.typ.Size
   199  
   200  		pHmap.buckets, _ = makeBucketArray(typ, pHmap.B, nil)
   201  
   202  		poolM := sync.Pool{
   203  			New: func() any {
   204  				B := uint8(8)
   205  				buckets, _ := makeBucketArray(typ, B, nil)
   206  				nbuckets := bucketShift(B)
   207  				h := reflect.SliceHeader{
   208  					Data: uintptr(buckets),
   209  					Len:  int(nbuckets * typ.typ.Size),
   210  					Cap:  int(nbuckets * typ.typ.Size),
   211  				}
   212  				uints := *(*[]uint8)(unsafe.Pointer(&h))
   213  				return uints
   214  			},
   215  		}
   216  
   217  		nbuckets := bucketShift(pHmap.B)
   218  		l := int(nbuckets * size)
   219  
   220  		m = make(map[string]interface{})
   221  		b.ResetTimer()
   222  		for i := 0; i < b.N; i++ {
   223  			pHmap := *(**hmap)(unsafe.Pointer(&m))
   224  			pHmap.B = B
   225  
   226  			uints := poolM.Get().([]uint8)
   227  			if cap(uints) < l {
   228  				uints = poolM.New().([]uint8)
   229  			}
   230  			p := uints[:l]
   231  			if cap(uints) > 2*l {
   232  				uints = uints[l:]
   233  				poolM.Put(uints)
   234  			}
   235  			pHmap.buckets = unsafe.Pointer(&p)
   236  		}
   237  	})
   238  	b.Run("make", func(b *testing.B) {
   239  		var m map[string]interface{}
   240  		_ = m
   241  		b.ResetTimer()
   242  		for i := 0; i < b.N; i++ {
   243  			m = make(map[string]interface{}, 16)
   244  		}
   245  	})
   246  }