Skip to content

Commit

Permalink
Group traces by thread
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Feb 2, 2024
1 parent 6bf0c29 commit daec623
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 61 deletions.
6 changes: 6 additions & 0 deletions wgpu-sync/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ impl LockId {
}
}

impl fmt::Display for LockId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}

impl fmt::Debug for LockId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("LockId")
Expand Down
166 changes: 105 additions & 61 deletions wgpu-sync/src/html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ use crate::Event;
type Child<'a> = (EventId, &'a str, u64, Option<&'a EventBacktrace>);

const STYLE: &str = r#"
html {
font-family: helvetica, arial, sans-serif;
}
#traces {
width: 100%;
}
.title {
font-family: helvetica;
font-size: 14px;
font-weight: bold;
}
Expand All @@ -31,17 +34,12 @@ const STYLE: &str = r#"
margin-top: 0;
}
.lock-instance > .section {
background-color: #ffff80;
margin: 10px 0;
}
.lock-instance > .section:last-child {
margin-bottom: 0;
}
.timeline {
font-size: 18px;
position: relative;
min-height: 1em;
background-color: #ffffff;
margin-top: 10px;
}
.lock-session {
Expand All @@ -54,8 +52,20 @@ const STYLE: &str = r#"
}
.section {
height: 26px;
position: absolute;
min-width: 2px;
height: 1em;
}
.section-heading {
position: absolute;
left: 0;
}
.section-heading span {
font-size: 0.6em;
line-height: 1.66em;
padding-left: 0.166em;
}
.section.critical {
Expand Down Expand Up @@ -91,9 +101,13 @@ const STYLE: &str = r#"
}
.details {
font-family: helvetica;
font-size: 12px;
padding: 5px;
margin-top: 10px;
}
.details td {
padding: 2px;
}
.backtrace {
Expand Down Expand Up @@ -144,8 +158,8 @@ where
let mut end = u64::MIN;

let mut opens = BTreeMap::<_, Vec<_>>::new();
let mut children = HashMap::<_, Vec<_>>::new();
let mut closes = HashMap::new();
let mut children = HashMap::new();

for event in events {
start = start.min(event.timestamp);
Expand All @@ -161,15 +175,20 @@ where
..
} => {
if let Some(parent) = parent {
children.insert(
*parent,
(event.id, name.as_ref(), event.timestamp, backtrace.as_ref()),
);
children.entry(*parent).or_default().push((
event.id,
name.as_ref(),
event.timestamp,
backtrace.as_ref(),
));
} else {
opens
.entry((*lock, type_name.as_ref(), event.thread_index))
.or_default()
.push((event.id, name.as_ref(), event.timestamp, backtrace.as_ref()));
opens.entry((*lock, type_name.as_ref())).or_default().push((
event.id,
name.as_ref(),
event.timestamp,
backtrace.as_ref(),
event.thread_index,
));
}
}
EventKind::Leave {
Expand All @@ -193,7 +212,7 @@ where
writeln!(out, "<body>")?;
writeln!(out, "<div id=\"traces\">")?;

for ((lock, type_name, thread), events) in opens {
for ((lock, type_name), events) in opens {
writeln!(out, "<div class=\"lock-instance\">")?;

let kind = lock.kind();
Expand All @@ -203,21 +222,25 @@ where

writeln!(
out,
"<div class=\"title\">{kind:?}&lt;{type_name}&gt; (index: {index}) (thread: {thread})</div>"
r#"<div class="title">{kind:?}&lt;{type_name}&gt; (lock index: {index})</div>"#
)?;

for (id, name, open, backtrace) in events {
writeln!(
out,
"<div data-toggle=\"event-{id}-details\" class=\"lock-session\">"
)?;
let mut details = Vec::new();

let mut details = Vec::new();
writeln!(out, "<div class=\"lock-session\">")?;

writeln!(out, "<div class=\"timeline\">")?;
let height = events.len();
let style = format!("height: {height}em;");
writeln!(
out,
r#"<div data-toggle="event-{lock}-details" class="timeline" style="{style}">"#
)?;

for (level, (id, name, open, backtrace, thread_index)) in events.into_iter().enumerate() {
write_section(
&mut out,
level,
Some(thread_index),
id,
(start, end),
name,
Expand All @@ -227,23 +250,22 @@ where
backtrace,
&mut details,
)?;
}

writeln!(out, "</div>")?;

if !details.is_empty() {
writeln!(
out,
"<div id=\"event-{id}-details\" class=\"details\" style=\"display: none;\">"
)?;
writeln!(out, "</div>")?;

out.write_all(&details)?;
writeln!(out, "</div>")?;
}
if !details.is_empty() {
writeln!(
out,
r#"<table id="event-{lock}-details" class="details" style="display: none;">"#
)?;

writeln!(out, "</div>")?;
out.write_all(&details)?;
writeln!(out, "</table>")?;
}

writeln!(out, "</div>")?;
writeln!(out, "</div>")?;
}

writeln!(out, "</div>")?;
Expand All @@ -256,11 +278,13 @@ where
#[allow(clippy::too_many_arguments)]
fn write_section(
out: &mut dyn io::Write,
level: usize,
thread_index: Option<usize>,
id: EventId,
span: (u64, u64),
title: &str,
open: u64,
children: &HashMap<EventId, Child<'_>>,
children: &HashMap<EventId, Vec<Child<'_>>>,
closes: &HashMap<EventId, u64>,
backtrace: Option<&EventBacktrace>,
d: &mut Vec<u8>,
Expand All @@ -279,38 +303,58 @@ fn write_section(
let e = Duration::from_nanos(close);
let duration = Duration::from_nanos(close - open);

let style = format!("width: {width}%; margin-left: {left}%;");
if let Some(thread_index) = thread_index {
writeln!(
out,
r#"<span class="section-heading" style="top: {level}em;"><span>{thread_index} / {id}</span></span>"#
)?;
}

let style = format!("width: {width}%; left: {left}%; top: {level}em;");
let hover_title = format!("{title} ({s:?}-{e:?})");

writeln!(
out,
"<div id=\"event-{id}\" class=\"section {title}\" style=\"{style}\" title=\"{hover_title}\">"
"<div id=\"event-{id}\" class=\"section {title}\" style=\"{style}\" title=\"{hover_title}\"></div>"
)?;

if let Some(&(id, title, child_open, backtrace)) = children.get(&id) {
write_section(
out,
id,
(open, close),
title,
child_open,
children,
closes,
backtrace,
if let Some(thread_index) = thread_index {
writeln! {
d,
)?;
r#"
<tr>
<td class="title" colspan="6">Thread: {thread_index} / Event: {id}</td>
</tr>
"#
}?;
}

writeln!(d, "<div class=\"title {title}\">{title}</div>")?;
writeln!(
writeln! {
d,
"<div class=\"entry\">{s:?} &mdash; {e:?} ({duration:?})</div>"
)?;
r#"
<tr>
<td class="title {title}">{title}</td>
<td>{s:?}</td>
<td>&mdash;</td>
<td>{e:?}</td>
<td>({duration:?})</td>
<td width="100%"></td>
</tr>
"#
}?;

if let Some(backtrace) = backtrace {
writeln!(d, "<div class=\"backtrace\">Backtrace:\n{backtrace}</div>")?;
writeln!(
d,
r#"<tr><td>Backtrace:</td><td class="backtrace" colspan="5">{backtrace}</td></tr>"#
)?;
}

for &(id, title, child_open, backtrace) in children.get(&id).into_iter().flatten() {
write_section(
out, level, None, id, span, title, child_open, children, closes, backtrace, d,
)?;
}

writeln!(out, "</div>")?;
Ok(())
}

0 comments on commit daec623

Please sign in to comment.