History

Integrate scheduler crate into GPUI (#44810)

## Motivation This PR unifies the async execution infrastructure between GPUI and other components that depend on the `scheduler` crate (such as our cloud codebase). By having a scheduler that lives independently of GPUI, we can enable deterministic testing across the entire stack - testing GPUI applications alongside cloud services with a single, unified scheduler. ## Summary This PR completes the integration of the `scheduler` crate into GPUI, unifying async execution and enabling deterministic testing of GPUI combined with other components that depend on the scheduler crate. ## Key Changes ### Scheduler Integration (Phases 1-5, previously completed) - `TestDispatcher` now delegates to `TestScheduler` for timing, clock, RNG, and task scheduling - `PlatformScheduler` implements the `Scheduler` trait for production use - GPUI executors wrap scheduler executors, selecting `TestScheduler` or `PlatformScheduler` based on environment - Unified blocking logic via `Scheduler::block()` ### Dead Code Cleanup - Deleted orphaned `crates/gpui/src/platform/platform_scheduler.rs` (older incompatible version) ## Intentional Removals ### `spawn_labeled` and `deprioritize` removed The `TaskLabel` system (`spawn_labeled`, `deprioritize`) was removed during this integration. It was only used in a few places for test ordering control. cc @maxbrunsfeld @as-cii - The new priority-weighted scheduling in `TestScheduler` provides similar functionality through `Priority::High/Medium/Low`. If `deprioritize` is important for specific test scenarios, we could add it back to the scheduler crate. Let me know if this is blocking anything. ### `start_waiting` / `finish_waiting` debug methods removed Replaced by `TracingWaker` in `TestScheduler` - run tests with `PENDING_TRACES=1` to see backtraces of pending futures when parking is forbidden. ### Realtime Priority removed The realtime priority feature was unused in the codebase. I'd prefer to reintroduce it when we have an actual use case, as the implementation (bounded channel with capacity 1) could potentially block the main thread. Having a real use case will help us validate the design. ## Testing - All GPUI tests pass - All scheduler tests pass - Clippy clean ## Architecture ``` ┌─────────────────────────────────────────────────────────────┐ │ GPUI │ │ ┌──────────────────────┐ ┌────────────────────────────┐ │ │ │ gpui::Background- │ │ gpui::ForegroundExecutor │ │ │ │ Executor │ │ - wraps scheduler:: │ │ │ │ - scheduler: Arc< │ │ ForegroundExecutor │ │ │ │ dyn Scheduler> │ └────────────┬───────────────┘ │ │ └──────────┬───────────┘ │ │ │ │ │ │ │ └──────────┬──────────────────┘ │ │ ▼ │ │ ┌───────────────────────┐ │ │ │ Arc<dyn Scheduler> │ │ │ └───────────┬───────────┘ │ │ ┌──────────────┴──────────────┐ │ │ ▼ ▼ │ │ ┌──────────────────┐ ┌────────────────────┐ │ │ │ PlatformScheduler│ │ TestScheduler │ │ │ │ (production) │ │ (deterministic) │ │ │ └──────────────────┘ └────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` Release Notes: - N/A ---------

Nathan Sobo committed 10 months ago

Commit 73d93531 parent 17dbe8d88 files · +2275 −1813Browse files

Showing the changes to crates/buffer_diff/src/buffer_diff.rs (1 of 88 files). Show all

Unified · Split

crates/buffer_diff/src/buffer_diff.rs+34−42
@@ -1,22 +1,16 @@
11 use futures::channel::oneshot;
22 use git2::{DiffLineType as GitDiffLineType, DiffOptions as GitOptions, Patch as GitPatch};
3−use gpui::{App, AppContext as _, Context, Entity, EventEmitter, Task, TaskLabel};
3+use gpui::{App, AppContext as _, Context, Entity, EventEmitter, Task};
44 use language::{
55 BufferRow, Capability, DiffOptions, File, Language, LanguageName, LanguageRegistry,
66 language_settings::language_settings, word_diff_ranges,
77 };
88 use rope::Rope;
9−use std::{
10− cmp::Ordering,
11− iter,
12− ops::Range,
13− sync::{Arc, LazyLock},
14−};
9+use std::{cmp::Ordering, future::Future, iter, ops::Range, sync::Arc};
1510 use sum_tree::SumTree;
1611 use text::{Anchor, Bias, BufferId, OffsetRangeExt, Point, ToOffset as _, ToPoint as _};
1712 use util::ResultExt;
1813
19−pub static CALCULATE_DIFF_TASK: LazyLock<TaskLabel> = LazyLock::new(TaskLabel::new);
2014 pub const MAX_WORD_DIFF_LINE_COUNT: usize = 5;
2115
2216 pub struct BufferDiff {
@@ -1138,10 +1132,9 @@ impl BufferDiff { · 1115 unmodified lines
11381132 cx: &mut Context<Self>,
11391133 ) -> Self {
11401134 let mut this = BufferDiff::new(&buffer, cx);
1141− let executor = cx.background_executor().clone();
11421135 let mut base_text = base_text.to_owned();
11431136 text::LineEnding::normalize(&mut base_text);
1144− let inner = executor.block(this.update_diff(
1137+ let inner = cx.foreground_executor().block_on(this.update_diff(
11451138 buffer.clone(),
11461139 Some(Arc::from(base_text)),
11471140 true,
@@ -1254,37 +1247,36 @@ impl BufferDiff { · 106 unmodified lines
12541247 cx,
12551248 );
12561249
1257− cx.background_executor()
1258− .spawn_labeled(*CALCULATE_DIFF_TASK, async move {
1259− let base_text_rope = if let Some(base_text) = &base_text {
1260− if base_text_changed {
1261− Rope::from(base_text.as_ref())
1262− } else {
1263− prev_base_text
1264− }
1250+ cx.background_executor().spawn(async move {
1251+ let base_text_rope = if let Some(base_text) = &base_text {
1252+ if base_text_changed {
1253+ Rope::from(base_text.as_ref())
12651254 } else {
1266− Rope::new()
1267− };
1268− let base_text_exists = base_text.is_some();
1269− let hunks = compute_hunks(
1270− base_text
1271− .clone()
1272− .map(|base_text| (base_text, base_text_rope.clone())),
1273− buffer.clone(),
1274− diff_options,
1275− );
1276− let base_text = base_text.unwrap_or_default();
1277− let inner = BufferDiffInner {
1278− base_text,
1279− hunks,
1280− base_text_exists,
1281− pending_hunks: SumTree::new(&buffer),
1282− };
1283− BufferDiffUpdate {
1284− inner,
1285− base_text_changed,
1255+ prev_base_text
12861256 }
1287− })
1257+ } else {
1258+ Rope::new()
1259+ };
1260+ let base_text_exists = base_text.is_some();
1261+ let hunks = compute_hunks(
1262+ base_text
1263+ .clone()
1264+ .map(|base_text| (base_text, base_text_rope.clone())),
1265+ buffer.clone(),
1266+ diff_options,
1267+ );
1268+ let base_text = base_text.unwrap_or_default();
1269+ let inner = BufferDiffInner {
1270+ base_text,
1271+ hunks,
1272+ base_text_exists,
1273+ pending_hunks: SumTree::new(&buffer),
1274+ };
1275+ BufferDiffUpdate {
1276+ inner,
1277+ base_text_changed,
1278+ }
1279+ })
12881280 }
12891281
12901282 pub fn language_changed(
@@ -1503,10 +1495,10 @@ impl BufferDiff { · 212 unmodified lines
15031495 let language = self.base_text(cx).language().cloned();
15041496 let base_text = self.base_text_string(cx).map(|s| s.as_str().into());
15051497 let fut = self.update_diff(buffer.clone(), base_text, false, language, cx);
1506− let executor = cx.background_executor().clone();
1507− let snapshot = executor.block(fut);
1498+ let fg_executor = cx.foreground_executor().clone();
1499+ let snapshot = fg_executor.block_on(fut);
15081500 let fut = self.set_snapshot_with_secondary_inner(snapshot, buffer, None, false, cx);
1509− let (changed_range, base_text_changed_range) = executor.block(fut);
1501+ let (changed_range, base_text_changed_range) = fg_executor.block_on(fut);
15101502 cx.emit(BufferDiffEvent::DiffChanged {
15111503 changed_range,
15121504 base_text_changed_range,

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t