From ad2b6ded3b8175cd5f5edf103da7aa4e14884857 Mon Sep 17 00:00:00 2001 From: Dominik Honnef Date: Wed, 2 May 2018 15:40:49 +0200 Subject: [PATCH] Use bits.OnesCount64 when available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Benchmark on i7-2600k, which has the POPCNT instruction: name old time/op new time/op delta DistanceIdentical-8 5.08ns ± 0% 1.01ns ± 1% -80.07% (p=0.008 n=5+5) DistanceDifferent-8 81.5ns ± 2% 1.0ns ± 0% -98.76% (p=0.016 n=5+4) Benchmark on Cavium Octeon, a MIPS64 platform with no dedicated instruction: name old time/op new time/op delta DistanceIdentical-2 120ns ± 6% 144ns ± 5% +19.93% (p=0.008 n=5+5) DistanceDifferent-2 656ns ± 4% 144ns ± 4% -78.09% (p=0.008 n=5+5) --- AUTHORS.md | 1 + hashcompute_test.go | 18 ++++++++++++++++++ imagehash.go | 8 +------- imagehash18.go | 13 +++++++++++++ imagehash19.go | 9 +++++++++ 5 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 imagehash18.go create mode 100644 imagehash19.go diff --git a/AUTHORS.md b/AUTHORS.md index 63bd4ad..56c7518 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -1,3 +1,4 @@ ## AUTHORS +- [Dominik Honnef](https://github.com/dominikh) dominik@honnef.co - [Dong-hee Na](https://github.com/corona10/) donghee.na92@gmail.com - [Gustavo Brunoro](https://github.com/brunoro/) git@hitnail.net diff --git a/hashcompute_test.go b/hashcompute_test.go index 5502098..47e6c71 100644 --- a/hashcompute_test.go +++ b/hashcompute_test.go @@ -97,3 +97,21 @@ func TestHashCompute(t *testing.T) { } } } + +func BenchmarkDistanceIdentical(b *testing.B) { + h1 := &ImageHash{hash: 0xe48ae53c05e502f7} + h2 := &ImageHash{hash: 0xe48ae53c05e502f7} + + for i := 0; i < b.N; i++ { + h1.Distance(h2) + } +} + +func BenchmarkDistanceDifferent(b *testing.B) { + h1 := &ImageHash{hash: 0xe48ae53c05e502f7} + h2 := &ImageHash{hash: 0x678be53815e510f7} // 8 bits flipped + + for i := 0; i < b.N; i++ { + h1.Distance(h2) + } +} diff --git a/imagehash.go b/imagehash.go index 785a34b..da0af93 100644 --- a/imagehash.go +++ b/imagehash.go @@ -42,17 +42,11 @@ func (h *ImageHash) Distance(other *ImageHash) (int, error) { return -1, errors.New("Image hashes's kind should be identical") } - diff := 0 lhash := h.GetHash() rhash := other.GetHash() hamming := lhash ^ rhash - for hamming != 0 { - diff += int(hamming & 1) - hamming >>= 1 - } - - return diff, nil + return popcnt(hamming), nil } // GetHash method returns a 64bits hash value. diff --git a/imagehash18.go b/imagehash18.go new file mode 100644 index 0000000..e8d3fd6 --- /dev/null +++ b/imagehash18.go @@ -0,0 +1,13 @@ +// +build !go1.9 + +package goimagehash + +func popcnt(x uint64) int { + diff := 0 + for x != 0 { + diff += int(x & 1) + x >>= 1 + } + + return diff +} diff --git a/imagehash19.go b/imagehash19.go new file mode 100644 index 0000000..c1d47be --- /dev/null +++ b/imagehash19.go @@ -0,0 +1,9 @@ +// +build go1.9 + +package goimagehash + +import ( + "math/bits" +) + +func popcnt(x uint64) int { return bits.OnesCount64(x) }