Compare commits

...

4 Commits

Author SHA1 Message Date
Alex
32aa7389ca Upgrade module requirements 2022-01-05 10:40:05 +11:00
web3-bot
dc3bb41324 sync: update CI config files (#136)
* add version.json file

* update .github/workflows/go-test.yml

* update .github/workflows/go-check.yml

* add .github/workflows/releaser.yml

* add .github/workflows/release-check.yml

* add .github/workflows/tagpush.yml

Co-authored-by: web3-bot <web3-bot@users.noreply.github.com>
2021-12-13 12:26:14 +01:00
Masih H. Derkani
28f4a5eab6 Benchmark existing ways to check for IDENTITY CIDs
Add benchmarks that compare two ways of checking for
`multihash.IDENTITY` code:
1. `Cid.Prefix().MhType`
2. Decode of `Cid.Hash()`

This benchmark illustrates that using Cid.Prefix is more efficient than
`multihash.Decode`. Users wishing to perform such a check should use
`Cid.Prefix`.

Consider that `Cid.Prefix` is already efficient enough and introducing a
dedicated API for performing this check will likely result in small
gains.

Relates to #133
2021-11-08 14:52:45 +00:00
Daniel Martí
5640b0169f avoid double alloc in NewCidV1
We allocate once via "make([]byte, len)",
and again when that buffer is converted to a string.

Thankfully, since Go 1.10 we have strings.Builder,
designed specifically for this use case.

In a downstream benchmark in go-car,
which needs to reconstruct many CID values,
we see small but nice gains:

    name           old time/op    new time/op    delta
    ReadBlocks-16    1.09ms ± 4%    1.06ms ± 5%   -3.33%  (p=0.007 n=11+11)

    name           old speed      new speed      delta
    ReadBlocks-16   478MB/s ± 4%   494MB/s ± 5%   +3.46%  (p=0.007 n=11+11)

    name           old alloc/op   new alloc/op   delta
    ReadBlocks-16    1.30MB ± 0%    1.25MB ± 0%   -3.86%  (p=0.000 n=12+12)

    name           old allocs/op  new allocs/op  delta
    ReadBlocks-16     9.50k ± 0%     8.45k ± 0%  -11.05%  (p=0.000 n=12+12)
2021-09-12 14:08:59 +02:00
9 changed files with 128 additions and 10 deletions

View File

@@ -27,7 +27,7 @@ jobs:
echo "RUNGOGENERATE=true" >> $GITHUB_ENV
fi
- name: Install staticcheck
run: go install honnef.co/go/tools/cmd/staticcheck@df71e5d0e0ed317ebf43e6e59cf919430fa4b8f2 # 2021.1.1 (v0.2.1)
run: go install honnef.co/go/tools/cmd/staticcheck@c8caa92bad8c27ae734c6725b8a04932d54a147b # 2021.1.2 (v0.2.2)
- name: Check that go.mod is tidy
uses: protocol/multiple-go-modules@v1.2
with:

View File

@@ -26,13 +26,24 @@ jobs:
run: |
go version
go env
- name: Use msys2 on windows
if: ${{ matrix.os == 'windows' }}
shell: bash
# The executable for msys2 is also called bash.cmd
# https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md#shells
# If we prepend its location to the PATH
# subsequent 'shell: bash' steps will use msys2 instead of gitbash
run: echo "C:/msys64/usr/bin" >> $GITHUB_PATH
- name: Run repo-specific setup
uses: ./.github/actions/go-test-setup
if: hashFiles('./.github/actions/go-test-setup') != ''
- name: Run tests
uses: protocol/multiple-go-modules@v1.2
with:
run: go test -v -coverprofile module-coverage.txt ./...
# Use -coverpkg=./..., so that we include cross-package coverage.
# If package ./A imports ./B, and ./A's tests also cover ./B,
# this means ./B's coverage will be significantly higher than 0%.
run: go test -v -coverprofile=module-coverage.txt -coverpkg=./... ./...
- name: Run tests (32 bit)
if: ${{ matrix.os != 'macos' }} # can't run 32 bit tests on OSX.
uses: protocol/multiple-go-modules@v1.2
@@ -49,7 +60,7 @@ jobs:
shell: bash
run: echo "COVERAGES=$(find . -type f -name 'module-coverage.txt' | tr -s '\n' ',' | sed 's/,$//')" >> $GITHUB_ENV
- name: Upload coverage to Codecov
uses: codecov/codecov-action@51d810878be5422784e86451c0e7c14e5860ec47 # v2.0.2
uses: codecov/codecov-action@f32b3a3741e1053eb607407145bc9619351dc93b # v2.1.0
with:
files: '${{ env.COVERAGES }}'
env_vars: OS=${{ matrix.os }}, GO=${{ matrix.go }}

11
.github/workflows/release-check.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
# File managed by web3-bot. DO NOT EDIT.
# See https://github.com/protocol/.github/ for details.
name: Release Checker
on:
pull_request:
paths: [ 'version.json' ]
jobs:
release-check:
uses: protocol/.github/.github/workflows/release-check.yml@master

11
.github/workflows/releaser.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
# File managed by web3-bot. DO NOT EDIT.
# See https://github.com/protocol/.github/ for details.
name: Releaser
on:
push:
paths: [ 'version.json' ]
jobs:
releaser:
uses: protocol/.github/.github/workflows/releaser.yml@master

12
.github/workflows/tagpush.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# File managed by web3-bot. DO NOT EDIT.
# See https://github.com/protocol/.github/ for details.
name: Tag Push Checker
on:
push:
tags:
- v*
jobs:
releaser:
uses: protocol/.github/.github/workflows/tagpush.yml@master

61
benchmark_test.go Normal file
View File

@@ -0,0 +1,61 @@
package cid_test
import (
"math/rand"
"testing"
"github.com/ipfs/go-cid"
"github.com/multiformats/go-multihash"
)
// BenchmarkIdentityCheck benchmarks two ways of checking whether a CIDv1 has multihash.IDENTITY
// code:
// 1. Cid.Prefix(), and
// 2. decoding the Cid.Hash().
//
// This benchmark illustrates that using Cid.Prefix is more efficient than multihash.Decode.
// Users wishing to perform such a check should use Cid.Prefix.
//
// Consider that `Cid.Prefix` is already efficient enough and introducing a dedicated API for
// performing this check will likely result in small gains.
func BenchmarkIdentityCheck(b *testing.B) {
rng := rand.New(rand.NewSource(1413))
data := make([]byte, rng.Intn(100)+1024)
if _, err := rng.Read(data); err != nil {
b.Fatal(err)
}
mh, err := multihash.Sum(data, multihash.IDENTITY, -1)
if err != nil {
b.Fatal(err)
}
cv1 := cid.NewCidV1(cid.Raw, mh)
b.SetBytes(int64(cv1.ByteLen()))
b.ReportAllocs()
b.ResetTimer()
b.Run("Prefix", func(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if cv1.Prefix().MhType != multihash.IDENTITY {
b.Fatal("expected IDENTITY CID")
}
}
})
})
b.Run("MultihashDecode", func(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
dmh, err := multihash.Decode(cv1.Hash())
if err != nil {
b.Fatal(err)
}
if dmh.Code != multihash.IDENTITY {
b.Fatal("expected IDENTITY CID")
}
}
})
})
}

21
cid.go
View File

@@ -22,6 +22,7 @@ package cid
import (
"bytes"
"encoding"
"encoding/binary"
"encoding/json"
"errors"
"fmt"
@@ -173,16 +174,24 @@ func NewCidV0(mhash mh.Multihash) Cid {
// Panics if the multihash is invalid.
func NewCidV1(codecType uint64, mhash mh.Multihash) Cid {
hashlen := len(mhash)
// two 8 bytes (max) numbers plus hash
buf := make([]byte, 1+varint.UvarintSize(codecType)+hashlen)
n := varint.PutUvarint(buf, 1)
n += varint.PutUvarint(buf[n:], codecType)
cn := copy(buf[n:], mhash)
// Two 8 bytes (max) numbers plus hash.
// We use strings.Builder to only allocate once.
var b strings.Builder
b.Grow(1 + varint.UvarintSize(codecType) + hashlen)
b.WriteByte(1)
var buf [binary.MaxVarintLen64]byte
n := varint.PutUvarint(buf[:], codecType)
b.Write(buf[:n])
cn, _ := b.Write(mhash)
if cn != hashlen {
panic("copy hash length is inconsistent")
}
return Cid{string(buf[:n+hashlen])}
return Cid{b.String()}
}
var (

2
go.mod
View File

@@ -2,7 +2,7 @@ module github.com/ipfs/go-cid
require (
github.com/multiformats/go-multibase v0.0.3
github.com/multiformats/go-multihash v0.0.15
github.com/multiformats/go-multihash v0.1.0
github.com/multiformats/go-varint v0.0.6
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf // indirect
)

3
version.json Normal file
View File

@@ -0,0 +1,3 @@
{
"version": "v0.1.0"
}