]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/asn1: optimize asn1.Unmarshal
authorDmitrii Okunev <xaionaro@gmail.com>
Tue, 31 Dec 2019 20:39:14 +0000 (20:39 +0000)
committerFilippo Valsorda <filippo@golang.org>
Mon, 9 Nov 2020 21:36:24 +0000 (21:36 +0000)
Used type-switch instead of switch by reflect.Type and added
BenchmarkUnmarshal.

name         old time/op    new time/op    delta
Marshal-8      28.1µs ± 2%    27.9µs ± 1%     ~     (p=0.094 n=9+9)
Unmarshal-8    6.45µs ± 1%    5.83µs ± 4%   -9.59%  (p=0.000 n=10+10)

name         old alloc/op   new alloc/op   delta
Marshal-8      8.26kB ± 0%    8.26kB ± 0%     ~     (all equal)
Unmarshal-8      840B ± 0%      488B ± 0%  -41.90%  (p=0.000 n=10+10)

name         old allocs/op  new allocs/op  delta
Marshal-8         363 ± 0%       363 ± 0%     ~     (all equal)
Unmarshal-8      50.0 ± 0%      43.0 ± 0%  -14.00%  (p=0.000 n=10+10)

Change-Id: I6b53833c7a3e2524f025453311841d03c1256a45
GitHub-Pull-Request: golang/go#36341
Reviewed-on: https://go-review.googlesource.com/c/go/+/268557
Trust: Filippo Valsorda <filippo@golang.org>
Trust: Roland Shoemaker <roland@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
src/encoding/asn1/asn1.go
src/encoding/asn1/marshal_test.go

index 068594e2a1006cfe20217a680765e2783eef2052..7c260b49d90125f209984ce6c5fa1cb30ccd78ca 100644 (file)
@@ -851,53 +851,37 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
        offset += t.length
 
        // We deal with the structures defined in this package first.
-       switch fieldType {
-       case rawValueType:
-               result := RawValue{t.class, t.tag, t.isCompound, innerBytes, bytes[initOffset:offset]}
-               v.Set(reflect.ValueOf(result))
+       switch v := v.Addr().Interface().(type) {
+       case *RawValue:
+               *v = RawValue{t.class, t.tag, t.isCompound, innerBytes, bytes[initOffset:offset]}
                return
-       case objectIdentifierType:
-               newSlice, err1 := parseObjectIdentifier(innerBytes)
-               v.Set(reflect.MakeSlice(v.Type(), len(newSlice), len(newSlice)))
-               if err1 == nil {
-                       reflect.Copy(v, reflect.ValueOf(newSlice))
-               }
-               err = err1
+       case *ObjectIdentifier:
+               *v, err = parseObjectIdentifier(innerBytes)
                return
-       case bitStringType:
-               bs, err1 := parseBitString(innerBytes)
-               if err1 == nil {
-                       v.Set(reflect.ValueOf(bs))
-               }
-               err = err1
+       case *BitString:
+               *v, err = parseBitString(innerBytes)
                return
-       case timeType:
-               var time time.Time
-               var err1 error
+       case *time.Time:
                if universalTag == TagUTCTime {
-                       time, err1 = parseUTCTime(innerBytes)
-               } else {
-                       time, err1 = parseGeneralizedTime(innerBytes)
-               }
-               if err1 == nil {
-                       v.Set(reflect.ValueOf(time))
+                       *v, err = parseUTCTime(innerBytes)
+                       return
                }
-               err = err1
+               *v, err = parseGeneralizedTime(innerBytes)
                return
-       case enumeratedType:
+       case *Enumerated:
                parsedInt, err1 := parseInt32(innerBytes)
                if err1 == nil {
-                       v.SetInt(int64(parsedInt))
+                       *v = Enumerated(parsedInt)
                }
                err = err1
                return
-       case flagType:
-               v.SetBool(true)
+       case *Flag:
+               *v = true
                return
-       case bigIntType:
+       case **big.Int:
                parsedInt, err1 := parseBigInt(innerBytes)
                if err1 == nil {
-                       v.Set(reflect.ValueOf(parsedInt))
+                       *v = parsedInt
                }
                err = err1
                return
index 529052285f595059f16b955a285a3210e3b342b1..e3a7d8ff007a3452082ee9e4c977ea5b9d4627b8 100644 (file)
@@ -376,3 +376,31 @@ func TestSetEncoderSETSliceSuffix(t *testing.T) {
                t.Errorf("Unexpected SET content. got: %s, want: %s", resultSet, expectedOrder)
        }
 }
+
+func BenchmarkUnmarshal(b *testing.B) {
+       b.ReportAllocs()
+
+       type testCase struct {
+               in  []byte
+               out interface{}
+       }
+       var testData []testCase
+       for _, test := range unmarshalTestData {
+               pv := reflect.New(reflect.TypeOf(test.out).Elem())
+               inCopy := make([]byte, len(test.in))
+               copy(inCopy, test.in)
+               outCopy := pv.Interface()
+
+               testData = append(testData, testCase{
+                       in:  inCopy,
+                       out: outCopy,
+               })
+       }
+
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               for _, testCase := range testData {
+                       _, _ = Unmarshal(testCase.in, testCase.out)
+               }
+       }
+}