From c175ef40997caab59c6b01b366df1d99b637c2cd Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 1 Jun 2023 19:34:37 +0300 Subject: [PATCH] [#8] hrw: Do not create index slice for sorter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `ind` is only needed to index dist or weights, swap them directly. ``` goos: linux goarch: amd64 pkg: git.frostfs.info/TrueCloudLab/hrw cpu: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz │ 0 │ 1 │ │ sec/op │ sec/op vs base │ SortHashersByValue_Typed_fnv_10-8 596.2n ± 4% 580.1n ± 1% -2.72% (p=0.000 n=10) SortHashersByValue_Typed_fnv_100-8 4.453µ ± 2% 4.215µ ± 2% -5.35% (p=0.000 n=10) SortHashersByValue_Typed_fnv_1000-8 41.58µ ± 4% 39.40µ ± 1% -5.23% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_10-8 624.5n ± 2% 599.6n ± 2% -3.99% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_100-8 4.593µ ± 2% 4.337µ ± 5% -5.56% (p=0.003 n=10) SortHashersByWeightValueTyped_fnv_1000-8 4.896µ ± 8% 4.344µ ± 3% -11.27% (p=0.000 n=10) geomean 4.668µ 4.400µ -5.75% │ 0 │ 1 │ │ B/op │ B/op vs base │ SortHashersByValue_Typed_fnv_10-8 584.0 ± 0% 472.0 ± 0% -19.18% (p=0.000 n=10) SortHashersByValue_Typed_fnv_100-8 4.367Ki ± 0% 3.461Ki ± 0% -20.75% (p=0.000 n=10) SortHashersByValue_Typed_fnv_1000-8 39.80Ki ± 0% 31.77Ki ± 0% -20.18% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_10-8 600.0 ± 0% 472.0 ± 0% -21.33% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_100-8 4.383Ki ± 0% 3.461Ki ± 0% -21.03% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_1000-8 4.383Ki ± 0% 3.461Ki ± 0% -21.03% (p=0.000 n=10) geomean 3.742Ki 3.070Ki -17.96% │ 0 │ 1 │ │ allocs/op │ allocs/op vs base │ SortHashersByValue_Typed_fnv_10-8 17.00 ± 0% 16.00 ± 0% -5.88% (p=0.000 n=10) SortHashersByValue_Typed_fnv_100-8 107.0 ± 0% 106.0 ± 0% -0.93% (p=0.000 n=10) SortHashersByValue_Typed_fnv_1000-8 1.007k ± 0% 1.006k ± 0% -0.10% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_10-8 17.00 ± 0% 16.00 ± 0% -5.88% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_100-8 107.0 ± 0% 106.0 ± 0% -0.93% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_1000-8 107.0 ± 0% 106.0 ± 0% -0.93% (p=0.000 n=10) geomean 115.3 113.0 -1.94% ``` Signed-off-by: Evgenii Stratonikov --- hrw.go | 56 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/hrw.go b/hrw.go index 8ceae9e..57f49fd 100644 --- a/hrw.go +++ b/hrw.go @@ -243,24 +243,6 @@ func ValidateWeights(weights []float64) error { return nil } -func newSorter(l int, byIndex bool, nodes []uint64, h uint64, - swap func(i, j int)) (*sorter, []int, []uint64) { - ind := make([]int, l) - dist := make([]uint64, l) - for i := 0; i < l; i++ { - ind[i] = i - dist[i] = getDistance(byIndex, i, nodes, h) - } - - return &sorter{ - l: l, - swap: func(i, j int) { - swap(i, j) - ind[i], ind[j] = ind[j], ind[i] - }, - }, ind, dist -} - // sortByWeight sorts nodes by weight using provided swapper. // nodes contains hrw hashes. If it is nil, indices are used. func sortByWeight(l int, byIndex bool, nodes []uint64, weights []float64, hash uint64, swap func(i, j int)) { @@ -270,14 +252,23 @@ func sortByWeight(l int, byIndex bool, nodes []uint64, weights []float64, hash u return } - s, ind, dist := newSorter(l, byIndex, nodes, hash, swap) - s.less = func(i, j int) bool { - ii, jj := ind[i], ind[j] + dist := make([]float64, l) + for i := 0; i < l; i++ { + d := getDistance(byIndex, i, nodes, hash) // `maxUint64 - distance` makes the shorter distance more valuable // it is necessary for operation with normalized values - wi := float64(^uint64(0)-dist[ii]) * weights[ii] - wj := float64(^uint64(0)-dist[jj]) * weights[jj] - return wi > wj // higher distance must be placed lower to be first + dist[i] = float64(^uint64(0)-d) * weights[i] + } + + s := &sorter{ + l: l, + swap: func(i, j int) { + swap(i, j) + 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) } @@ -285,9 +276,20 @@ func sortByWeight(l int, byIndex bool, nodes []uint64, weights []float64, hash u // sortByDistance sorts nodes by hrw distance using provided swapper. // nodes contains hrw hashes. If it is nil, indices are used. func sortByDistance(l int, byIndex bool, nodes []uint64, hash uint64, swap func(i, j int)) { - s, ind, dist := newSorter(l, byIndex, nodes, hash, swap) - s.less = func(i, j int) bool { - return dist[ind[i]] < dist[ind[j]] + dist := make([]uint64, l) + for i := 0; i < l; i++ { + dist[i] = getDistance(byIndex, i, nodes, hash) + } + + s := &sorter{ + l: l, + swap: func(i, j int) { + swap(i, j) + dist[i], dist[j] = dist[j], dist[i] + }, + less: func(i, j int) bool { + return dist[i] < dist[j] + }, } sort.Sort(s) }