From fc31f1b1ee2f083ecba1cdb5ebdc7fd0ca4de714 Mon Sep 17 00:00:00 2001 From: Jeff Putlock Date: Thu, 30 Apr 2026 18:33:37 -0400 Subject: [PATCH 1/5] Add case insensitivity --- src/flamegraph/flamegraph.css | 2 ++ src/flamegraph/flamegraph.js | 36 +++++++++++++++++++++++++++++++---- src/flamegraph/svg.rs | 14 ++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/flamegraph/flamegraph.css b/src/flamegraph/flamegraph.css index 42e9d535..aa6bcb0a 100644 --- a/src/flamegraph/flamegraph.css +++ b/src/flamegraph/flamegraph.css @@ -1,6 +1,8 @@ #matched { text-anchor:end; } #search { text-anchor:end; opacity:0.1; cursor:pointer; } #search:hover, #search.show { opacity:1; } +#ignorecase { text-anchor:end; opacity:0.1; cursor:pointer; } +#ignorecase:hover, #ignorecase.show { opacity:1; } #subtitle { text-anchor:middle; font-color:rgb(160,160,160); } #unzoom { cursor:pointer; } #frames > *:hover { stroke:black; stroke-width:0.5; cursor:pointer; } diff --git a/src/flamegraph/flamegraph.js b/src/flamegraph/flamegraph.js index 7c8e41e1..f764c19d 100644 --- a/src/flamegraph/flamegraph.js +++ b/src/flamegraph/flamegraph.js @@ -1,8 +1,9 @@ "use strict"; -var details, searchbtn, unzoombtn, matchedtxt, svg, searching, frames, known_font_width; +var details, searchbtn, ignorecasebtn, unzoombtn, matchedtxt, svg, searching, frames, known_font_width, case_insensitive, current_search_term; function init(evt) { details = document.getElementById("details").firstChild; searchbtn = document.getElementById("search"); + ignorecasebtn = document.getElementById("ignorecase"); unzoombtn = document.getElementById("unzoom"); matchedtxt = document.getElementById("matched"); svg = document.getElementsByTagName("svg")[0]; @@ -10,6 +11,8 @@ function init(evt) { known_font_width = get_monospace_width(frames); total_samples = parseInt(frames.attributes.total_samples.value); searching = 0; + case_insensitive = 0; + current_search_term = null; // Use GET parameters to restore a flamegraph's state. var restore_state = function() { @@ -41,7 +44,8 @@ function init(evt) { // Keep search elements at a fixed distance from right edge. var svgWidth = svg.width.baseVal.value; - searchbtn.attributes.x.value = svgWidth - xpad; + ignorecasebtn.attributes.x.value = svgWidth - xpad; + searchbtn.attributes.x.value = svgWidth - xpad - fontsize * fontwidth * 4; matchedtxt.attributes.x.value = svgWidth - xpad; }; window.addEventListener('resize', function() { @@ -87,6 +91,7 @@ window.addEventListener("click", function(e) { history.replaceState(null, null, parse_params(params)); } else if (e.target.id == "search") search_prompt(); + else if (e.target.id == "ignorecase") toggle_ignorecase(); }, false) // mouse-over for info // show @@ -106,6 +111,13 @@ window.addEventListener("keydown",function (e) { search_prompt(); } }, false) +// ctrl-I to toggle case-insensitive search +window.addEventListener("keydown",function (e) { + if (e.ctrlKey && e.keyCode === 73) { + e.preventDefault(); + toggle_ignorecase(); + } +}, false) // functions function get_params() { var params = {}; @@ -375,14 +387,17 @@ function reset_search() { } function search_prompt() { if (!searching) { + var casemsg = case_insensitive ? ", ignoring case" : ""; var term = prompt("Enter a search term (regexp " + - "allowed, eg: ^ext4_)", ""); + "allowed, eg: ^ext4_)" + casemsg + "\nPress Ctrl+i to toggle case sensitivity", ""); if (term != null) { + current_search_term = term; search(term) } } else { reset_search(); searching = 0; + current_search_term = null; searchbtn.classList.remove("show"); searchbtn.firstChild.nodeValue = "Search" matchedtxt.classList.add("hide"); @@ -390,7 +405,7 @@ function search_prompt() { } } function search(term) { - var re = new RegExp(term); + var re = new RegExp(term, case_insensitive ? "i" : ""); var el = frames.children; var matches = new Object(); var maxwidth = 0; @@ -465,6 +480,19 @@ function search(term) { if (pct != 100) pct = pct.toFixed(1); matchedtxt.firstChild.nodeValue = "Matched: " + pct + "%"; } +function toggle_ignorecase() { + case_insensitive = !case_insensitive; + if (case_insensitive) { + ignorecasebtn.classList.add("show"); + } else { + ignorecasebtn.classList.remove("show"); + } + if (searching && current_search_term != null) { + reset_search(); + searching = 0; + search(current_search_term); + } +} function format_percent(n) { return n.toFixed(4) + "%"; } diff --git a/src/flamegraph/svg.rs b/src/flamegraph/svg.rs index 23d3924a..dbc71a78 100644 --- a/src/flamegraph/svg.rs +++ b/src/flamegraph/svg.rs @@ -232,12 +232,26 @@ text {{ font-family:{}; font-size:{}px }} }, )?; + // "ic" indicator for case-insensitive search, right-aligned at the edge write_str( svg, &mut buf, TextItem { x: Dimension::Pixels(image_width as usize - super::XPAD), y: (opt.font_size * 2) as f64, + text: "ic".into(), + extra: vec![("id", "ignorecase"), ("fill", &style_options.uicolor)], + }, + )?; + + // Search button, shifted left to make room for the "ic" indicator + let ic_offset = (opt.font_size as f64 * opt.font_width * 4.0) as usize; + write_str( + svg, + &mut buf, + TextItem { + x: Dimension::Pixels(image_width as usize - super::XPAD - ic_offset), + y: (opt.font_size * 2) as f64, text: "Search".into(), extra: vec![("id", "search"), ("fill", &style_options.uicolor)], }, From ef69c5730e1ff2d44c0494779f24a11743618fb4 Mon Sep 17 00:00:00 2001 From: Jeff Putlock Date: Mon, 4 May 2026 17:28:48 -0400 Subject: [PATCH 2/5] add tooltip --- src/flamegraph/svg.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/flamegraph/svg.rs b/src/flamegraph/svg.rs index dbc71a78..676fc77a 100644 --- a/src/flamegraph/svg.rs +++ b/src/flamegraph/svg.rs @@ -232,19 +232,24 @@ text {{ font-family:{}; font-size:{}px }} }, )?; - // "ic" indicator for case-insensitive search, right-aligned at the edge - write_str( - svg, - &mut buf, - TextItem { - x: Dimension::Pixels(image_width as usize - super::XPAD), - y: (opt.font_size * 2) as f64, - text: "ic".into(), - extra: vec![("id", "ignorecase"), ("fill", &style_options.uicolor)], - }, - )?; + { + let x = write!(buf, "{:.2}", image_width as usize - super::XPAD); + let y = write!(buf, "{:.2}", (opt.font_size * 2) as f64); + svg.write_event(Event::Start(BytesStart::new("text").with_attributes( + args!( + "id" => "ignorecase", + "fill" => &*style_options.uicolor, + "x" => &buf[x], + "y" => &buf[y] + ), + )))?; + svg.write_event(Event::Start(BytesStart::new("title")))?; + svg.write_event(Event::Text(BytesText::new("ignore case")))?; + svg.write_event(Event::End(BytesEnd::new("title")))?; + svg.write_event(Event::Text(BytesText::new("ic")))?; + svg.write_event(Event::End(BytesEnd::new("text")))?; + } - // Search button, shifted left to make room for the "ic" indicator let ic_offset = (opt.font_size as f64 * opt.font_width * 4.0) as usize; write_str( svg, From 24d6d6aa9e5622f3e249eb972dafccebe1c2957f Mon Sep 17 00:00:00 2001 From: Jeff Putlock Date: Mon, 4 May 2026 17:54:53 -0400 Subject: [PATCH 3/5] Fix false optimization where search only occurs if matched --- src/flamegraph/flamegraph.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flamegraph/flamegraph.js b/src/flamegraph/flamegraph.js index f764c19d..2fd5e8a0 100644 --- a/src/flamegraph/flamegraph.js +++ b/src/flamegraph/flamegraph.js @@ -487,7 +487,7 @@ function toggle_ignorecase() { } else { ignorecasebtn.classList.remove("show"); } - if (searching && current_search_term != null) { + if (current_search_term != null) { reset_search(); searching = 0; search(current_search_term); From a1bdb3459cf2b2a521d6296dfd00531642d2e255 Mon Sep 17 00:00:00 2001 From: Jeff Putlock Date: Mon, 4 May 2026 18:29:08 -0400 Subject: [PATCH 4/5] add ic to params --- src/flamegraph/flamegraph.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/flamegraph/flamegraph.js b/src/flamegraph/flamegraph.js index 2fd5e8a0..39226f03 100644 --- a/src/flamegraph/flamegraph.js +++ b/src/flamegraph/flamegraph.js @@ -19,8 +19,14 @@ function init(evt) { var params = get_params(); if (params.x && params.y) zoom(find_group(document.querySelector('[*|x="' + params.x + '"][y="' + params.y + '"]'))); - if (params.s) + if (params.s) { + if (params.ic) { + case_insensitive = 1; + ignorecasebtn.classList.add("show"); + } + current_search_term = params.s; search(params.s); + } }; if (fluiddrawing) { @@ -383,6 +389,7 @@ function reset_search() { } var params = get_params(); delete params.s; + delete params.ic; history.replaceState(null, null, parse_params(params)); } function search_prompt() { @@ -444,6 +451,11 @@ function search(term) { return; var params = get_params(); params.s = term; + if (case_insensitive) { + params.ic = "1"; + } else { + delete params.ic; + } history.replaceState(null, null, parse_params(params)); searchbtn.classList.add("show"); From a44eb4f0ccc07e678ad431ac5df47df2fa9cbcb1 Mon Sep 17 00:00:00 2001 From: Jeff Putlock Date: Mon, 4 May 2026 23:11:25 -0400 Subject: [PATCH 5/5] fix linger when disabling --- src/flamegraph/flamegraph.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/flamegraph/flamegraph.js b/src/flamegraph/flamegraph.js index 39226f03..8ccb6a71 100644 --- a/src/flamegraph/flamegraph.js +++ b/src/flamegraph/flamegraph.js @@ -447,8 +447,13 @@ function search(term) { searching = 1; } } - if (!searching) + if (!searching) { + searchbtn.classList.remove("show"); + searchbtn.firstChild.nodeValue = "Search"; + matchedtxt.classList.add("hide"); + matchedtxt.firstChild.nodeValue = ""; return; + } var params = get_params(); params.s = term; if (case_insensitive) {