Added callsite to func calls

This commit is contained in:
Dherse 2025-03-28 10:43:16 +01:00
parent 838a46dbb7
commit c97ce11dbb
4 changed files with 57 additions and 11 deletions

View File

@ -298,7 +298,7 @@ impl Func {
} }
/// Non-generic implementation of `call`. /// Non-generic implementation of `call`.
#[typst_macros::time(name = "func call", span = self.span())] #[typst_macros::time(name = "func call", span = self.span(), callsite = args.span)]
fn call_impl( fn call_impl(
&self, &self,
engine: &mut Engine, engine: &mut Engine,

View File

@ -8,12 +8,13 @@ use crate::util::{kw, parse_key_value, parse_string};
/// Expand the `#[time(..)]` macro. /// Expand the `#[time(..)]` macro.
pub fn time(stream: TokenStream, item: syn::ItemFn) -> Result<TokenStream> { pub fn time(stream: TokenStream, item: syn::ItemFn) -> Result<TokenStream> {
let meta: Meta = syn::parse2(stream)?; let meta: Meta = syn::parse2(stream)?;
Ok(create(meta, item)) create(meta, item)
} }
/// The `..` in `#[time(..)]`. /// The `..` in `#[time(..)]`.
pub struct Meta { pub struct Meta {
pub span: Option<syn::Expr>, pub span: Option<syn::Expr>,
pub callsite: Option<syn::Expr>,
pub name: Option<String>, pub name: Option<String>,
} }
@ -22,15 +23,24 @@ impl Parse for Meta {
Ok(Self { Ok(Self {
name: parse_string::<kw::name>(input)?, name: parse_string::<kw::name>(input)?,
span: parse_key_value::<kw::span, syn::Expr>(input)?, span: parse_key_value::<kw::span, syn::Expr>(input)?,
callsite: parse_key_value::<kw::callsite, syn::Expr>(input)?,
}) })
} }
} }
fn create(meta: Meta, mut item: syn::ItemFn) -> TokenStream { fn create(meta: Meta, mut item: syn::ItemFn) -> Result<TokenStream> {
let name = meta.name.unwrap_or_else(|| item.sig.ident.to_string()); let name = meta.name.unwrap_or_else(|| item.sig.ident.to_string());
let construct = match meta.span.as_ref() { let construct = match (meta.span.as_ref(), meta.callsite.as_ref()) {
Some(span) => quote! { with_span(#name, Some(#span.into_raw())) }, (Some(span), Some(callsite)) => quote! {
None => quote! { new(#name) }, with_callsite(#name, Some(#span.into_raw()), Some(#callsite.into_raw()))
},
(Some(span), None) => quote! {
with_span(#name, Some(#span.into_raw()))
},
(None, Some(expr)) => {
bail!(expr, "cannot have a callsite span without a main span")
}
(None, None) => quote! { new(#name) },
}; };
item.block.stmts.insert( item.block.stmts.insert(
@ -40,5 +50,5 @@ fn create(meta: Meta, mut item: syn::ItemFn) -> TokenStream {
}, },
); );
item.into_token_stream() Ok(item.into_token_stream())
} }

View File

@ -254,6 +254,7 @@ impl Parse for BareType {
pub mod kw { pub mod kw {
syn::custom_keyword!(name); syn::custom_keyword!(name);
syn::custom_keyword!(span); syn::custom_keyword!(span);
syn::custom_keyword!(callsite);
syn::custom_keyword!(title); syn::custom_keyword!(title);
syn::custom_keyword!(scope); syn::custom_keyword!(scope);
syn::custom_keyword!(contextual); syn::custom_keyword!(contextual);

View File

@ -107,6 +107,10 @@ pub fn export_json<W: Write>(
struct Args { struct Args {
file: String, file: String,
line: u32, line: u32,
#[serde(skip_serializing_if = "Option::is_none")]
callsite_file: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
callsite_line: Option<u32>,
} }
let lock = EVENTS.lock(); let lock = EVENTS.lock();
@ -128,7 +132,15 @@ pub fn export_json<W: Write>(
ts: event.timestamp.micros_since(events[0].timestamp), ts: event.timestamp.micros_since(events[0].timestamp),
pid: 1, pid: 1,
tid: event.thread_id, tid: event.thread_id,
args: event.span.map(&mut source).map(|(file, line)| Args { file, line }), args: event.span.map(&mut source).map(|(file, line)| {
let (callsite_file, callsite_line) = match event.callsite.map(&mut source)
{
Some((a, b)) => (Some(a), Some(b)),
None => (None, None),
};
Args { file, line, callsite_file, callsite_line }
}),
}) })
.map_err(|e| format!("failed to serialize event: {e}"))?; .map_err(|e| format!("failed to serialize event: {e}"))?;
} }
@ -142,6 +154,7 @@ pub fn export_json<W: Write>(
pub struct TimingScope { pub struct TimingScope {
name: &'static str, name: &'static str,
span: Option<NonZeroU64>, span: Option<NonZeroU64>,
callsite: Option<NonZeroU64>,
thread_id: u64, thread_id: u64,
} }
@ -159,14 +172,32 @@ impl TimingScope {
/// `typst-timing`). /// `typst-timing`).
#[inline] #[inline]
pub fn with_span(name: &'static str, span: Option<NonZeroU64>) -> Option<Self> { pub fn with_span(name: &'static str, span: Option<NonZeroU64>) -> Option<Self> {
Self::with_callsite(name, span, None)
}
/// Create a new scope with a span if timing is enabled.
///
/// The span is a raw number because `typst-timing` can't depend on
/// `typst-syntax` (or else `typst-syntax` couldn't depend on
/// `typst-timing`).
#[inline]
pub fn with_callsite(
name: &'static str,
span: Option<NonZeroU64>,
callsite: Option<NonZeroU64>,
) -> Option<Self> {
if is_enabled() { if is_enabled() {
return Some(Self::new_impl(name, span)); return Some(Self::new_impl(name, span, callsite));
} }
None None
} }
/// Create a new scope without checking if timing is enabled. /// Create a new scope without checking if timing is enabled.
fn new_impl(name: &'static str, span: Option<NonZeroU64>) -> Self { fn new_impl(
name: &'static str,
span: Option<NonZeroU64>,
callsite: Option<NonZeroU64>,
) -> Self {
let (thread_id, timestamp) = let (thread_id, timestamp) =
THREAD_DATA.with(|data| (data.id, Timestamp::now_with(data))); THREAD_DATA.with(|data| (data.id, Timestamp::now_with(data)));
EVENTS.lock().push(Event { EVENTS.lock().push(Event {
@ -174,9 +205,10 @@ impl TimingScope {
timestamp, timestamp,
name, name,
span, span,
callsite,
thread_id, thread_id,
}); });
Self { name, span, thread_id } Self { name, span, callsite: None, thread_id }
} }
} }
@ -188,6 +220,7 @@ impl Drop for TimingScope {
timestamp, timestamp,
name: self.name, name: self.name,
span: self.span, span: self.span,
callsite: self.callsite,
thread_id: self.thread_id, thread_id: self.thread_id,
}); });
} }
@ -203,6 +236,8 @@ struct Event {
name: &'static str, name: &'static str,
/// The raw value of the span of code that this event was recorded in. /// The raw value of the span of code that this event was recorded in.
span: Option<NonZeroU64>, span: Option<NonZeroU64>,
/// The raw value of the callsite span of the code that this event was recorded in.
callsite: Option<NonZeroU64>,
/// The thread ID of this event. /// The thread ID of this event.
thread_id: u64, thread_id: u64,
} }