[#8] hrw: Inline swap() when slice is known
``` goos: linux goarch: amd64 pkg: git.frostfs.info/TrueCloudLab/hrw cpu: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz │ 2 │ 3 │ │ sec/op │ sec/op vs base │ SortHashersByValue_Typed_fnv_10-8 368.5n ± 2% 336.3n ± 3% -8.75% (p=0.000 n=10) SortHashersByValue_Typed_fnv_100-8 2.411µ ± 4% 2.424µ ± 3% ~ (p=0.853 n=10) SortHashersByValue_Typed_fnv_1000-8 22.19µ ± 2% 22.35µ ± 1% ~ (p=0.247 n=10) SortHashersByWeightValueTyped_fnv_10-8 364.3n ± 2% 346.6n ± 3% -4.86% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_100-8 2.541µ ± 3% 2.637µ ± 6% ~ (p=0.055 n=10) SortHashersByWeightValueTyped_fnv_1000-8 2.483µ ± 1% 2.609µ ± 4% +5.07% (p=0.003 n=10) geomean 1.888µ 1.875µ -0.71% │ 2 │ 3 │ │ B/op │ B/op vs base │ SortHashersByValue_Typed_fnv_10-8 312.0 ± 0% 296.0 ± 0% -5.13% (p=0.000 n=10) SortHashersByValue_Typed_fnv_100-8 1.898Ki ± 0% 1.883Ki ± 0% -0.82% (p=0.000 n=10) SortHashersByValue_Typed_fnv_1000-8 16.15Ki ± 0% 16.13Ki ± 0% -0.10% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_10-8 312.0 ± 0% 296.0 ± 0% -5.13% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_100-8 1.898Ki ± 0% 1.883Ki ± 0% -0.82% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_1000-8 1.898Ki ± 0% 1.883Ki ± 0% -0.82% (p=0.000 n=10) geomean 1.474Ki 1.442Ki -2.16% │ 2 │ 3 │ │ allocs/op │ allocs/op vs base │ SortHashersByValue_Typed_fnv_10-8 6.000 ± 0% 5.000 ± 0% -16.67% (p=0.000 n=10) SortHashersByValue_Typed_fnv_100-8 6.000 ± 0% 5.000 ± 0% -16.67% (p=0.000 n=10) SortHashersByValue_Typed_fnv_1000-8 6.000 ± 0% 5.000 ± 0% -16.67% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_10-8 6.000 ± 0% 5.000 ± 0% -16.67% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_100-8 6.000 ± 0% 5.000 ± 0% -16.67% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_1000-8 6.000 ± 0% 5.000 ± 0% -16.67% (p=0.000 n=10) geomean 6.000 5.000 -16.67% ``` Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
This commit is contained in:
parent
213c105ac1
commit
895ecf150f
1 changed files with 51 additions and 8 deletions
55
hrw.go
55
hrw.go
|
@ -87,10 +87,7 @@ func SortSliceByValue(slice interface{}, hash uint64) {
|
||||||
func SortHasherSliceByValue[T Hasher](slice []T, hash uint64) {
|
func SortHasherSliceByValue[T Hasher](slice []T, hash uint64) {
|
||||||
rule := prepareHasherRule(slice)
|
rule := prepareHasherRule(slice)
|
||||||
if rule != nil {
|
if rule != nil {
|
||||||
swap := func(i, j int) {
|
sortHasherByDistance(slice, false, rule, hash)
|
||||||
slice[i], slice[j] = slice[j], slice[i]
|
|
||||||
}
|
|
||||||
sortByDistance(len(rule), false, rule, hash, swap)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,11 +104,57 @@ func SortSliceByWeightValue(slice interface{}, weights []float64, hash uint64) {
|
||||||
func SortHasherSliceByWeightValue[T Hasher](slice []T, weights []float64, hash uint64) {
|
func SortHasherSliceByWeightValue[T Hasher](slice []T, weights []float64, hash uint64) {
|
||||||
rule := prepareHasherRule(slice)
|
rule := prepareHasherRule(slice)
|
||||||
if rule != nil {
|
if rule != nil {
|
||||||
swap := func(i, j int) {
|
sortHasherByWeight(slice, false, rule, weights, hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sortHasherByDistance is similar to sortByDistance but accepts slice directly.
|
||||||
|
func sortHasherByDistance[T Hasher](slice []T, byIndex bool, nodes []uint64, hash uint64) {
|
||||||
|
dist := make([]uint64, len(slice))
|
||||||
|
for i := range dist {
|
||||||
|
dist[i] = getDistance(byIndex, i, nodes, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
s := &sorter{
|
||||||
|
l: len(slice),
|
||||||
|
swap: func(i, j int) {
|
||||||
slice[i], slice[j] = slice[j], slice[i]
|
slice[i], slice[j] = slice[j], slice[i]
|
||||||
|
dist[i], dist[j] = dist[j], dist[i]
|
||||||
|
},
|
||||||
|
less: func(i, j int) bool {
|
||||||
|
return dist[i] < dist[j]
|
||||||
|
},
|
||||||
}
|
}
|
||||||
sortByWeight(len(slice), false, rule, weights, hash, swap)
|
sort.Sort(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sortHasherByWeight is similar to sortByWeight but accepts slice directly.
|
||||||
|
func sortHasherByWeight[T Hasher](slice []T, byIndex bool, nodes []uint64, weights []float64, hash uint64) {
|
||||||
|
// if all nodes have the same distance then sort uniformly
|
||||||
|
if allSameF64(weights) {
|
||||||
|
sortHasherByDistance(slice, byIndex, nodes, hash)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dist := make([]float64, len(slice))
|
||||||
|
for i := range dist {
|
||||||
|
d := getDistance(byIndex, i, nodes, hash)
|
||||||
|
// `maxUint64 - distance` makes the shorter distance more valuable
|
||||||
|
// it is necessary for operation with normalized values
|
||||||
|
dist[i] = float64(^uint64(0)-d) * weights[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
s := &sorter{
|
||||||
|
l: len(slice),
|
||||||
|
swap: func(i, j int) {
|
||||||
|
slice[i], slice[j] = slice[j], slice[i]
|
||||||
|
dist[i], dist[j] = dist[j], dist[i]
|
||||||
|
},
|
||||||
|
less: func(i, j int) bool {
|
||||||
|
return dist[i] > dist[j] // higher distance must be placed lower to be first
|
||||||
|
},
|
||||||
|
}
|
||||||
|
sort.Sort(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SortSliceByIndex received []T and hash to sort by index-distance
|
// SortSliceByIndex received []T and hash to sort by index-distance
|
||||||
|
|
Loading…
Reference in a new issue