From 4a42c29efac55761e463d27c829a7bc95a9cbbad Mon Sep 17 00:00:00 2001 From: Lukas Bergdoll Date: Thu, 22 Feb 2024 18:11:31 +0100 Subject: [PATCH] Add eager transition (#31) --- src/drift.rs | 26 ++++++++++++-------------- src/lib.rs | 6 +++++- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/drift.rs b/src/drift.rs index b45cd4a..708ccd5 100644 --- a/src/drift.rs +++ b/src/drift.rs @@ -116,20 +116,18 @@ pub fn sort bool>( } let scale_factor = merge_tree_scale_factor(len); - // It's important to have a relatively high entry barrier for pre-sorted - // runs, as the presence of a single such run will force on average several - // merge operations and shrink the maximum quicksort size a lot. For that - // reason we use sqrt(len) as our pre-sorted run threshold, but no smaller - // than 32. When eagerly sorting we use crate::quicksort::SMALL_SORT_THRESHOLD - // as our threshold, as we will call small_sort on any runs smaller than this. - const MIN_MERGE_SLICE_LEN: usize = 32; - let min_good_run_len = if eager_sort { - T::SMALL_SORT_THRESHOLD - } else if len <= (MIN_MERGE_SLICE_LEN * MIN_MERGE_SLICE_LEN) { - MIN_MERGE_SLICE_LEN - } else { - sqrt_approx(len) - }; + // It's important to have a relatively high entry barrier for pre-sorted runs, as the presence + // of a single such run will force on average several merge operations and shrink the maximum + // quicksort size a lot. For that reason we use sqrt(len) as our pre-sorted run threshold, with + // SMALL_SORT_THRESHOLD as the lower limit. When eagerly sorting we also use + // SMALL_SORT_THRESHOLD as our threshold, as we will call small_sort on any runs smaller than + // this. + let min_good_run_len = + if eager_sort || len <= (T::SMALL_SORT_THRESHOLD * T::SMALL_SORT_THRESHOLD) { + T::SMALL_SORT_THRESHOLD + } else { + sqrt_approx(len) + }; // (stack_len, runs, desired_depths) together form a stack maintaining run // information for the powersort heuristic. desired_depths[i] is the desired diff --git a/src/lib.rs b/src/lib.rs index d517318..849d879 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -117,7 +117,11 @@ fn driftsort_main bool, BufT: BufGuard>(v: &mut [T], i let scratch_slice = unsafe { slice::from_raw_parts_mut(buf.mut_ptr() as *mut MaybeUninit, buf.capacity()) }; - let eager_sort = false; + // Using the hybrid quick + merge-sort has performance issues with the transition from insertion + // sort to main loop. A more gradual and smoother transition can be had by using an always eager + // merge approach as long as it can be served by a single merge. + use crate::smallsort::SmallSortTypeImpl; + let eager_sort = len <= T::SMALL_SORT_THRESHOLD * 2; drift::sort(v, scratch_slice, eager_sort, is_less); }