Use bits.OnesCount64 when available

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)
This commit is contained in:
Dominik Honnef 2018-05-02 15:40:49 +02:00 committed by Dong-hee Na
parent 7f23d56ee5
commit ad2b6ded3b
5 changed files with 42 additions and 7 deletions

View File

@ -1,3 +1,4 @@
## AUTHORS ## AUTHORS
- [Dominik Honnef](https://github.com/dominikh) dominik@honnef.co
- [Dong-hee Na](https://github.com/corona10/) donghee.na92@gmail.com - [Dong-hee Na](https://github.com/corona10/) donghee.na92@gmail.com
- [Gustavo Brunoro](https://github.com/brunoro/) git@hitnail.net - [Gustavo Brunoro](https://github.com/brunoro/) git@hitnail.net

View File

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

View File

@ -42,17 +42,11 @@ func (h *ImageHash) Distance(other *ImageHash) (int, error) {
return -1, errors.New("Image hashes's kind should be identical") return -1, errors.New("Image hashes's kind should be identical")
} }
diff := 0
lhash := h.GetHash() lhash := h.GetHash()
rhash := other.GetHash() rhash := other.GetHash()
hamming := lhash ^ rhash hamming := lhash ^ rhash
for hamming != 0 { return popcnt(hamming), nil
diff += int(hamming & 1)
hamming >>= 1
}
return diff, nil
} }
// GetHash method returns a 64bits hash value. // GetHash method returns a 64bits hash value.

13
imagehash18.go Normal file
View File

@ -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
}

9
imagehash19.go Normal file
View File

@ -0,0 +1,9 @@
// +build go1.9
package goimagehash
import (
"math/bits"
)
func popcnt(x uint64) int { return bits.OnesCount64(x) }