Skip to content

Commit

Permalink
Spill recursion stack over to heap if necessary.
Browse files Browse the repository at this point in the history
  • Loading branch information
n3vu0r committed Jun 13, 2024
1 parent 5ed3d62 commit ba79df2
Show file tree
Hide file tree
Showing 10 changed files with 62 additions and 24 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,4 @@ jobs:
- name: fmt
run: cargo fmt --check
- name: miri
run: cargo miri test -- Slice1Ext
run: cargo miri test --no-default-features --features std -- Slice1Ext
7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ndarray-slice"
version = "0.3.0"
version = "0.3.1"
rust-version = "1.65.0"
edition = "2021"
authors = ["Rouven Spreckels <[email protected]>"]
Expand Down Expand Up @@ -37,15 +37,16 @@ rustdoc-args = ["--cfg", "docsrs"]

[dependencies]
ndarray = { version = "0.15.6", default-features = false }
rayon = { version = "1.9.0", optional = true }
stacker = { version = "0.1.15", optional = true }
rayon = { version = "1.10.0", optional = true }

[dev-dependencies]
quickcheck = "1.0.3"
quickcheck_macros = "1.0.0"
rand = "0.8.5"

[features]
default = ["std"]
default = ["std", "stacker"]
alloc = []
std = ["alloc", "ndarray/std"]
rayon = ["dep:rayon", "ndarray/rayon", "std"]
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ See the [release history](RELEASES.md) to keep track of the development.

* `alloc` for stable `sort`/`sort_by`/`sort_by_key`. Enabled by `std`.
* `std` for stable `sort_by_cached_key`. Enabled by `default` or `rayon`.
* `stacker` for spilling recursion stack over to heap if necessary. Enabled by `default`.
* `rayon` for parallel `par_sort*`/`par_select_many_nth_unstable*`.

# License
Expand Down
4 changes: 4 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Version 0.3.1 (2024-06-13)

* Spill recursion stack over to heap if necessary.

# Version 0.3.0 (2024-03-19)

* Synchronize with Rust standard library.
Expand Down
13 changes: 13 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
//!
//! * `alloc` for stable `sort`/`sort_by`/`sort_by_key`. Enabled by `std`.
//! * `std` for stable `sort_by_cached_key`. Enabled by `default` or `rayon`.
//! * `stacker` for spilling recursion stack over to heap if necessary. Enabled by `default`.
//! * `rayon` for parallel `par_sort*`/`par_select_many_nth_unstable*`.

#![deny(
Expand All @@ -81,6 +82,18 @@
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(miri, feature(strict_provenance), feature(maybe_uninit_slice))]

#[inline(always)]
fn maybe_grow<R, F: FnOnce() -> R>(callback: F) -> R {
#[cfg(feature = "stacker")]
{
stacker::maybe_grow(32 * 1_024, 1_024 * 1_024, callback)
}
#[cfg(not(feature = "stacker"))]
{
callback()
}
}

mod heap_sort;
mod insertion_sort;
mod merge_sort;
Expand Down
2 changes: 1 addition & 1 deletion src/par/merge_sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl<T> SendPtr<T> {
// Implement Clone without the T: Clone bound from the derive
impl<T> Clone for SendPtr<T> {
fn clone(&self) -> Self {
Self(self.0)
*self
}
}

Expand Down
39 changes: 28 additions & 11 deletions src/par/partition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use crate::{
insertion_sort::InsertionHole,
maybe_grow,
par::insertion_sort::insertion_sort_shift_left,
partition::{break_patterns, reverse},
};
Expand Down Expand Up @@ -48,15 +49,31 @@ pub fn par_partition_at_indices<'a, T, F>(
let (left_values, right_values) = values.split_at_mut(at);
let right_values = &mut right_values[1..];
if at == 0 || pivot - offset <= MAX_SEQUENTIAL {
par_partition_at_indices(left, offset, left_indices, left_values, is_less);
maybe_grow(|| {
par_partition_at_indices(left, offset, left_indices, left_values, is_less)
});
v = right;
offset = pivot + 1;
indices = right_indices;
values = right_values;
} else {
rayon::join(
|| par_partition_at_indices(left, offset, left_indices, left_values, is_less),
|| par_partition_at_indices(right, pivot + 1, right_indices, right_values, is_less),
|| {
maybe_grow(|| {
par_partition_at_indices(left, offset, left_indices, left_values, is_less)
})
},
|| {
maybe_grow(|| {
par_partition_at_indices(
right,
pivot + 1,
right_indices,
right_values,
is_less,
)
})
},
);
break;
}
Expand Down Expand Up @@ -641,15 +658,15 @@ where

if count > 0 {
macro_rules! left {
() => {
v.view_mut().index(l + usize::from(*start_l)) as *mut T //l.add(usize::from(*start_l))
};
}
() => {
v.view_mut().index(l + usize::from(*start_l)) as *mut T //l.add(usize::from(*start_l))
};
}
macro_rules! right {
() => {
v.view_mut().index(r - (usize::from(*start_r) + 1)) as *mut T //r.sub(usize::from(*start_r) + 1)
};
}
() => {
v.view_mut().index(r - (usize::from(*start_r) + 1)) as *mut T //r.sub(usize::from(*start_r) + 1)
};
}

// Instead of swapping one pair at the time, it is more efficient to perform a cyclic
// permutation. This is not strictly equivalent to swapping, but produces a similar
Expand Down
9 changes: 5 additions & 4 deletions src/par/quick_sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//! [`rayon::slice::quicksort`]: https://docs.rs/rayon/latest/src/rayon/slice/quicksort.rs.html

use crate::{
maybe_grow,
par::{
heap_sort::heap_sort,
insertion_sort::{insertion_sort_shift_left, partial_insertion_sort},
Expand Down Expand Up @@ -123,18 +124,18 @@ fn recurse<'a, T, F>(
// calls and consume less stack space. Then just continue with the longer side (this is
// akin to tail recursion).
if left.len() < right.len() {
recurse(left, is_less, pred, limit);
maybe_grow(|| recurse(left, is_less, pred, limit));
v = right;
pred = Some(pivot);
} else {
recurse(right, is_less, Some(pivot), limit);
maybe_grow(|| recurse(right, is_less, Some(pivot), limit));
v = left;
}
} else {
// Sort the left and right half in parallel.
rayon::join(
|| recurse(left, is_less, pred, limit),
|| recurse(right, is_less, Some(pivot), limit),
|| maybe_grow(|| recurse(left, is_less, pred, limit)),
|| maybe_grow(|| recurse(right, is_less, Some(pivot), limit)),
);
break;
}
Expand Down
4 changes: 2 additions & 2 deletions src/partition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//!
//! [`core::slice::sort`]: https://doc.rust-lang.org/src/core/slice/sort.rs.html

use crate::insertion_sort::insertion_sort_shift_left;
use crate::{insertion_sort::insertion_sort_shift_left, maybe_grow};
use core::{
cmp::{
self,
Expand Down Expand Up @@ -33,7 +33,7 @@ pub fn partition_at_indices<'a, T, E, F>(
let (index, right_indices) = right_indices.split_at(Axis(0), 1);
let pivot = *index.index(0);
let (left, value, right) = partition_at_index(v, pivot - offset, is_less);
partition_at_indices(left, offset, left_indices, collection, is_less);
maybe_grow(|| partition_at_indices(left, offset, left_indices, collection, is_less));
collection.extend([(pivot, value)]);
v = right;
offset = pivot + 1;
Expand Down
5 changes: 3 additions & 2 deletions src/quick_sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
heap_sort::heap_sort,
insertion_sort::insertion_sort_shift_left,
insertion_sort::partial_insertion_sort,
maybe_grow,
partition::{break_patterns, choose_pivot, partition, partition_equal},
};
use core::{cmp, mem};
Expand Down Expand Up @@ -115,11 +116,11 @@ fn recurse<'a, T, F>(
// calls and consume less stack space. Then just continue with the longer side (this is
// akin to tail recursion).
if left.len() < right.len() {
recurse(left, is_less, pred, limit);
maybe_grow(|| recurse(left, is_less, pred, limit));
v = right;
pred = Some(pivot);
} else {
recurse(right, is_less, Some(pivot), limit);
maybe_grow(|| recurse(right, is_less, Some(pivot), limit));
v = left;
}
}
Expand Down

0 comments on commit ba79df2

Please sign in to comment.