Skip to content

Commit d6d3766

Browse files
feat: add command to profile the entire server (#1438)
* feat: declare and bind tinymist.profileServer command * feat: editor bridge with the frontend * feat: start and stop server profiling * feat: add profile-server prototype (#1440) * Add profile-server prototype * fix: use branch --------- Co-authored-by: Myriad-Dreamin <camiyoru@gmail.com> * feat: make it good * build: update cargo.lock * dev: ls profile impl and hook * test: update snapshot --------- Co-authored-by: Derived Cat <hooyuser@outlook.com>
1 parent 890ecd9 commit d6d3766

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+857
-297
lines changed

Cargo.lock

Lines changed: 150 additions & 151 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ reflexo-vec2svg = { version = "=0.6.0-rc1" }
137137
typst = "0.13.1"
138138
typst-html = "0.13.1"
139139
typst-library = "0.13.1"
140+
typst-macros = "0.13.1"
140141
typst-timing = "0.13.1"
141142
typst-svg = "0.13.1"
142143
typst-render = "0.13.1"
@@ -266,6 +267,7 @@ extend-exclude = ["/.git", "fixtures"]
266267
#
267268
# A regular build MUST use `tag` or `rev` to specify the version of the patched crate to ensure stability.
268269
typst = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist/v0.13.10" }
270+
typst-macros = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist/v0.13.10" }
269271
typst-library = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist/v0.13.10" }
270272
typst-html = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist/v0.13.10" }
271273
typst-timing = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist/v0.13.10" }

crates/sync-lsp/src/server.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,18 @@ impl LspClientRoot {
199199
msg_kind: M::get_message_kind(),
200200
sender: Arc::downgrade(&_strong),
201201
req_queue: Arc::new(Mutex::new(ReqQueue::default())),
202+
203+
hook: Arc::new(()),
202204
};
203205
Self { weak, _strong }
204206
}
205207

208+
/// Sets the hook for the language server host.
209+
pub fn with_hook(mut self, hook: Arc<dyn LsHook>) -> Self {
210+
self.weak.hook = hook;
211+
self
212+
}
213+
206214
/// Returns the weak reference to the language server host.
207215
pub fn weak(&self) -> LspClient {
208216
self.weak.clone()
@@ -221,6 +229,8 @@ pub struct LspClient {
221229
pub(crate) msg_kind: MessageKind,
222230
pub(crate) sender: Weak<ConnectionTx>,
223231
pub(crate) req_queue: Arc<Mutex<ReqQueue>>,
232+
233+
pub(crate) hook: Arc<dyn LsHook>,
224234
}
225235

226236
impl LspClient {
@@ -290,7 +300,7 @@ impl LspClient {
290300
/// Registers an client2server request in the request queue.
291301
pub fn register_request(&self, method: &str, id: &RequestId, received_at: Instant) {
292302
let mut req_queue = self.req_queue.lock();
293-
self.start_request(id, method);
303+
self.hook.start_request(id, method);
294304
req_queue
295305
.incoming
296306
.register(id.clone(), (method.to_owned(), received_at));
@@ -327,7 +337,7 @@ impl LspClient {
327337
return;
328338
};
329339

330-
self.stop_request(&id, &method, received_at);
340+
self.hook.stop_request(&id, &method, received_at);
331341

332342
let Some(sender) = self.sender.upgrade() else {
333343
log::warn!("failed to send response ({method}, {id}): connection closed");
@@ -380,7 +390,19 @@ impl LspClient {
380390
}
381391
}
382392

383-
impl LspClient {
393+
/// A trait that defines the hook for the language server.
394+
pub trait LsHook: fmt::Debug + Send + Sync {
395+
/// Starts a request.
396+
fn start_request(&self, req_id: &RequestId, method: &str);
397+
/// Stops a request.
398+
fn stop_request(&self, req_id: &RequestId, method: &str, received_at: Instant);
399+
/// Starts a notification.
400+
fn start_notification(&self, method: &str);
401+
/// Stops a notification.
402+
fn stop_notification(&self, method: &str, received_at: Instant, result: LspResult<()>);
403+
}
404+
405+
impl LsHook for () {
384406
fn start_request(&self, req_id: &RequestId, method: &str) {
385407
log::info!("handling {method} - ({req_id})");
386408
}

crates/sync-lsp/src/server/dap_srv.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ where
260260

261261
/// Handles an incoming event.
262262
fn on_event(&mut self, received_at: Instant, not: dap::Event) -> anyhow::Result<()> {
263-
self.client.start_notification(&not.event);
263+
self.client.hook.start_notification(&not.event);
264264
let handle = |s,
265265
dap::Event {
266266
seq: _,
@@ -273,7 +273,9 @@ where
273273
};
274274

275275
let result = handler(s, body);
276-
self.client.stop_notification(&event, received_at, result);
276+
self.client
277+
.hook
278+
.stop_notification(&event, received_at, result);
277279

278280
Ok(())
279281
};

crates/sync-lsp/src/server/lsp_srv.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,15 +354,17 @@ where
354354

355355
/// Handles an incoming notification.
356356
fn on_notification(&mut self, received_at: Instant, not: Notification) -> anyhow::Result<()> {
357-
self.client.start_notification(&not.method);
357+
self.client.hook.start_notification(&not.method);
358358
let handle = |s, Notification { method, params }: Notification| {
359359
let Some(handler) = self.notifications.get(method.as_str()) else {
360360
log::warn!("unhandled notification: {method}");
361361
return Ok(());
362362
};
363363

364364
let result = handler(s, params);
365-
self.client.stop_notification(&method, received_at, result);
365+
self.client
366+
.hook
367+
.stop_notification(&method, received_at, result);
366368

367369
Ok(())
368370
};

crates/tinymist-analysis/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ tinymist-world.workspace = true
3535
toml.workspace = true
3636
triomphe.workspace = true
3737
typst.workspace = true
38+
typst-macros.workspace = true
3839
typst-shim.workspace = true
40+
typst-timing.workspace = true
3941
unscanny.workspace = true
4042

4143
[dev-dependencies]

crates/tinymist-analysis/src/track_values.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub fn analyze_expr(world: &dyn World, node: &LinkedNode) -> EcoVec<(Value, Opti
2323
}
2424

2525
/// Try to determine a set of possible values for an expression.
26+
#[typst_macros::time(span = node.span())]
2627
pub fn analyze_expr_(world: &dyn World, node: &SyntaxNode) -> EcoVec<(Value, Option<Styles>)> {
2728
let Some(expr) = node.cast::<ast::Expr>() else {
2829
return eco_vec![];
@@ -51,6 +52,7 @@ pub fn analyze_expr_(world: &dyn World, node: &SyntaxNode) -> EcoVec<(Value, Opt
5152
}
5253

5354
/// Try to load a module from the current source file.
55+
#[typst_macros::time(span = source.span())]
5456
pub fn analyze_import_(world: &dyn World, source: &SyntaxNode) -> (Option<Value>, Option<Value>) {
5557
let source_span = source.span();
5658
let Some((source, _)) = analyze_expr_(world, source).into_iter().next() else {
@@ -109,6 +111,7 @@ pub struct DynLabel {
109111
/// - All labels and descriptions for them, if available
110112
/// - A split offset: All labels before this offset belong to nodes, all after
111113
/// belong to a bibliography.
114+
#[typst_macros::time]
112115
pub fn analyze_labels(document: &TypstDocument) -> (Vec<DynLabel>, usize) {
113116
let mut output = vec![];
114117

crates/tinymist-query/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ tinymist-std.workspace = true
5151
tinymist-l10n.workspace = true
5252
tinymist-lint.workspace = true
5353
typst.workspace = true
54+
typst-macros.workspace = true
5455
typst-shim.workspace = true
56+
typst-timing.workspace = true
5557
unscanny.workspace = true
5658
walkdir.workspace = true
5759
yaml-rust2.workspace = true

crates/tinymist-query/src/analysis/call.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ pub struct CallInfo {
3838

3939
// todo: cache call
4040
/// Analyzes a function call.
41+
#[typst_macros::time(span = node.span())]
4142
pub fn analyze_call(
4243
ctx: &mut LocalContext,
4344
source: Source,

crates/tinymist-query/src/analysis/completion/scope.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ impl CompletionPair<'_, '_, '_> {
5050
self.def_completions(defines, parens);
5151
}
5252

53+
#[typst_macros::time]
5354
pub fn scope_defs(&mut self) -> Option<Defines> {
5455
let mut defines = Defines {
5556
types: self.worker.ctx.type_check(&self.cursor.source),

crates/tinymist-query/src/analysis/definition.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ impl HasNameRange for Decl {
8181

8282
// todo: field definition
8383
/// Finds the definition of a symbol.
84+
#[typst_macros::time(span = syntax.node().span())]
8485
pub fn definition(
8586
ctx: &Arc<SharedContext>,
8687
source: &Source,

crates/tinymist-query/src/analysis/global.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,7 @@ impl SharedContext {
779779
}
780780

781781
/// Get the lint result of a source file.
782+
#[typst_macros::time(span = source.root().span())]
782783
pub(crate) fn lint(self: &Arc<Self>, source: &Source) -> LintInfo {
783784
let ei = self.expr_stage(source);
784785
let ti = self.type_check(source);
@@ -1296,6 +1297,7 @@ fn ceil_char_boundary(text: &str, mut cursor: usize) -> usize {
12961297
cursor.min(text.len())
12971298
}
12981299

1300+
#[typst_macros::time]
12991301
#[comemo::memoize]
13001302
fn analyze_bib(
13011303
world: Tracked<dyn World + '_>,

crates/tinymist-query/src/analysis/link_expr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use tinymist_world::package::PackageSpec;
88
use super::prelude::*;
99

1010
/// Get link expressions from a source.
11+
#[typst_macros::time(span = src.root().span())]
1112
#[comemo::memoize]
1213
pub fn get_link_exprs(src: &Source) -> Arc<LinkInfo> {
1314
let root = LinkedNode::new(src.root());

crates/tinymist-query/src/analysis/post_tyck.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::ty::BuiltinTy;
1313

1414
/// With given type information, check the type of a literal expression again by
1515
/// touching the possible related nodes.
16+
#[typst_macros::time(span = node.span())]
1617
pub(crate) fn post_type_check(
1718
ctx: Arc<SharedContext>,
1819
ti: &TypeInfo,

crates/tinymist-query/src/analysis/semantic_tokens.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use crate::{
2626
pub type SemanticTokens = Arc<Vec<SemanticToken>>;
2727

2828
/// Get the semantic tokens for a source.
29+
#[typst_macros::time(span = source.root().span())]
2930
pub(crate) fn get_semantic_tokens(ctx: &mut LocalContext, source: &Source) -> SemanticTokens {
3031
let mut tokenizer = Tokenizer::new(
3132
source.clone(),

crates/tinymist-query/src/analysis/signature.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,18 @@ pub enum SignatureTarget {
3030
Convert(Func),
3131
}
3232

33+
impl SignatureTarget {
34+
/// Returns the span of the callee node.
35+
pub fn span(&self) -> Span {
36+
match self {
37+
SignatureTarget::Def(_, def) => def.decl.span(),
38+
SignatureTarget::SyntaxFast(_, span) | SignatureTarget::Syntax(_, span) => *span,
39+
SignatureTarget::Runtime(func) | SignatureTarget::Convert(func) => func.span(),
40+
}
41+
}
42+
}
43+
44+
#[typst_macros::time(span = callee_node.span())]
3345
pub(crate) fn analyze_signature(
3446
ctx: &Arc<SharedContext>,
3547
callee_node: SignatureTarget,
@@ -41,6 +53,7 @@ pub(crate) fn analyze_signature(
4153
})
4254
}
4355

56+
#[typst_macros::time(span = callee_node.span())]
4457
fn analyze_type_signature(
4558
ctx: &Arc<SharedContext>,
4659
callee_node: &SignatureTarget,
@@ -315,6 +328,7 @@ impl BoundChecker for AliasStackChecker<'_, '_> {
315328
}
316329
}
317330

331+
#[typst_macros::time(span = callee_node.span())]
318332
fn analyze_dyn_signature(
319333
ctx: &Arc<SharedContext>,
320334
callee_node: &SignatureTarget,

crates/tinymist-query/src/analysis/tyck.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub struct TypeEnv {
2929
}
3030

3131
/// Type checking at the source unit level.
32+
#[typst_macros::time(span = ei.source.root().span())]
3233
pub(crate) fn type_check(
3334
ctx: Arc<SharedContext>,
3435
ei: ExprInfo,
@@ -228,14 +229,14 @@ impl TypeChecker<'_> {
228229
&mut self,
229230
sig: &Interned<SigTy>,
230231
args: &Interned<SigTy>,
231-
withs: Option<&Vec<Interned<SigTy>>>,
232+
with: Option<&Vec<Interned<SigTy>>>,
232233
) {
233-
let call_desc = (sig.clone(), args.clone(), withs.cloned());
234+
let call_desc = (sig.clone(), args.clone(), with.cloned());
234235
if !self.call_cache.insert(call_desc) {
235236
return;
236237
}
237238

238-
for (arg_recv, arg_ins) in sig.matches(args, withs) {
239+
for (arg_recv, arg_ins) in sig.matches(args, with) {
239240
self.constrain(arg_ins, arg_recv);
240241
}
241242
}

crates/tinymist-query/src/analysis/tyck/syntax.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ static EMPTY_DOCSTRING: LazyLock<DocString> = LazyLock::new(DocString::default);
1212
static EMPTY_VAR_DOC: LazyLock<VarDoc> = LazyLock::new(VarDoc::default);
1313

1414
impl TypeChecker<'_> {
15+
#[typst_macros::time(span = expr.span())]
1516
pub(crate) fn check_syntax(&mut self, expr: &Expr) -> Option<Ty> {
1617
Some(match expr {
1718
Expr::Block(exprs) => self.check_block(exprs),

crates/tinymist-query/src/syntax/expr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use super::{compute_docstring, def::*, DocCommentMatcher, InterpretMode};
2828

2929
pub type ExprRoute = FxHashMap<TypstFileId, Option<Arc<LazyHash<LexicalScope>>>>;
3030

31+
#[typst_macros::time(span = source.root().span())]
3132
pub(crate) fn expr_of(
3233
ctx: Arc<SharedContext>,
3334
source: Source,

crates/tinymist-query/src/syntax/index.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub struct IndexInfo {
1212
pub(crate) identifiers: FxHashSet<Interned<str>>,
1313
}
1414

15+
#[typst_macros::time(span = src.root().span())]
1516
#[comemo::memoize]
1617
pub fn get_index_info(src: &Source) -> Arc<IndexInfo> {
1718
let root = src.root();

crates/tinymist-query/src/syntax/lexical_hierarchy.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use typst_shim::utils::LazyHash;
1111

1212
use super::{is_mark, CommentGroupMatcher};
1313

14+
#[typst_macros::time(span = source.root().span())]
1415
pub(crate) fn get_lexical_hierarchy(
1516
source: &Source,
1617
scope_kind: LexicalScopeKind,

crates/tinymist-query/src/syntax/module.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub struct ModuleDependency {
1818
/// It will scan all the files in the context, using
1919
/// [`LocalContext::source_files`], and find the dependencies and dependents
2020
/// of each file.
21+
#[typst_macros::time]
2122
pub fn construct_module_dependencies(
2223
ctx: &mut LocalContext,
2324
) -> HashMap<TypstFileId, ModuleDependency> {

crates/tinymist-std/src/error.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,22 @@ impl<T, E: std::fmt::Display> IgnoreLogging<T> for Result<T, E> {
318318
}
319319
}
320320

321+
impl<T> IgnoreLogging<T> for Option<T> {
322+
fn log_error(self, msg: &str) -> Option<T> {
323+
self.or_else(|| {
324+
log::error!("{msg}");
325+
None
326+
})
327+
}
328+
329+
fn log_error_with(self, f: impl FnOnce() -> String) -> Option<T> {
330+
self.or_else(|| {
331+
log::error!("{}", f());
332+
None
333+
})
334+
}
335+
}
336+
321337
/// A trait to add context to a result.
322338
pub trait WithContext<T>: Sized {
323339
/// Add a context to the result.

crates/tinymist-std/src/hash.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ use rkyv::{Archive, Deserialize as rDeser, Serialize as rSer};
1515

1616
use crate::error::prelude::Result;
1717

18-
pub(crate) type FxBuildHasher = std::hash::BuildHasherDefault<FxHasher>;
19-
pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
18+
pub use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet, FxHasher};
2019
// pub type FxIndexSet<K> = indexmap::IndexSet<K, FxHasher>;
2120
// pub type FxIndexMap<K, V> = indexmap::IndexMap<K, V, FxHasher>;
2221
/// A dashmap that uses the FxHasher as the underlying hasher.
@@ -34,7 +33,8 @@ pub type FxDashMap<K, V> = dashmap::DashMap<K, V, FxBuildHasher>;
3433
/// > is a probability of 1 in 36,890,000,000,000 of a `StableCrateId`
3534
/// > collision.
3635
///
37-
/// This stores the 16-bytes data in a pair of `u64` instead of single `u128` to avoid heavily affecting `align` of the embedding structs.
36+
/// This stores the 16-bytes data in a pair of `u64` instead of single `u128` to
37+
/// avoid heavily affecting `align` of the embedding structs.
3838
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
3939
#[cfg_attr(feature = "rkyv", derive(Archive, rDeser, rSer))]
4040
#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]

0 commit comments

Comments
 (0)