From c4e37dc47ca37048723db4269904a483171f842a Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 13 Jul 2021 18:13:25 +0200 Subject: [PATCH] Use the same background executor for spawning CPU intensive tasks Co-Authored-By: Nathan Sobo Co-Authored-By: Max Brunsfeld --- gpui/src/app.rs | 15 ---- gpui/src/executor.rs | 12 +--- gpui_macros/src/lib.rs | 2 +- zed/src/file_finder.rs | 4 +- zed/src/worktree.rs | 12 ++-- zed/src/worktree/fuzzy.rs | 143 +++++++++++++++++++------------------- 6 files changed, 85 insertions(+), 103 deletions(-) diff --git a/gpui/src/app.rs b/gpui/src/app.rs index 7bcb43a27cf8711f92d0b020eaf9a639a33e8e8b..b356a883f61312aff1cf903beeb14cb7a7749667 100644 --- a/gpui/src/app.rs +++ b/gpui/src/app.rs @@ -123,7 +123,6 @@ impl App { let cx = Rc::new(RefCell::new(MutableAppContext::new( foreground, Arc::new(executor::Background::new()), - Arc::new(executor::Background::new()), Arc::new(platform), Rc::new(foreground_platform), (), @@ -140,7 +139,6 @@ impl App { let app = Self(Rc::new(RefCell::new(MutableAppContext::new( foreground, Arc::new(executor::Background::new()), - Arc::new(executor::Background::new()), platform.clone(), foreground_platform.clone(), asset_source, @@ -247,7 +245,6 @@ impl TestAppContext { pub fn new( foreground: Rc, background: Arc, - thread_pool: Arc, first_entity_id: usize, ) -> Self { let platform = Arc::new(platform::test::platform()); @@ -255,7 +252,6 @@ impl TestAppContext { let mut cx = MutableAppContext::new( foreground.clone(), background, - thread_pool, platform, foreground_platform.clone(), (), @@ -594,7 +590,6 @@ impl MutableAppContext { fn new( foreground: Rc, background: Arc, - thread_pool: Arc, platform: Arc, foreground_platform: Rc, asset_source: impl AssetSource, @@ -612,7 +607,6 @@ impl MutableAppContext { values: Default::default(), ref_counts: Arc::new(Mutex::new(RefCounts::default())), background, - thread_pool, font_cache: Arc::new(FontCache::new(fonts)), }, actions: HashMap::new(), @@ -1490,7 +1484,6 @@ pub struct AppContext { values: RwLock>>, background: Arc, ref_counts: Arc>, - thread_pool: Arc, font_cache: Arc, } @@ -1535,10 +1528,6 @@ impl AppContext { &self.font_cache } - pub fn thread_pool(&self) -> &Arc { - &self.thread_pool - } - pub fn value(&self, id: usize) -> ValueHandle { let key = (TypeId::of::(), id); let mut values = self.values.write(); @@ -1721,10 +1710,6 @@ impl<'a, T: Entity> ModelContext<'a, T> { &self.app.cx.background } - pub fn thread_pool(&self) -> &Arc { - &self.app.cx.thread_pool - } - pub fn halt_stream(&mut self) { self.halt_stream = true; } diff --git a/gpui/src/executor.rs b/gpui/src/executor.rs index ad4338d3ee9a00af2d4a556b651aa26913cd8b65..037754d402fcd5598c68cbceeee5ee05b838ee86 100644 --- a/gpui/src/executor.rs +++ b/gpui/src/executor.rs @@ -34,7 +34,6 @@ pub enum Background { Deterministic(Arc), Production { executor: Arc>, - threads: usize, _stop: channel::Sender<()>, }, } @@ -324,9 +323,8 @@ impl Background { pub fn new() -> Self { let executor = Arc::new(Executor::new()); let stop = channel::unbounded::<()>(); - let threads = num_cpus::get(); - for i in 0..threads { + for i in 0..2 * num_cpus::get() { let executor = executor.clone(); let stop = stop.1.clone(); thread::Builder::new() @@ -337,16 +335,12 @@ impl Background { Self::Production { executor, - threads, _stop: stop.0, } } - pub fn threads(&self) -> usize { - match self { - Self::Deterministic(_) => 1, - Self::Production { threads, .. } => *threads, - } + pub fn num_cpus(&self) -> usize { + num_cpus::get() } pub fn spawn(&self, future: F) -> Task diff --git a/gpui_macros/src/lib.rs b/gpui_macros/src/lib.rs index 30f164bad1511ccac8517fd465c9be9d38669b39..5606726f8c5f58487e1f1e843527767dce617a80 100644 --- a/gpui_macros/src/lib.rs +++ b/gpui_macros/src/lib.rs @@ -60,7 +60,7 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream { let inner_fn_args = (0..inner_fn.sig.inputs.len()) .map(|i| { let first_entity_id = i * 100_000; - quote!(#namespace::TestAppContext::new(foreground.clone(), background.clone(), background.clone(), #first_entity_id),) + quote!(#namespace::TestAppContext::new(foreground.clone(), background.clone(), #first_entity_id),) }) .collect::(); diff --git a/zed/src/file_finder.rs b/zed/src/file_finder.rs index 33259f5ff71c38e5166b2adf1450580b543d82bc..a48b402c6588613f59c073b10dfe618a99cd1d07 100644 --- a/zed/src/file_finder.rs +++ b/zed/src/file_finder.rs @@ -399,7 +399,7 @@ impl FileFinder { .map(|tree| tree.read(cx).snapshot()) .collect::>(); let search_id = util::post_inc(&mut self.search_count); - let pool = cx.as_ref().thread_pool().clone(); + let background = cx.as_ref().background().clone(); self.cancel_flag.store(true, atomic::Ordering::Relaxed); self.cancel_flag = Arc::new(AtomicBool::new(false)); let cancel_flag = self.cancel_flag.clone(); @@ -413,7 +413,7 @@ impl FileFinder { false, 100, cancel_flag.clone(), - pool, + background, ) .await; let did_cancel = cancel_flag.load(atomic::Ordering::Relaxed); diff --git a/zed/src/worktree.rs b/zed/src/worktree.rs index 35034cb4c646c4c90ce984a6867fb969d0409d7a..01b497a9dab1db941ed663a5536fbcc0a7b10c01 100644 --- a/zed/src/worktree.rs +++ b/zed/src/worktree.rs @@ -552,11 +552,11 @@ impl Worktree { let tree = tree.as_local_mut().unwrap(); let abs_path = tree.snapshot.abs_path.clone(); let background_snapshot = tree.background_snapshot.clone(); - let thread_pool = cx.thread_pool().clone(); + let background = cx.background().clone(); tree._background_scanner_task = Some(cx.background().spawn(async move { let events = fs.watch(&abs_path, Duration::from_millis(100)).await; let scanner = - BackgroundScanner::new(background_snapshot, scan_states_tx, fs, thread_pool); + BackgroundScanner::new(background_snapshot, scan_states_tx, fs, background); scanner.run(events).await; })); }); @@ -2295,7 +2295,7 @@ impl BackgroundScanner { self.executor .scoped(|scope| { - for _ in 0..self.executor.threads() { + for _ in 0..self.executor.num_cpus() { scope.spawn(async { while let Ok(job) = rx.recv().await { if let Err(err) = self @@ -2487,7 +2487,7 @@ impl BackgroundScanner { drop(scan_queue_tx); self.executor .scoped(|scope| { - for _ in 0..self.executor.threads() { + for _ in 0..self.executor.num_cpus() { scope.spawn(async { while let Ok(job) = scan_queue_rx.recv().await { if let Err(err) = self @@ -2555,7 +2555,7 @@ impl BackgroundScanner { self.executor .scoped(|scope| { - for _ in 0..self.executor.threads() { + for _ in 0..self.executor.num_cpus() { scope.spawn(async { while let Ok(job) = ignore_queue_rx.recv().await { self.update_ignore_status(job, &snapshot).await; @@ -3044,7 +3044,7 @@ mod tests { false, 10, Default::default(), - cx.thread_pool().clone(), + cx.background().clone(), ) }) .await; diff --git a/zed/src/worktree/fuzzy.rs b/zed/src/worktree/fuzzy.rs index 484b8e9535ddd0d2ce4c5a2f224dcce4a2e17b08..776fd2177db59710a64c0ddfd226b0f7846a84bb 100644 --- a/zed/src/worktree/fuzzy.rs +++ b/zed/src/worktree/fuzzy.rs @@ -59,7 +59,7 @@ pub async fn match_paths<'a, T>( smart_case: bool, max_results: usize, cancel_flag: Arc, - pool: Arc, + background: Arc, ) -> Vec where T: Clone + Send + Iterator + 'a, @@ -77,82 +77,85 @@ where snapshots.clone().map(Snapshot::visible_file_count).sum() }; - let segment_size = (path_count + pool.threads() - 1) / pool.threads(); - let mut segment_results = (0..pool.threads()) + let num_cpus = background.num_cpus().min(path_count); + let segment_size = (path_count + num_cpus - 1) / num_cpus; + let mut segment_results = (0..num_cpus) .map(|_| Vec::with_capacity(max_results)) .collect::>(); - pool.scoped(|scope| { - for (segment_idx, results) in segment_results.iter_mut().enumerate() { - let snapshots = snapshots.clone(); - let cancel_flag = &cancel_flag; - scope.spawn(async move { - let segment_start = segment_idx * segment_size; - let segment_end = segment_start + segment_size; - - let mut min_score = 0.0; - let mut last_positions = Vec::new(); - last_positions.resize(query.len(), 0); - let mut match_positions = Vec::new(); - match_positions.resize(query.len(), 0); - let mut score_matrix = Vec::new(); - let mut best_position_matrix = Vec::new(); - - let mut tree_start = 0; - for snapshot in snapshots { - let tree_end = if include_ignored { - tree_start + snapshot.file_count() - } else { - tree_start + snapshot.visible_file_count() - }; - - let include_root_name = include_root_name || snapshot.root_entry().is_file(); - if tree_start < segment_end && segment_start < tree_end { - let start = max(tree_start, segment_start) - tree_start; - let end = min(tree_end, segment_end) - tree_start; - let entries = if include_ignored { - snapshot.files(start).take(end - start) + background + .scoped(|scope| { + for (segment_idx, results) in segment_results.iter_mut().enumerate() { + let snapshots = snapshots.clone(); + let cancel_flag = &cancel_flag; + scope.spawn(async move { + let segment_start = segment_idx * segment_size; + let segment_end = segment_start + segment_size; + + let mut min_score = 0.0; + let mut last_positions = Vec::new(); + last_positions.resize(query.len(), 0); + let mut match_positions = Vec::new(); + match_positions.resize(query.len(), 0); + let mut score_matrix = Vec::new(); + let mut best_position_matrix = Vec::new(); + + let mut tree_start = 0; + for snapshot in snapshots { + let tree_end = if include_ignored { + tree_start + snapshot.file_count() } else { - snapshot.visible_files(start).take(end - start) + tree_start + snapshot.visible_file_count() }; - let paths = entries.map(|entry| { - if let EntryKind::File(char_bag) = entry.kind { - MatchCandidate { - path: &entry.path, - char_bag, - } + + let include_root_name = + include_root_name || snapshot.root_entry().is_file(); + if tree_start < segment_end && segment_start < tree_end { + let start = max(tree_start, segment_start) - tree_start; + let end = min(tree_end, segment_end) - tree_start; + let entries = if include_ignored { + snapshot.files(start).take(end - start) } else { - unreachable!() - } - }); - - match_single_tree_paths( - snapshot, - include_root_name, - paths, - query, - lowercase_query, - query_chars, - smart_case, - results, - max_results, - &mut min_score, - &mut match_positions, - &mut last_positions, - &mut score_matrix, - &mut best_position_matrix, - &cancel_flag, - ); - } - if tree_end >= segment_end { - break; + snapshot.visible_files(start).take(end - start) + }; + let paths = entries.map(|entry| { + if let EntryKind::File(char_bag) = entry.kind { + MatchCandidate { + path: &entry.path, + char_bag, + } + } else { + unreachable!() + } + }); + + match_single_tree_paths( + snapshot, + include_root_name, + paths, + query, + lowercase_query, + query_chars, + smart_case, + results, + max_results, + &mut min_score, + &mut match_positions, + &mut last_positions, + &mut score_matrix, + &mut best_position_matrix, + &cancel_flag, + ); + } + if tree_end >= segment_end { + break; + } + tree_start = tree_end; } - tree_start = tree_end; - } - }) - } - }) - .await; + }) + } + }) + .await; let mut results = Vec::new(); for segment_result in segment_results {