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 }