Compare commits
4 Commits
performanc
...
perf/proje
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83357cd96a | ||
|
|
be9bb2f11a | ||
|
|
285965ffa8 | ||
|
|
408887eeed |
@@ -1,6 +1,6 @@
|
||||
[build]
|
||||
# v0 mangling scheme provides more detailed backtraces around closures
|
||||
rustflags = ["-C", "symbol-mangling-version=v0", "--cfg", "tokio_unstable"]
|
||||
rustflags = ["-C", "symbol-mangling-version=v0", "-C", "force-frame-pointers=yes", "--cfg", "tokio_unstable"]
|
||||
|
||||
[alias]
|
||||
xtask = "run --package xtask --"
|
||||
@@ -8,6 +8,14 @@ perf-test = ["test", "--profile", "release-fast", "--lib", "--bins", "--tests",
|
||||
# Keep similar flags here to share some ccache
|
||||
perf-compare = ["run", "--profile", "release-fast", "-p", "perf", "--config", "target.'cfg(true)'.rustflags=[\"--cfg\", \"perf_enabled\"]", "--", "compare"]
|
||||
|
||||
# [target.x86_64-unknown-linux-gnu]
|
||||
# linker = "clang"
|
||||
# rustflags = ["-C", "link-arg=-fuse-ld=mold"]
|
||||
|
||||
[target.aarch64-unknown-linux-gnu]
|
||||
linker = "clang"
|
||||
rustflags = ["-C", "link-arg=-fuse-ld=mold"]
|
||||
|
||||
[target.'cfg(target_os = "windows")']
|
||||
rustflags = [
|
||||
"--cfg",
|
||||
@@ -16,5 +24,8 @@ rustflags = [
|
||||
"target-feature=+crt-static", # This fixes the linking issue when compiling livekit on Windows
|
||||
]
|
||||
|
||||
[target.'cfg(target_os = "macos")']
|
||||
rustflags = ["-C", "split-debuginfo=packed"]
|
||||
|
||||
[env]
|
||||
MACOSX_DEPLOYMENT_TARGET = "10.15.7"
|
||||
|
||||
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -10029,6 +10029,7 @@ name = "miniprofiler_ui"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"gpui",
|
||||
"log",
|
||||
"serde_json",
|
||||
"smol",
|
||||
"util",
|
||||
|
||||
@@ -859,7 +859,7 @@ ui_input = { codegen-units = 1 }
|
||||
zed_actions = { codegen-units = 1 }
|
||||
|
||||
[profile.release]
|
||||
debug = "limited"
|
||||
debug = "full"
|
||||
lto = "thin"
|
||||
codegen-units = 1
|
||||
|
||||
|
||||
@@ -17830,11 +17830,6 @@ async fn test_on_type_formatting_is_applied_after_autoindent(cx: &mut TestAppCon
|
||||
)
|
||||
.await;
|
||||
|
||||
cx.update_buffer(|buffer, _| {
|
||||
// This causes autoindent to be async.
|
||||
buffer.set_sync_parse_timeout(Duration::ZERO)
|
||||
});
|
||||
|
||||
cx.set_state("fn c() {\n d()ˇ\n}\n");
|
||||
cx.simulate_keystroke("\n");
|
||||
cx.run_until_parked();
|
||||
|
||||
@@ -7,12 +7,14 @@ use crate::{
|
||||
use anyhow::{Context as _, Result, anyhow};
|
||||
use buffer_diff::{BufferDiff, DiffHunkSecondaryStatus};
|
||||
use collections::{HashMap, HashSet};
|
||||
use db::smol::stream::StreamExt;
|
||||
use editor::{
|
||||
Addon, Editor, EditorEvent, SelectionEffects,
|
||||
actions::{GoToHunk, GoToPreviousHunk},
|
||||
multibuffer_context_lines,
|
||||
scroll::Autoscroll,
|
||||
};
|
||||
use futures::{FutureExt, stream::FuturesUnordered};
|
||||
use git::{
|
||||
Commit, StageAll, StageAndNext, ToggleStaged, UnstageAll, UnstageAndNext,
|
||||
repository::{Branch, RepoPath, Upstream, UpstreamTracking, UpstreamTrackingStatus},
|
||||
@@ -27,7 +29,7 @@ use multi_buffer::{MultiBuffer, PathKey};
|
||||
use project::{
|
||||
Project, ProjectPath,
|
||||
git_store::{
|
||||
Repository,
|
||||
self, Repository,
|
||||
branch_diff::{self, BranchDiffEvent, DiffBase},
|
||||
},
|
||||
};
|
||||
@@ -37,7 +39,7 @@ use std::ops::Range;
|
||||
use std::sync::Arc;
|
||||
use theme::ActiveTheme;
|
||||
use ui::{KeyBinding, Tooltip, prelude::*, vertical_divider};
|
||||
use util::{ResultExt as _, rel_path::RelPath};
|
||||
use util::{ResultExt, rel_path::RelPath};
|
||||
use workspace::{
|
||||
CloseActiveItem, ItemNavHistory, SerializableItem, ToolbarItemEvent, ToolbarItemLocation,
|
||||
ToolbarItemView, Workspace,
|
||||
@@ -551,7 +553,7 @@ impl ProjectDiff {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn refresh(this: WeakEntity<Self>, cx: &mut AsyncWindowContext) -> Result<()> {
|
||||
pub async fn old_refresh(this: WeakEntity<Self>, cx: &mut AsyncWindowContext) -> Result<()> {
|
||||
let mut path_keys = Vec::new();
|
||||
let buffers_to_load = this.update(cx, |this, cx| {
|
||||
let (repo, buffers_to_load) = this.branch_diff.update(cx, |branch_diff, cx| {
|
||||
@@ -600,6 +602,98 @@ impl ProjectDiff {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn refresh(this: WeakEntity<Self>, cx: &mut AsyncWindowContext) -> Result<()> {
|
||||
use git_store::branch_diff::BranchDiff;
|
||||
let Some(this) = this.upgrade() else {
|
||||
return Ok(());
|
||||
};
|
||||
let multibuffer = cx.read_entity(&this, |this, _| this.multibuffer.clone())?;
|
||||
let branch_diff = cx.read_entity(&this, |pd, _| pd.branch_diff.clone())?;
|
||||
|
||||
let Some(repo) = cx.read_entity(&branch_diff, |bd, _| bd.repo.clone())? else {
|
||||
return Ok(());
|
||||
};
|
||||
let project = cx.read_entity(&branch_diff, |bd, _| bd.project.clone())?;
|
||||
|
||||
let cached_status: Vec<git_store::StatusEntry> =
|
||||
cx.read_entity(&repo, |repo: &Repository, _| repo.cached_status().collect())?;
|
||||
|
||||
let mut previous_paths =
|
||||
cx.read_entity(&multibuffer, |mb, _| mb.paths().collect::<HashSet<_>>())?;
|
||||
|
||||
// Idea: on click in git panel prioritize task for that file in some way ...
|
||||
// could have a hashmap of futures here
|
||||
// - needs to prioritize *some* background tasks over others
|
||||
// -
|
||||
let mut tasks = FuturesUnordered::new();
|
||||
let mut seen = HashSet::default();
|
||||
for entry in cached_status {
|
||||
seen.insert(entry.repo_path.clone());
|
||||
let tree_diff_status = cx.read_entity(&branch_diff, |branch_diff, _| {
|
||||
branch_diff
|
||||
.tree_diff
|
||||
.as_ref()
|
||||
.and_then(|t| t.entries.get(&entry.repo_path))
|
||||
.cloned()
|
||||
})?;
|
||||
|
||||
let Some(status) = cx.read_entity(&branch_diff, |bd, _| {
|
||||
bd.merge_statuses(Some(entry.status), tree_diff_status.as_ref())
|
||||
})?
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
if !status.has_changes() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let Some(project_path) = cx.read_entity(&repo, |repo, cx| {
|
||||
repo.repo_path_to_project_path(&entry.repo_path, cx)
|
||||
})?
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let sort_prefix = cx.read_entity(&repo, |repo, cx| {
|
||||
sort_prefix(repo, &entry.repo_path, entry.status, cx)
|
||||
})?;
|
||||
|
||||
let path_key = PathKey::with_sort_prefix(sort_prefix, entry.repo_path.into_arc());
|
||||
previous_paths.remove(&path_key);
|
||||
|
||||
let repo = repo.clone();
|
||||
let task = project.update(cx, move |_, cx| {
|
||||
BranchDiff::load_buffer(tree_diff_status, project_path, repo, cx)
|
||||
.map(move |res| (res, path_key, entry.status))
|
||||
})?;
|
||||
|
||||
tasks.push(task)
|
||||
}
|
||||
|
||||
// remove anything not part of the diff in the multibuffer
|
||||
this.update(cx, |this, cx| {
|
||||
multibuffer.update(cx, |multibuffer, cx| {
|
||||
for path in previous_paths {
|
||||
this.buffer_diff_subscriptions.remove(&path.path);
|
||||
multibuffer.remove_excerpts_for_path(path, cx);
|
||||
}
|
||||
});
|
||||
})?;
|
||||
|
||||
// add the new buffers as they are parsed
|
||||
while let Some((res, path_key, file_status)) = tasks.next().await {
|
||||
if let Some((buffer, diff)) = res.log_err() {
|
||||
cx.update(|window, cx| {
|
||||
this.update(cx, |this, cx| {
|
||||
this.register_buffer(path_key, file_status, buffer, diff, window, cx)
|
||||
});
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn excerpt_paths(&self, cx: &App) -> Vec<std::sync::Arc<util::rel_path::RelPath>> {
|
||||
self.multibuffer
|
||||
|
||||
@@ -107,7 +107,6 @@ pub struct Buffer {
|
||||
autoindent_requests: Vec<Arc<AutoindentRequest>>,
|
||||
wait_for_autoindent_txs: Vec<oneshot::Sender<()>>,
|
||||
pending_autoindent: Option<Task<()>>,
|
||||
sync_parse_timeout: Duration,
|
||||
syntax_map: Mutex<SyntaxMap>,
|
||||
reparse: Option<Task<()>>,
|
||||
parse_status: (watch::Sender<ParseStatus>, watch::Receiver<ParseStatus>),
|
||||
@@ -989,7 +988,6 @@ impl Buffer {
|
||||
syntax_map,
|
||||
reparse: None,
|
||||
non_text_state_update_count: 0,
|
||||
sync_parse_timeout: Duration::from_millis(1),
|
||||
parse_status: watch::channel(ParseStatus::Idle),
|
||||
autoindent_requests: Default::default(),
|
||||
wait_for_autoindent_txs: Default::default(),
|
||||
@@ -1509,11 +1507,6 @@ impl Buffer {
|
||||
self.syntax_map.lock().contains_unknown_injections()
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn set_sync_parse_timeout(&mut self, timeout: Duration) {
|
||||
self.sync_parse_timeout = timeout;
|
||||
}
|
||||
|
||||
/// Called after an edit to synchronize the buffer's main parse tree with
|
||||
/// the buffer's new underlying state.
|
||||
///
|
||||
@@ -1566,43 +1559,32 @@ impl Buffer {
|
||||
});
|
||||
|
||||
self.parse_status.0.send(ParseStatus::Parsing).unwrap();
|
||||
match cx
|
||||
.background_executor()
|
||||
.block_with_timeout(self.sync_parse_timeout, parse_task)
|
||||
{
|
||||
Ok(new_syntax_snapshot) => {
|
||||
self.did_finish_parsing(new_syntax_snapshot, cx);
|
||||
self.reparse = None;
|
||||
}
|
||||
Err(parse_task) => {
|
||||
// todo(lw): hot foreground spawn
|
||||
self.reparse = Some(cx.spawn(async move |this, cx| {
|
||||
let new_syntax_map = cx.background_spawn(parse_task).await;
|
||||
this.update(cx, move |this, cx| {
|
||||
let grammar_changed = || {
|
||||
this.language.as_ref().is_none_or(|current_language| {
|
||||
!Arc::ptr_eq(&language, current_language)
|
||||
})
|
||||
};
|
||||
let language_registry_changed = || {
|
||||
new_syntax_map.contains_unknown_injections()
|
||||
&& language_registry.is_some_and(|registry| {
|
||||
registry.version() != new_syntax_map.language_registry_version()
|
||||
})
|
||||
};
|
||||
let parse_again = this.version.changed_since(&parsed_version)
|
||||
|| language_registry_changed()
|
||||
|| grammar_changed();
|
||||
this.did_finish_parsing(new_syntax_map, cx);
|
||||
this.reparse = None;
|
||||
if parse_again {
|
||||
this.reparse(cx);
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
}));
|
||||
}
|
||||
}
|
||||
// todo(lw): hot foreground spawn
|
||||
self.reparse = Some(cx.spawn(async move |this, cx| {
|
||||
let new_syntax_map = cx.background_spawn(parse_task).await;
|
||||
this.update(cx, move |this, cx| {
|
||||
let grammar_changed = || {
|
||||
this.language
|
||||
.as_ref()
|
||||
.is_none_or(|current_language| !Arc::ptr_eq(&language, current_language))
|
||||
};
|
||||
let language_registry_changed = || {
|
||||
new_syntax_map.contains_unknown_injections()
|
||||
&& language_registry.is_some_and(|registry| {
|
||||
registry.version() != new_syntax_map.language_registry_version()
|
||||
})
|
||||
};
|
||||
let parse_again = this.version.changed_since(&parsed_version)
|
||||
|| language_registry_changed()
|
||||
|| grammar_changed();
|
||||
this.did_finish_parsing(new_syntax_map, cx);
|
||||
this.reparse = None;
|
||||
if parse_again {
|
||||
this.reparse(cx);
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
}));
|
||||
}
|
||||
|
||||
fn did_finish_parsing(&mut self, syntax_snapshot: SyntaxSnapshot, cx: &mut Context<Self>) {
|
||||
|
||||
@@ -622,10 +622,6 @@ async fn test_reparse(cx: &mut gpui::TestAppContext) {
|
||||
)
|
||||
);
|
||||
|
||||
buffer.update(cx, |buffer, _| {
|
||||
buffer.set_sync_parse_timeout(Duration::ZERO)
|
||||
});
|
||||
|
||||
// Perform some edits (add parameter and variable reference)
|
||||
// Parsing doesn't begin until the transaction is complete
|
||||
buffer.update(cx, |buf, cx| {
|
||||
@@ -734,11 +730,7 @@ async fn test_reparse(cx: &mut gpui::TestAppContext) {
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_resetting_language(cx: &mut gpui::TestAppContext) {
|
||||
let buffer = cx.new(|cx| {
|
||||
let mut buffer = Buffer::local("{}", cx).with_language(Arc::new(rust_lang()), cx);
|
||||
buffer.set_sync_parse_timeout(Duration::ZERO);
|
||||
buffer
|
||||
});
|
||||
let buffer = cx.new(|cx| Buffer::local("{}", cx).with_language(Arc::new(rust_lang()), cx));
|
||||
|
||||
// Wait for the initial text to parse
|
||||
cx.executor().run_until_parked();
|
||||
@@ -2216,9 +2208,6 @@ async fn test_async_autoindents_preserve_preview(cx: &mut TestAppContext) {
|
||||
let text = "fn a() {}";
|
||||
let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
|
||||
|
||||
// This causes autoindent to be async.
|
||||
buffer.set_sync_parse_timeout(Duration::ZERO);
|
||||
|
||||
buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
|
||||
buffer.refresh_preview();
|
||||
|
||||
|
||||
@@ -1306,6 +1306,7 @@ fn parse_text(
|
||||
parser.set_included_ranges(ranges)?;
|
||||
parser.set_language(&grammar.ts_language)?;
|
||||
parser
|
||||
// TODO JK hotspot
|
||||
.parse_with_options(
|
||||
&mut move |offset, _| {
|
||||
chunks.seek(start_byte + offset);
|
||||
|
||||
@@ -18,6 +18,7 @@ workspace.workspace = true
|
||||
util.workspace = true
|
||||
serde_json.workspace = true
|
||||
smol.workspace = true
|
||||
log.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
gpui = { workspace = true, features = ["test-support"] }
|
||||
|
||||
@@ -6,9 +6,9 @@ use std::{
|
||||
|
||||
use gpui::{
|
||||
App, AppContext, Context, Entity, Hsla, InteractiveElement, IntoElement, ParentElement, Render,
|
||||
ScrollHandle, SerializedTaskTiming, StatefulInteractiveElement, Styled, Task, TaskTiming,
|
||||
TitlebarOptions, WindowBounds, WindowHandle, WindowOptions, div, prelude::FluentBuilder, px,
|
||||
relative, size,
|
||||
ScrollHandle, SerializedThreadTaskTimings, StatefulInteractiveElement, Styled, Task,
|
||||
TaskTiming, ThreadTaskTimings, TitlebarOptions, WindowBounds, WindowHandle, WindowOptions, div,
|
||||
prelude::FluentBuilder, px, relative, size,
|
||||
};
|
||||
use util::ResultExt;
|
||||
use workspace::{
|
||||
@@ -287,8 +287,17 @@ impl Render for ProfilerWindow {
|
||||
let Some(data) = this.get_timings() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let timings = ThreadTaskTimings {
|
||||
thread_name: Some("main".to_string()),
|
||||
thread_id: std::thread::current().id(),
|
||||
timings: data.clone(),
|
||||
};
|
||||
let timings =
|
||||
SerializedTaskTiming::convert(this.startup_time, &data);
|
||||
Vec::from([SerializedThreadTaskTimings::convert(
|
||||
this.startup_time,
|
||||
timings,
|
||||
)]);
|
||||
|
||||
let active_path = workspace
|
||||
.read_with(cx, |workspace, cx| {
|
||||
@@ -305,12 +314,17 @@ impl Render for ProfilerWindow {
|
||||
);
|
||||
|
||||
cx.background_spawn(async move {
|
||||
let path = path.await;
|
||||
let path =
|
||||
path.log_err().and_then(|p| p.log_err()).flatten();
|
||||
|
||||
let Some(path) = path else {
|
||||
return;
|
||||
let path = match path.await.log_err() {
|
||||
Some(Ok(Some(path))) => path,
|
||||
Some(e @ Err(_)) => {
|
||||
e.log_err();
|
||||
log::warn!("Saving miniprof in workingdir");
|
||||
std::path::Path::new(
|
||||
"performance_profile.miniprof",
|
||||
)
|
||||
.to_path_buf()
|
||||
}
|
||||
Some(Ok(None)) | None => return,
|
||||
};
|
||||
|
||||
let Some(timings) =
|
||||
|
||||
@@ -34,11 +34,11 @@ impl DiffBase {
|
||||
|
||||
pub struct BranchDiff {
|
||||
diff_base: DiffBase,
|
||||
repo: Option<Entity<Repository>>,
|
||||
project: Entity<Project>,
|
||||
pub repo: Option<Entity<Repository>>,
|
||||
pub project: Entity<Project>,
|
||||
base_commit: Option<SharedString>,
|
||||
head_commit: Option<SharedString>,
|
||||
tree_diff: Option<TreeDiff>,
|
||||
pub tree_diff: Option<TreeDiff>,
|
||||
_subscription: Subscription,
|
||||
update_needed: postage::watch::Sender<()>,
|
||||
_task: Task<()>,
|
||||
@@ -318,7 +318,7 @@ impl BranchDiff {
|
||||
output
|
||||
}
|
||||
|
||||
fn load_buffer(
|
||||
pub fn load_buffer(
|
||||
branch_diff: Option<git::status::TreeDiffStatus>,
|
||||
project_path: crate::ProjectPath,
|
||||
repo: Entity<Repository>,
|
||||
|
||||
@@ -13,6 +13,32 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
// https://docs.rs/tokio/latest/src/tokio/task/yield_now.rs.html#39-64
|
||||
pub async fn yield_now() {
|
||||
/// Yield implementation
|
||||
struct YieldNow {
|
||||
yielded: bool,
|
||||
}
|
||||
|
||||
impl Future for YieldNow {
|
||||
type Output = ();
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
|
||||
// use core::task::ready;
|
||||
// ready!(crate::trace::trace_leaf(cx));
|
||||
if self.yielded {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
|
||||
self.yielded = true;
|
||||
// context::defer(cx.waker());
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
YieldNow { yielded: false }.await;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ForegroundExecutor {
|
||||
session_id: SessionId,
|
||||
|
||||
Reference in New Issue
Block a user