History

Somehow handle chunk size in absence of known chunk amount

Sebastian Thiel committed 6 years ago

Commit acfccad1 parent 973e6bb2 files · +75 −20Browse files

Unified · Split

2 files
  1. git-features/src/parallel.rs +25 −20
  2. git-features/tests/parallel.rs +50 −0
git-features/src/parallel.rs+25−20
@@ -36,7 +36,7 @@ mod serial { · 35 unmodified lines
3636
3737 #[cfg(feature = "parallel")]
3838 mod in_parallel {
39− use crate::parallel::Reducer;
39+ use crate::parallel::{num_threads, Reducer};
4040 use crossbeam_utils::thread;
4141
4242 pub fn join<O1: Send, O2: Send>(left: impl FnOnce() -> O1 + Send, right: impl FnOnce() -> O2 + Send) -> (O1, O2) {
@@ -48,13 +48,6 @@ mod in_parallel { · 5 unmodified lines
4848 .unwrap()
4949 }
5050
51− fn num_threads(thread_limit: Option<usize>) -> usize {
52− let logical_cores = num_cpus::get();
53− thread_limit
54− .map(|l| if l == 0 { logical_cores } else { l })
55− .unwrap_or(logical_cores)
56− }
57−
5851 pub fn in_parallel<I, S, O, R>(
5952 input: impl Iterator<Item = I> + Send,
6053 thread_limit: Option<usize>,
@@ -107,16 +100,6 @@ mod in_parallel { · 46 unmodified lines
107100 }
108101 }
109102
110−pub fn num_threads(thread_limit: Option<usize>) -> usize {
111− #[cfg(not(feature = "num_cpus"))]
112− return 1;
113−
114− let logical_cores = num_cpus::get();
115− thread_limit
116− .map(|l| if l == 0 { logical_cores } else { l })
117− .unwrap_or(logical_cores)
118−}
119−
120103 pub fn optimize_chunk_size_and_thread_limit(
121104 desired_chunk_size: usize,
122105 num_chunks: Option<usize>,
@@ -144,7 +127,19 @@ pub fn optimize_chunk_size_and_thread_limit( · 21 unmodified lines
144127 };
145128 (chunk_size, thread_limit)
146129 })
147− .unwrap_or((desired_chunk_size, available_threads));
130+ .unwrap_or((
131+ if available_threads == 1 {
132+ desired_chunk_size
133+ } else {
134+ let arbitrary_desirable_chunk_size = 5;
135+ if desired_chunk_size < arbitrary_desirable_chunk_size {
136+ arbitrary_desirable_chunk_size
137+ } else {
138+ desired_chunk_size
139+ }
140+ },
141+ available_threads,
142+ ));
148143 (chunk_size, Some(thread_limit))
149144 }
150145
@@ -154,6 +149,16 @@ pub use serial::*; · 3 unmodified lines
154149 #[cfg(feature = "parallel")]
155150 pub use in_parallel::*;
156151
152+pub(crate) fn num_threads(thread_limit: Option<usize>) -> usize {
153+ #[cfg(not(feature = "num_cpus"))]
154+ return 1;
155+
156+ let logical_cores = num_cpus::get();
157+ thread_limit
158+ .map(|l| if l == 0 { logical_cores } else { l })
159+ .unwrap_or(logical_cores)
160+}
161+
157162 pub fn in_parallel_if<I, S, O, R>(
158163 condition: impl FnOnce() -> bool,
159164 input: impl Iterator<Item = I> + Send,
@@ -167,7 +172,7 @@ where · 7 unmodified lines
167172 I: Send,
168173 O: Send,
169174 {
170− if condition() {
175+ if num_threads(thread_limit) > 1 && condition() {
171176 in_parallel(input, thread_limit, new_thread_state, consume, reducer)
172177 } else {
173178 serial::in_parallel(input, thread_limit, new_thread_state, consume, reducer)
git-features/tests/parallel.rs+50−0
@@ -32,6 +32,11 @@ mod optimize_chunk_size_and_thread_limit { · 31 unmodified lines
3232 optimize_chunk_size_and_thread_limit(1, Some(100), None, Some(10)),
3333 (5, Some(10))
3434 );
35+ assert_eq!(
36+ optimize_chunk_size_and_thread_limit(1, Some(100), Some(5), Some(10)),
37+ (10, Some(5)),
38+ "the thread limit is always respected"
39+ );
3540 }
3641
3742 #[test]
@@ -40,5 +45,50 @@ mod optimize_chunk_size_and_thread_limit { · 2 unmodified lines
4045 optimize_chunk_size_and_thread_limit(50, Some(2), None, Some(10)),
4146 (5, Some(10))
4247 );
48+ assert_eq!(
49+ optimize_chunk_size_and_thread_limit(50, Some(2), Some(5), Some(10)),
50+ (10, Some(5)),
51+ "the thread limit is always respected"
52+ );
53+ }
54+
55+ mod unknown_chunk_count {
56+ use git_features::parallel::optimize_chunk_size_and_thread_limit;
57+
58+ #[test]
59+ fn medium_chunk_size_many_threads() {
60+ assert_eq!(
61+ optimize_chunk_size_and_thread_limit(50, None, None, Some(4)),
62+ (50, Some(4)),
63+ "really, what do we know"
64+ );
65+ }
66+
67+ #[test]
68+ fn medium_chunk_size_single_thread() {
69+ assert_eq!(
70+ optimize_chunk_size_and_thread_limit(50, None, None, Some(1)),
71+ (50, Some(1)),
72+ "single threaded - we don't touch that"
73+ );
74+ }
75+
76+ #[test]
77+ fn small_chunk_size_single_thread() {
78+ assert_eq!(
79+ optimize_chunk_size_and_thread_limit(1, None, None, Some(1)),
80+ (1, Some(1)),
81+ "single threaded - we don't touch that"
82+ );
83+ }
84+
85+ #[test]
86+ fn small_chunk_size_many_threads() {
87+ assert_eq!(
88+ optimize_chunk_size_and_thread_limit(1, None, None, Some(4)),
89+ (5, Some(4)),
90+ "we prefer an arbitrary number, which should really be based on effort, but the caller has to adjust for that"
91+ );
92+ }
4393 }
4494 }