Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lib/sort: optimize heapsort for handling final 2 or 3 elements

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>

authored by

Kuan-Wei Chiu and committed by
Andrew Morton
41ed7804 f49ac957

+6 -4
+6 -4
lib/sort.c
··· 250 250 a = size << shift; 251 251 n -= size; 252 252 do_swap(base + a, base + n, size, swap_func, priv); 253 - } else if (n > size) { /* Sorting: Extract root */ 254 - n -= size; 255 - do_swap(base, base + n, size, swap_func, priv); 256 - } else { /* Sort complete */ 253 + } else { /* Sort complete */ 257 254 break; 258 255 } 259 256 ··· 280 283 do_swap(base + b, base + c, size, swap_func, priv); 281 284 } 282 285 } 286 + 287 + n -= size; 288 + do_swap(base, base + n, size, swap_func, priv); 289 + if (n == size * 2 && do_cmp(base, base + size, cmp_func, priv) > 0) 290 + do_swap(base, base + size, size, swap_func, priv); 283 291 } 284 292 EXPORT_SYMBOL(sort_r); 285 293