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 }