encoding/asn1: optimize asn1.Unmarshal

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>
This commit is contained in:
Dmitrii Okunev 2019-12-31 20:39:14 +00:00 committed by Filippo Valsorda
parent d4957122ee
commit d361691201
2 changed files with 45 additions and 33 deletions

View 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)
*v, err = parseUTCTime(innerBytes)
return
}
if err1 == nil {
v.Set(reflect.ValueOf(time))
}
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

View 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)
}
}
}