multiformats / go-multihash

Multihash implementation in Go
MIT License
239 stars 57 forks source link

perf: outline logic in Decode to allow for stack allocations #174

Closed Jorropo closed 1 year ago

Jorropo commented 1 year ago

I took extra efforts for this to be a backward compatible change, I think DecodedMultihash should return a value struct not a pointer.

I also updated the error type to a value because this allows for 1 instead of 2 allocations when erroring.

name       old time/op    new time/op    delta
Decode-12     102ns ± 3%      18ns ± 3%   -82.47%  (p=0.000 n=9+9)

name       old alloc/op   new alloc/op   delta
Decode-12     64.0B ± 0%      0.0B       -100.00%  (p=0.000 n=10+10)

name       old allocs/op  new allocs/op  delta
Decode-12      1.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)

I originally found this problem by benchmarking go-cid:

github.com/ipfs/go-cid.CidFromBytes

/home/hugo/go/pkg/mod/github.com/ipfs/go-cid@v0.4.0/cid.go

  Total:      4.64GB    10.75GB (flat, cum)   100%
    638            .          .             if len(data) > 2 && data[0] == mh.SHA2_256 && data[1] == 32 {
    639            .          .                 if len(data) < 34 {
    640            .          .                     return 0, Undef, ErrInvalidCid{fmt.Errorf("not enough bytes for cid v0")}
    641            .          .                 }
    642            .          .
    643            .     6.11GB                 h, err := mh.Cast(data[:34])
                                                               _, err := Decode(buf)                                        multihash.go:215

    644            .          .                 if err != nil {
    645            .          .                     return 0, Undef, ErrInvalidCid{err}
    646            .          .                 }

We can see it call mh.Cast and mh.Cast call Decode and instantly drops the DecodedMultihash. The point of this is purely to validate the multihash.

github-actions[bot] commented 1 year ago

Suggested version: v0.2.3

Comparing to: v0.2.2 (diff)

Changes in go.mod file(s):

(empty)

gorelease says:

# summary
Suggested version: v0.2.3

gocompat says:

Your branch is up to date with 'origin/master'.

Cutting a Release (and modifying non-markdown files)

This PR is modifying both version.json and non-markdown files. The Release Checker is not able to analyse files that are not checked in to master. This might cause the above analysis to be inaccurate. Please consider performing all the code changes in a separate PR before cutting the release.

Automatically created GitHub Release

A draft GitHub Release has been created. It is going to be published when this PR is merged. You can modify its' body to include any release notes you wish to include with the release.