Skip to content

Commit

Permalink
Merge pull request #210 from saethlin/samples-not-percentages
Browse files Browse the repository at this point in the history
Compute rect position and width from samples
  • Loading branch information
jonhoo committed May 5, 2021
2 parents 43ed780 + 675c79c commit d80e579
Show file tree
Hide file tree
Showing 38 changed files with 11,423 additions and 11,420 deletions.
77 changes: 35 additions & 42 deletions src/flamegraph/flamegraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ function init(evt) {
matchedtxt = document.getElementById("matched");
svg = document.getElementsByTagName("svg")[0];
frames = document.getElementById("frames");
total_samples = parseInt(frames.attributes.total_samples.value);
searching = 0;

// Use GET parameters to restore a flamegraph's state.
var restore_state = function() {
var params = get_params();
if (params.x && params.y)
zoom(find_group(document.querySelector('[x="' + params.x + '"][y="' + params.y + '"]')));
zoom(find_group(document.querySelector('[*|x="' + params.x + '"][y="' + params.y + '"]')));
if (params.s)
search(params.s);
};
Expand Down Expand Up @@ -71,9 +72,9 @@ window.addEventListener("click", function(e) {

// set parameters for zoom state
var el = target.querySelector("rect");
if (el && el.attributes && el.attributes.y && el.attributes._orig_x) {
if (el && el.attributes && el.attributes.y && el.attributes["fg:x"]) {
var params = get_params()
params.x = el.attributes._orig_x.value;
params.x = el.attributes["fg:x"].value;
params.y = el.attributes.y.value;
history.replaceState(null, null, parse_params(params));
}
Expand Down Expand Up @@ -141,15 +142,15 @@ function find_group(node) {
return find_group(parent);
}
function orig_save(e, attr, val) {
if (e.attributes["_orig_" + attr] != undefined) return;
if (e.attributes["fg:orig_" + attr] != undefined) return;
if (e.attributes[attr] == undefined) return;
if (val == undefined) val = e.attributes[attr].value;
e.setAttribute("_orig_" + attr, val);
e.setAttribute("fg:orig_" + attr, val);
}
function orig_load(e, attr) {
if (e.attributes["_orig_"+attr] == undefined) return;
e.attributes[attr].value = e.attributes["_orig_" + attr].value;
e.removeAttribute("_orig_" + attr);
if (e.attributes["fg:orig_"+attr] == undefined) return;
e.attributes[attr].value = e.attributes["fg:orig_" + attr].value;
e.removeAttribute("fg:orig_" + attr);
}
function g_to_text(e) {
var text = find_child(e, "title").firstChild.nodeValue;
Expand Down Expand Up @@ -197,42 +198,34 @@ function update_text(e) {
}
// zoom
function zoom_reset(e) {
if (e.attributes != undefined) {
orig_load(e, "x");
orig_load(e, "width");
if (e.tagName == "rect") {
e.attributes.x.value = format_percent(100 * parseInt(e.attributes["fg:x"].value) / total_samples);
e.attributes.width.value = format_percent(100 * parseInt(e.attributes["fg:w"].value) / total_samples);
}
if (e.childNodes == undefined) return;
for(var i = 0, c = e.childNodes; i < c.length; i++) {
zoom_reset(c[i]);
}
}
function zoom_child(e, x, ratio) {
if (e.attributes != undefined) {
if (e.attributes.x != undefined) {
orig_save(e, "x");
e.attributes.x.value = format_percent((parseFloat(e.attributes.x.value) - x) * ratio);
if (e.tagName == "text") {
e.attributes.x.value = format_percent(parseFloat(find_child(e.parentNode, "rect[x]").attributes.x.value) + (100 * 3 / frames.attributes.width.value));
}
}
if (e.attributes.width != undefined) {
orig_save(e, "width");
e.attributes.width.value = format_percent(parseFloat(e.attributes.width.value) * ratio);
}
function zoom_child(e, x, zoomed_width_samples) {
if (e.tagName == "text") {
var parent_x = parseFloat(find_child(e.parentNode, "rect[x]").attributes.x.value);
e.attributes.x.value = format_percent(parent_x + (100 * 3 / frames.attributes.width.value));
} else if (e.tagName == "rect") {
e.attributes.x.value = format_percent(100 * (parseInt(e.attributes["fg:x"].value) - x) / zoomed_width_samples);
e.attributes.width.value = format_percent(100 * parseInt(e.attributes["fg:w"].value) / zoomed_width_samples);
}
if (e.childNodes == undefined) return;
for(var i = 0, c = e.childNodes; i < c.length; i++) {
zoom_child(c[i], x, ratio);
zoom_child(c[i], x, zoomed_width_samples);
}
}
function zoom_parent(e) {
if (e.attributes) {
if (e.attributes.x != undefined) {
orig_save(e, "x");
e.attributes.x.value = "0.0%";
}
if (e.attributes.width != undefined) {
orig_save(e, "width");
e.attributes.width.value = "100.0%";
}
}
Expand All @@ -243,20 +236,17 @@ function zoom_parent(e) {
}
function zoom(node) {
var attr = find_child(node, "rect").attributes;
var width = parseFloat(attr.width.value);
var xmin = parseFloat(attr.x.value);
var width = parseInt(attr["fg:w"].value);
var xmin = parseInt(attr["fg:x"].value);
var xmax = xmin + width;
var ymin = parseFloat(attr.y.value);
var ratio = 100 / width;
// XXX: Workaround for JavaScript float issues (fix me)
var fudge = 0.001;
unzoombtn.classList.remove("hide");
var el = frames.children;
for (var i = 0; i < el.length; i++) {
var e = el[i];
var a = find_child(e, "rect").attributes;
var ex = parseFloat(a.x.value);
var ew = parseFloat(a.width.value);
var ex = parseInt(a["fg:x"].value);
var ew = parseInt(a["fg:w"].value);
// Is it an ancestor
if (!inverted) {
var upstack = parseFloat(a.y.value) > ymin;
Expand All @@ -265,7 +255,7 @@ function zoom(node) {
}
if (upstack) {
// Direct ancestor
if (ex <= xmin && (ex+ew+fudge) >= xmax) {
if (ex <= xmin && (ex+ew) >= xmax) {
e.classList.add("parent");
zoom_parent(e);
update_text(e);
Expand All @@ -277,11 +267,11 @@ function zoom(node) {
// Children maybe
else {
// no common path
if (ex < xmin || ex + fudge >= xmax) {
if (ex < xmin || ex >= xmax) {
e.classList.add("hide");
}
else {
zoom_child(e, xmin, ratio);
zoom_child(e, xmin, width);
update_text(e);
}
}
Expand Down Expand Up @@ -330,17 +320,21 @@ function search(term) {
var maxwidth = 0;
for (var i = 0; i < el.length; i++) {
var e = el[i];
// Skip over frames which are either not visible, or below the zoomed-to frame
if (e.classList.contains("hide") || e.classList.contains("parent")) {
continue;
}
var func = g_to_func(e);
var rect = find_child(e, "rect");
if (func == null || rect == null)
continue;
// Save max width. Only works as we have a root frame
var w = parseFloat(rect.attributes.width.value);
var w = parseInt(rect.attributes["fg:w"].value);
if (w > maxwidth)
maxwidth = w;
if (func.match(re)) {
// highlight
var x = parseFloat(rect.attributes.x.value);
var x = parseInt(rect.attributes["fg:x"].value);
orig_save(rect, "fill");
rect.attributes.fill.value = searchcolor;
// remember matches
Expand Down Expand Up @@ -380,11 +374,10 @@ function search(term) {
// Step through frames saving only the biggest bottom-up frames
// thanks to the sort order. This relies on the tree property
// where children are always smaller than their parents.
var fudge = 0.0001; // JavaScript floating point
for (var k in keys) {
var x = parseFloat(keys[k]);
var x = parseInt(keys[k]);
var w = matches[keys[k]];
if (x >= lastx + lastw - fudge) {
if (x >= lastx + lastw) {
count += w;
lastx = x;
lastw = w;
Expand Down
11 changes: 10 additions & 1 deletion src/flamegraph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,10 @@ impl Default for TextTruncateDirection {
}

struct Rectangle {
x1_samples: usize,
x1_pct: f64,
y1: usize,
x2_samples: usize,
x2_pct: f64,
y2: usize,
}
Expand Down Expand Up @@ -522,6 +524,7 @@ where
("id", "frames"),
("x", &container_x),
("width", &container_width),
("total_samples", &format!("{}", timemax)),
]),
))?;

Expand All @@ -547,8 +550,10 @@ where

let rect = Rectangle {
x1_pct,
x1_samples: frame.start_time,
y1,
x2_pct,
x2_samples: frame.end_time,
y2,
};

Expand Down Expand Up @@ -857,6 +862,8 @@ fn filled_rectangle<W: Write>(
let width = write!(buffer, "{:.4}%", rect.width_pct());
let height = write_usize(buffer, rect.height());
let color = write!(buffer, "rgb({},{},{})", color.r, color.g, color.b);
let x_samples = write_usize(buffer, rect.x1_samples);
let width_samples = write_usize(buffer, rect.x2_samples - rect.x1_samples);

if let Event::Empty(bytes_start) = cache_rect {
// clear the state
Expand All @@ -866,7 +873,9 @@ fn filled_rectangle<W: Write>(
"y" => &buffer[y],
"width" => &buffer[width],
"height" => &buffer[height],
"fill" => &buffer[color]
"fill" => &buffer[color],
"fg:x" => &buffer[x_samples],
"fg:w" => &buffer[width_samples]
));
} else {
unreachable!("cache wrapper was of wrong type: {:?}", cache_rect);
Expand Down
1 change: 1 addition & 0 deletions src/flamegraph/svg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ where
("viewBox", &*format!("0 0 {} {}", imagewidth, imageheight)),
("xmlns", "http://www.w3.org/2000/svg"),
("xmlns:xlink", "http://www.w3.org/1999/xlink"),
("xmlns:fg", "http://github.com/jonhoo/inferno"),
]),
))?;
svg.write_event(Event::Comment(BytesText::from_plain_str(
Expand Down

0 comments on commit d80e579

Please sign in to comment.