]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
lib/sort: optimize heapsort for handling final 2 or 3 elements
authorKuan-Wei Chiu <visitorckw@gmail.com>
Mon, 27 May 2024 20:30:10 +0000 (04:30 +0800)
committerAndrew Morton <akpm@linux-foundation.org>
Tue, 25 Jun 2024 05:25:03 +0000 (22:25 -0700)
After building the heap, the code continuously pops two elements from the
heap until only 2 or 3 elements remain, at which point it switches back to
a regular heapsort with one element popped at a time.  However, to handle
the final 2 or 3 elements, an additional else-if statement in the while
loop was introduced, potentially increasing branch misses.  Moreover, when
there are only 2 or 3 elements left, continuing with regular heapify
operations is unnecessary as these cases are simple enough to be handled
with a single comparison and 1 or 2 swaps outside the while loop.

Eliminating the additional else-if statement and directly managing cases
involving 2 or 3 elements outside the loop reduces unnecessary conditional
branches resulting from the numerous loops and conditionals in heapify.

This optimization maintains consistent numbers of comparisons and swaps
for arrays with even lengths while reducing swaps and comparisons for
arrays with odd lengths from 2.5 swaps and 1 comparison to 1.5 swaps and 1
comparison.

Link: https://lkml.kernel.org/r/20240527203011.1644280-4-visitorckw@gmail.com
Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
Cc: Ching-Chun (Jim) Huang <jserv@ccns.ncku.edu.tw>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
lib/sort.c

index b918ae15302da066554f4906db091637a59565a6..048b7a6ef9673ce9e76ca07cf886373454f83704 100644 (file)
@@ -250,10 +250,7 @@ void sort_r(void *base, size_t num, size_t size,
                        a = size << shift;
                        n -= size;
                        do_swap(base + a, base + n, size, swap_func, priv);
-               } else if (n > size) {  /* Sorting: Extract root */
-                       n -= size;
-                       do_swap(base, base + n, size, swap_func, priv);
-               } else  {               /* Sort complete */
+               } else {                /* Sort complete */
                        break;
                }
 
@@ -283,6 +280,11 @@ void sort_r(void *base, size_t num, size_t size,
                        do_swap(base + b, base + c, size, swap_func, priv);
                }
        }
+
+       n -= size;
+       do_swap(base, base + n, size, swap_func, priv);
+       if (n == size * 2 && do_cmp(base, base + size, cmp_func, priv) > 0)
+               do_swap(base, base + size, size, swap_func, priv);
 }
 EXPORT_SYMBOL(sort_r);