]> Cypherpunks repositories - gostls13.git/commitdiff
sort: reduce leaf calls in Stable
authorJosh Bleecher Snyder <josharian@gmail.com>
Thu, 18 Dec 2014 21:11:08 +0000 (13:11 -0800)
committerJosh Bleecher Snyder <josharian@gmail.com>
Mon, 22 Dec 2014 21:17:43 +0000 (21:17 +0000)
Move the symMerge recursion stopping condition
from the beginning of symMerge to the callers.

This halves the number of calls to symMerge
while running 'go test sort'.

benchmark                   old ns/op      new ns/op      delta
BenchmarkStable1e6          8358117060     7954143849     -4.83%
BenchmarkStable1e4          40116117       38583285       -3.82%
BenchmarkStableInt1K        119150         115182         -3.33%
BenchmarkStableInt64K       9799845        9515475        -2.90%
BenchmarkStableString1K     388901         393516         +1.19%
BenchmarkStable1e2          124917         123618         -1.04%

Change-Id: I7ba2ca277f213b076fe6830e1139edb47ac53800
Reviewed-on: https://go-review.googlesource.com/1820
Reviewed-by: Robert Griesemer <gri@golang.org>
src/sort/sort.go

index 63f8894a1967cd42ddfd757e52221143521aac24..55134956c00b083afd04a60dd805b767e11ff992 100644 (file)
@@ -316,7 +316,7 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
 // data.Less and O(n*log(n)*log(n)) calls to data.Swap.
 func Stable(data Interface) {
        n := data.Len()
-       blockSize := 20
+       blockSize := 20 // must be > 0
        a, b := 0, blockSize
        for b <= n {
                insertionSort(data, a, b)
@@ -332,7 +332,9 @@ func Stable(data Interface) {
                        a = b
                        b += 2 * blockSize
                }
-               symMerge(data, a, a+blockSize, n)
+               if m := a + blockSize; m < n {
+                       symMerge(data, a, m, n)
+               }
                blockSize *= 2
        }
 }
@@ -352,11 +354,11 @@ func Stable(data Interface) {
 // rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
 // in the paper carries through for Swap operations, especially as the block
 // swapping rotate uses only O(M+N) Swaps.
+//
+// symMerge assumes non-degenerate arguments: a < m && m < b.
+// Having the caller check this condition eliminates many leaf recursion calls,
+// which improves performance.
 func symMerge(data Interface, a, m, b int) {
-       if a >= m || m >= b {
-               return
-       }
-
        mid := a + (b-a)/2
        n := mid + m
        var start, r int
@@ -380,8 +382,12 @@ func symMerge(data Interface, a, m, b int) {
 
        end := n - start
        rotate(data, start, m, end)
-       symMerge(data, a, start, mid)
-       symMerge(data, mid, end, b)
+       if a < start && start < mid {
+               symMerge(data, a, start, mid)
+       }
+       if mid < end && end < b {
+               symMerge(data, mid, end, b)
+       }
 }
 
 // Rotate two consecutives blocks u = data[a:m] and v = data[m:b] in data: