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 @@
1use futures::channel::oneshot;1use futures::channel::oneshot;
2use git2::{DiffLineType as GitDiffLineType, DiffOptions as GitOptions, Patch as GitPatch};2use git2::{DiffLineType as GitDiffLineType, DiffOptions as GitOptions, Patch as GitPatch};
3use gpui::{App, AppContext as _, Context, Entity, EventEmitter, Task, TaskLabel};3use gpui::{App, AppContext as _, Context, Entity, EventEmitter, Task};
4use language::{4use language::{
5 BufferRow, Capability, DiffOptions, File, Language, LanguageName, LanguageRegistry,5 BufferRow, Capability, DiffOptions, File, Language, LanguageName, LanguageRegistry,
6 language_settings::language_settings, word_diff_ranges,6 language_settings::language_settings, word_diff_ranges,
7};7};
8use rope::Rope;8use rope::Rope;
9use std::{9use std::{cmp::Ordering, future::Future, iter, ops::Range, sync::Arc};
10 cmp::Ordering,
11 iter,
12 ops::Range,
13 sync::{Arc, LazyLock},
14};
15use sum_tree::SumTree;10use sum_tree::SumTree;
16use text::{Anchor, Bias, BufferId, OffsetRangeExt, Point, ToOffset as _, ToPoint as _};11use text::{Anchor, Bias, BufferId, OffsetRangeExt, Point, ToOffset as _, ToPoint as _};
17use util::ResultExt;12use util::ResultExt;
18 13
19pub static CALCULATE_DIFF_TASK: LazyLock<TaskLabel> = LazyLock::new(TaskLabel::new);
20pub const MAX_WORD_DIFF_LINE_COUNT: usize = 5;14pub const MAX_WORD_DIFF_LINE_COUNT: usize = 5;
21 15
22pub struct BufferDiff {16pub struct BufferDiff {
@@ -1138,10 +1132,9 @@ impl BufferDiff { · 1115 unmodified lines
1138 cx: &mut Context<Self>,1132 cx: &mut Context<Self>,
1139 ) -> Self {1133 ) -> Self {
1140 let mut this = BufferDiff::new(&buffer, cx);1134 let mut this = BufferDiff::new(&buffer, cx);
1141 let executor = cx.background_executor().clone();
1142 let mut base_text = base_text.to_owned();1135 let mut base_text = base_text.to_owned();
1143 text::LineEnding::normalize(&mut base_text);1136 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(
1145 buffer.clone(),1138 buffer.clone(),
1146 Some(Arc::from(base_text)),1139 Some(Arc::from(base_text)),
1147 true,1140 true,
@@ -1254,37 +1247,36 @@ impl BufferDiff { · 106 unmodified lines
1254 cx,1247 cx,
1255 );1248 );
1256 1249
1257 cx.background_executor()1250 cx.background_executor().spawn(async move {
1258 .spawn_labeled(*CALCULATE_DIFF_TASK, async move {1251 let base_text_rope = if let Some(base_text) = &base_text {
1259 let base_text_rope = if let Some(base_text) = &base_text {1252 if base_text_changed {
1260 if base_text_changed {1253 Rope::from(base_text.as_ref())
1261 Rope::from(base_text.as_ref())
1262 } else {
1263 prev_base_text
1264 }
1265 } else {1254 } else {
1266 Rope::new()1255 prev_base_text
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,
1286 }1256 }
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 })
1288 }1280 }
1289 1281
1290 pub fn language_changed(1282 pub fn language_changed(
@@ -1503,10 +1495,10 @@ impl BufferDiff { · 212 unmodified lines
1503 let language = self.base_text(cx).language().cloned();1495 let language = self.base_text(cx).language().cloned();
1504 let base_text = self.base_text_string(cx).map(|s| s.as_str().into());1496 let base_text = self.base_text_string(cx).map(|s| s.as_str().into());
1505 let fut = self.update_diff(buffer.clone(), base_text, false, language, cx);1497 let fut = self.update_diff(buffer.clone(), base_text, false, language, cx);
1506 let executor = cx.background_executor().clone();1498 let fg_executor = cx.foreground_executor().clone();
1507 let snapshot = executor.block(fut);1499 let snapshot = fg_executor.block_on(fut);
1508 let fut = self.set_snapshot_with_secondary_inner(snapshot, buffer, None, false, cx);1500 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);
1510 cx.emit(BufferDiffEvent::DiffChanged {1502 cx.emit(BufferDiffEvent::DiffChanged {
1511 changed_range,1503 changed_range,
1512 base_text_changed_range,1504 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