Skip to content

Commit 231824a

Browse files
committed
perf: parallelize LSP servers and remove warmup wait
1 parent 3554459 commit 231824a

1 file changed

Lines changed: 61 additions & 109 deletions

File tree

src/code/lsp.rs

Lines changed: 61 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,46 +1187,6 @@ impl AsyncLspClient {
11871187
Ok(Some(content))
11881188
}
11891189

1190-
async fn wait_for_ready(&self, _path: &Path, _max_attempts: u32, server_name: &str) -> bool {
1191-
debug!(server = %server_name, "waiting for LSP to be ready via progress tracking");
1192-
1193-
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
1194-
1195-
for _ in 0..60 {
1196-
let progress_count = {
1197-
let progress = self.inner.active_progress.lock().await;
1198-
progress.len()
1199-
};
1200-
1201-
if progress_count == 0 {
1202-
debug!(server = %server_name, "LSP ready (no active progress)");
1203-
return true;
1204-
}
1205-
1206-
trace!(server = %server_name, active = progress_count, "waiting for progress to complete");
1207-
1208-
let timeout = tokio::time::timeout(
1209-
std::time::Duration::from_secs(2),
1210-
self.inner.progress_notify.notified(),
1211-
)
1212-
.await;
1213-
1214-
if timeout.is_ok() {
1215-
let remaining = {
1216-
let progress = self.inner.active_progress.lock().await;
1217-
progress.len()
1218-
};
1219-
if remaining == 0 {
1220-
debug!(server = %server_name, "LSP ready (progress complete)");
1221-
return true;
1222-
}
1223-
}
1224-
}
1225-
1226-
warn!(server = %server_name, "LSP wait timeout, proceeding anyway");
1227-
true
1228-
}
1229-
12301190
async fn shutdown(&self) -> Result<()> {
12311191
let _ = self.send_request("shutdown", json!(null)).await;
12321192
let _ = self.send_notification("exit", json!(null)).await;
@@ -1373,6 +1333,10 @@ impl AsyncLspResolver {
13731333
.push((i, *call, abs_path, content));
13741334
}
13751335

1336+
type TaskHandle = tokio::task::JoinHandle<(usize, String, Option<lsp_types::Location>, Option<String>, Option<String>, String)>;
1337+
let mut all_handles: Vec<TaskHandle> = Vec::new();
1338+
let global_semaphore = Arc::new(tokio::sync::Semaphore::new(concurrency));
1339+
13761340
for (server_name, server_calls) in requests_by_server {
13771341
let ext = match server_calls.first() {
13781342
Some((_, call, _, _)) => call
@@ -1429,22 +1393,9 @@ impl AsyncLspResolver {
14291393
.fetch_add(def_file_count, Ordering::Relaxed);
14301394

14311395
if !is_ready(&client) {
1432-
if let Some((_, _, abs_path, _)) = server_calls.first() {
1433-
let t_ready = Instant::now();
1434-
let ready = client.wait_for_ready(abs_path, 60, &server_name).await;
1435-
self.timing
1436-
.add_wait_ready(t_ready.elapsed().as_millis() as u64);
1437-
set_ready(&client, true);
1438-
if !ready {
1439-
debug!(server = %server_name, "LSP not ready, continuing anyway");
1440-
}
1441-
}
1396+
set_ready(&client, true);
14421397
}
14431398

1444-
let semaphore = Arc::new(tokio::sync::Semaphore::new(concurrency));
1445-
1446-
let mut handles = Vec::new();
1447-
14481399
for (call_idx, call, abs_path, content) in server_calls {
14491400
let lines: Vec<&str> = content.lines().collect();
14501401
let start_line_idx = call.span.start_line.saturating_sub(1);
@@ -1456,16 +1407,17 @@ impl AsyncLspResolver {
14561407
let line_content = lines[start_line_idx];
14571408
let col = line_content.find(&call.callee).unwrap_or(0) as u32;
14581409

1459-
let permit = semaphore.clone().acquire_owned().await.unwrap();
1410+
let semaphore = global_semaphore.clone();
14601411
let client_clone = client.clone();
14611412
let abs_path_clone = abs_path.clone();
14621413
let callee = call.callee.clone();
14631414
let qualifier = call.qualifier.clone();
14641415
let line_content_owned = line_content.to_string();
14651416
let timing = self.timing.clone();
1417+
let server_name_clone = server_name.clone();
14661418

14671419
let handle = tokio::spawn(async move {
1468-
let _permit = permit;
1420+
let _permit = semaphore.acquire_owned().await.unwrap();
14691421

14701422
let (signature, receiver_type) = if skip_hover {
14711423
(None, None)
@@ -1557,72 +1509,72 @@ impl AsyncLspResolver {
15571509
}
15581510
}
15591511

1560-
(call_idx, callee, location, signature, receiver_type)
1512+
(call_idx, callee, location, signature, receiver_type, server_name_clone)
15611513
});
15621514

1563-
handles.push(handle);
1515+
all_handles.push(handle);
15641516
}
1517+
}
15651518

1566-
for handle in handles {
1567-
if let Ok((call_idx, callee, location, signature, receiver_type)) = handle.await {
1568-
let location = match location {
1569-
Some(loc) => loc,
1570-
None => {
1571-
trace!(callee = %callee, "no definition found");
1572-
self.get_server_stats(&server_name).no_definition += 1;
1573-
continue;
1574-
}
1575-
};
1519+
for handle in all_handles {
1520+
if let Ok((call_idx, callee, location, signature, receiver_type, server_name)) = handle.await {
1521+
let location = match location {
1522+
Some(loc) => loc,
1523+
None => {
1524+
trace!(callee = %callee, "no definition found");
1525+
self.get_server_stats(&server_name).no_definition += 1;
1526+
continue;
1527+
}
1528+
};
15761529

1577-
let def_path = match uri_to_path(&location.uri) {
1578-
Some(p) => p,
1579-
None => continue,
1580-
};
1530+
let def_path = match uri_to_path(&location.uri) {
1531+
Some(p) => p,
1532+
None => continue,
1533+
};
15811534

1582-
let rel_path = match def_path.strip_prefix(&self.root) {
1583-
Ok(p) => p.to_path_buf(),
1584-
Err(_) => {
1585-
trace!(callee = %callee, path = %def_path.display(), "definition is external");
1586-
self.get_server_stats(&server_name).external += 1;
1587-
continue;
1588-
}
1589-
};
1535+
let rel_path = match def_path.strip_prefix(&self.root) {
1536+
Ok(p) => p.to_path_buf(),
1537+
Err(_) => {
1538+
trace!(callee = %callee, path = %def_path.display(), "definition is external");
1539+
self.get_server_stats(&server_name).external += 1;
1540+
continue;
1541+
}
1542+
};
15901543

1591-
let start_line = location.range.start.line as usize + 1;
1592-
let end_line = location.range.end.line as usize + 1;
1544+
let start_line = location.range.start.line as usize + 1;
1545+
let end_line = location.range.end.line as usize + 1;
1546+
1547+
let record = match index.get(&rel_path) {
1548+
Some(r) => r,
1549+
None => {
1550+
trace!(callee = %callee, path = %rel_path.display(), "definition file not indexed");
1551+
self.get_server_stats(&server_name).not_indexed += 1;
1552+
continue;
1553+
}
1554+
};
15931555

1594-
let record = match index.get(&rel_path) {
1595-
Some(r) => r,
1556+
let def =
1557+
match record.definitions.iter().find(|d| {
1558+
d.span.start_line <= start_line && d.span.end_line >= end_line
1559+
}) {
1560+
Some(d) => d,
15961561
None => {
1597-
trace!(callee = %callee, path = %rel_path.display(), "definition file not indexed");
1598-
self.get_server_stats(&server_name).not_indexed += 1;
1562+
self.get_server_stats(&server_name).no_match += 1;
15991563
continue;
16001564
}
16011565
};
16021566

1603-
let def =
1604-
match record.definitions.iter().find(|d| {
1605-
d.span.start_line <= start_line && d.span.end_line >= end_line
1606-
}) {
1607-
Some(d) => d,
1608-
None => {
1609-
self.get_server_stats(&server_name).no_match += 1;
1610-
continue;
1611-
}
1612-
};
1613-
1614-
self.get_server_stats(&server_name).resolved += 1;
1615-
results.push((
1616-
call_idx,
1617-
ResolvedCall {
1618-
target_file: rel_path,
1619-
target_name: def.name.clone(),
1620-
target_span: def.span.clone(),
1621-
signature,
1622-
receiver_type,
1623-
},
1624-
));
1625-
}
1567+
self.get_server_stats(&server_name).resolved += 1;
1568+
results.push((
1569+
call_idx,
1570+
ResolvedCall {
1571+
target_file: rel_path,
1572+
target_name: def.name.clone(),
1573+
target_span: def.span.clone(),
1574+
signature,
1575+
receiver_type,
1576+
},
1577+
));
16261578
}
16271579
}
16281580

0 commit comments

Comments
 (0)