perf(constants): avoid allocating a map for each Decode*() call

```
goos: linux
goarch: amd64
pkg: github.com/ucan-wg/go-varsig
cpu: 13th Gen Intel(R) Core(TM) i7-1360P
                         │    old.txt    │               new.txt                │
                         │    sec/op     │    sec/op     vs base                │
DecodeHashAlgorithm-16     145.65n ± 10%   59.62n ± 30%  -59.07% (p=0.000 n=10)
DecodePayloadEncoding-16   136.65n ± 46%   50.02n ±  5%  -63.40% (p=0.000 n=10)
geomean                     141.1n         54.60n        -61.29%

                         │  old.txt   │               new.txt               │
                         │    B/op    │    B/op     vs base                 │
DecodeHashAlgorithm-16     48.00 ± 0%   48.00 ± 0%       ~ (p=1.000 n=10) ¹
DecodePayloadEncoding-16   48.00 ± 0%   48.00 ± 0%       ~ (p=1.000 n=10) ¹
geomean                    48.00        48.00       +0.00%
¹ all samples are equal

                         │  old.txt   │               new.txt               │
                         │ allocs/op  │ allocs/op   vs base                 │
DecodeHashAlgorithm-16     1.000 ± 0%   1.000 ± 0%       ~ (p=1.000 n=10) ¹
DecodePayloadEncoding-16   1.000 ± 0%   1.000 ± 0%       ~ (p=1.000 n=10) ¹
geomean                    1.000        1.000       +0.00%
¹ all samples are equal
```
This commit is contained in:
Michael Muré
2025-07-08 15:50:59 +02:00
parent 8dcaefbf3a
commit 5cea53af26
2 changed files with 40 additions and 27 deletions

View File

@@ -12,7 +12,7 @@ import (
const Prefix = uint64(multicodec.Varsig) const Prefix = uint64(multicodec.Varsig)
// HashAlgorithm is the multicodec.Code that specifies the hash algorithm // HashAlgorithm is the multicodec.Code that specifies the hash algorithm
// that's used to reduced the signed content // that's used to reduce the signed content
type HashAlgorithm uint64 type HashAlgorithm uint64
// Constant multicodec.Code values that allow Varsig implementations to // Constant multicodec.Code values that allow Varsig implementations to
@@ -36,16 +36,15 @@ func DecodeHashAlgorithm(r *bytes.Reader) (HashAlgorithm, error) {
h := HashAlgorithm(u) h := HashAlgorithm(u)
if _, ok := map[HashAlgorithm]struct{}{ switch h {
HashAlgorithmSHA256: {}, case HashAlgorithmSHA256,
HashAlgorithmSHA384: {}, HashAlgorithmSHA384,
HashAlgorithmSHA512: {}, HashAlgorithmSHA512,
HashAlgorithmShake256: {}, HashAlgorithmShake256:
}[h]; !ok { return h, nil
default:
return HashAlgorithmUnspecified, fmt.Errorf("%w: %x", ErrUnknownHashAlgorithm, h) return HashAlgorithmUnspecified, fmt.Errorf("%w: %x", ErrUnknownHashAlgorithm, h)
} }
return h, nil
} }
// PayloadEncoding specifies the encoding of the data being (hashed and) // PayloadEncoding specifies the encoding of the data being (hashed and)
@@ -88,32 +87,30 @@ func DecodePayloadEncoding(r *bytes.Reader, vers Version) (PayloadEncoding, erro
// https://github.com/ChainAgnostic/varsig#4-payload-encoding // https://github.com/ChainAgnostic/varsig#4-payload-encoding
func decodeEncodingInfoV0(payEnc PayloadEncoding) (PayloadEncoding, error) { func decodeEncodingInfoV0(payEnc PayloadEncoding) (PayloadEncoding, error) {
if _, ok := map[PayloadEncoding]struct{}{ switch payEnc {
PayloadEncodingVerbatim: {}, case PayloadEncodingVerbatim,
PayloadEncodingDAGPB: {}, PayloadEncodingDAGPB,
PayloadEncodingDAGCBOR: {}, PayloadEncodingDAGCBOR,
PayloadEncodingDAGJSON: {}, PayloadEncodingDAGJSON,
PayloadEncodingJWT: {}, PayloadEncodingJWT,
PayloadEncodingEIP191: {}, PayloadEncodingEIP191:
}[payEnc]; !ok { return payEnc, nil
default:
return PayloadEncodingUnspecified, fmt.Errorf("%w: version=%d, encoding=%x", ErrUnsupportedPayloadEncoding, Version0, payEnc) return PayloadEncodingUnspecified, fmt.Errorf("%w: version=%d, encoding=%x", ErrUnsupportedPayloadEncoding, Version0, payEnc)
} }
return payEnc, nil
} }
// https://github.com/expede/varsig/blob/main/README.md#payload-encoding // https://github.com/expede/varsig/blob/main/README.md#payload-encoding
func decodeEncodingInfoV1(payEnc PayloadEncoding) (PayloadEncoding, error) { func decodeEncodingInfoV1(payEnc PayloadEncoding) (PayloadEncoding, error) {
if _, ok := map[PayloadEncoding]struct{}{ switch payEnc {
PayloadEncodingVerbatim: {}, case PayloadEncodingVerbatim,
PayloadEncodingDAGCBOR: {}, PayloadEncodingDAGCBOR,
PayloadEncodingDAGJSON: {}, PayloadEncodingDAGJSON,
PayloadEncodingEIP191: {}, PayloadEncodingEIP191:
}[payEnc]; !ok { return payEnc, nil
default:
return PayloadEncodingUnspecified, fmt.Errorf("%w: version=%d, encoding=%x", ErrUnsupportedPayloadEncoding, Version1, payEnc) return PayloadEncodingUnspecified, fmt.Errorf("%w: version=%d, encoding=%x", ErrUnsupportedPayloadEncoding, Version1, payEnc)
} }
return payEnc, nil
} }
// Discriminator is (usually) the multicodec.Code representing the public // Discriminator is (usually) the multicodec.Code representing the public

View File

@@ -39,6 +39,14 @@ func TestDecodeHashAlgorithm(t *testing.T) {
}) })
} }
func BenchmarkDecodeHashAlgorithm(b *testing.B) {
b.ReportAllocs()
data := []byte{0x12}
for i := 0; i < b.N; i++ {
_, _ = varsig.DecodeHashAlgorithm(bytes.NewReader(data))
}
}
func TestDecodePayloadEncoding(t *testing.T) { func TestDecodePayloadEncoding(t *testing.T) {
t.Parallel() t.Parallel()
@@ -105,3 +113,11 @@ func TestDecodePayloadEncoding(t *testing.T) {
} }
}) })
} }
func BenchmarkDecodePayloadEncoding(b *testing.B) {
b.ReportAllocs()
data := []byte{0x5f}
for i := 0; i < b.N; i++ {
_, _ = varsig.DecodePayloadEncoding(bytes.NewReader(data), varsig.Version1)
}
}