Skip to content

Dim non-matching nodes in the stack chart when searching - #5935

Merged
fatadel merged 6 commits into
firefox-devtools:mainfrom
fatadel:highlight-node-1818
Apr 20, 2026
Merged

Dim non-matching nodes in the stack chart when searching#5935
fatadel merged 6 commits into
firefox-devtools:mainfrom
fatadel:highlight-node-1818

Conversation

@fatadel

@fatadelfatadel commented Apr 2, 2026

Copy link
Copy Markdown
Contributor

Closes#1818.

When the search box is active, the stack chart now dims funcs that don't
match the search, making hits visually scannable without losing the
surrounding context. Matching is OR-combined across comma-separated
search strings (a func is highlighted if any term matches its name,
filename, or library), while the existing stack-drop behavior keeps its
AND semantics.

The match computation lives in a memoized selector
(computeSearchStringFilterOutput) that returns both the stack-drop
TransformOutput and a combined func-match BitSet, shared between
getFilteredThread and getSearchFilteredFuncMatchesBitSet. The canvas
draw loop does a single checkBit lookup per node instead of rebuilding
a Set and re-running string matching on every frame.

This is the profile from the STR of the original issue with the changes of this PR.

@codecov

codecovBot commented Apr 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.33%. Comparing base (4308a73) to head (1289c9b).
⚠️ Report is 5 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #5935 +/- ##
==========================================
- Coverage 85.37% 85.33% -0.04% 
==========================================
Files 322 322 Lines 32069 32117 +48 Branches 8814 8744 -70 ==========================================
+ Hits 27378 27408 +30 - Misses 4260 4278 +18 
Partials 431 431 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@fatadel
fatadel requested review from canova and julienwApril 2, 2026 16:01
@mstange

Copy link
Copy Markdown
Contributor

Before reviewing the code changes, I would like you to have a look visually and tell me if that is what you want to see 🤓

Looks acceptable to me visually. Not super pretty but good enough :)

@canova

Copy link
Copy Markdown
Member

Hm, I'm surprised that the ancestors are also highlighted. I think it adds more visual noise than value. I think it might be better to highlight only the matching nodes, or to see a prototype of it. For example, we also only highlight the matching nodes in the call tree. @mstange wdyt?

For example, looking at chrome's devtools: when you search something, it shows only the matching nodes with their real color:

Screenshot 2026-04-07 at 12 42 49

@canova

Copy link
Copy Markdown
Member

Also visualization-wise, I was thinking about dimming the unmatched nodes (graying them out) like chrome does. But I'm not so sure if it's better than the current one yet.

@fatadel

Copy link
Copy Markdown
ContributorAuthor

@canova I've initially implemented this feature highlighting only the target nodes but then I've noticed this comment from @julienw and therefore re-implemented to highlight the whole path :) I am open to any solution. I like the one you've shared tbh.

@fatadel

Copy link
Copy Markdown
ContributorAuthor

Also visualization-wise, I was thinking about dimming the unmatched nodes (graying them out) like chrome does. But I'm not so sure if it's better than the current one yet.

Yeah it sounds more visually appealing to me too :)

@canova

Copy link
Copy Markdown
Member

@canova I've initially implemented this feature highlighting only the target nodes but then I've noticed this comment from @julienw and therefore re-implemented to highlight the whole path :) I am open to any solution. I like the one you've shared tbh.

Oh interesting. I don't think I agree with that comment tbh. Since we do the filtering already, only the roots with matching child will be included in the filtered stack chart. I don't really see the benefit of having these highlighted. Happy to hear counter arguments though.

@julienw

Copy link
Copy Markdown
Contributor

@canova I've initially implemented this feature highlighting only the target nodes but then I've noticed this comment from @julienw and therefore re-implemented to highlight the whole path :) I am open to any solution. I like the one you've shared tbh.

Oh interesting. I don't think I agree with that comment tbh. Since we do the filtering already, only the roots with matching child will be included in the filtered stack chart. I don't really see the benefit of having these highlighted. Happy to hear counter arguments though.

I think that highlighting just the child works when the child's node is wide enough to be seen, but when it's super small to the point that it's barely visible or even not visible, then it's difficult to understand what's going on IMO. That's why I was mentioning this possible solution.
But if you're dimming the non-ancestor nodes, that might work too! It's worth trying

@fatadel

Copy link
Copy Markdown
ContributorAuthor

Sounds good, let me re-implement with dimming then.

@fatadel
fatadelforce-pushed the highlight-node-1818 branch 2 times, most recently from 6d0f011 to 7c6932bCompareApril 9, 2026 11:23
@fatadel

Copy link
Copy Markdown
ContributorAuthor

Done ✅
Looks like this. Please review :)

Screen.Recording.2026-04-09.at.13.25.57.mov

@fatadel
fatadelforce-pushed the highlight-node-1818 branch 2 times, most recently from 37fd131 to c9c8f24CompareApril 9, 2026 12:49
@fatadel

Copy link
Copy Markdown
ContributorAuthor

The video above is slightly invalid because it was recorded with dimming opacity of 0.2 and currently it's set to 0.5 (after discussing with @canova)

@nchevobbe

Copy link
Copy Markdown
Member

In the #5935 (comment) screencast, the dimmed text is definitely not accessible (I'm seeing some light grey text on white background with 1.4:1 contrast ratio)
If the text is going to be displayed, I'd argue it should be visible
I see that for those dimmed nodes, you're tweaking the opacity; in the past I found it quite hard to then work out proper contrast ratio when custom opacity are applied, I'd rather have specific dimmed background/foreground colors. Also, this would make it easier to handle High Contrast Mode too, where we can use https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/system-color#accentcolor:~:text=GrayText to convey the "dimmed" aspect. Finally, it would be nice to see how this work in dark mode, to make sure the contrasts are good too :)

Ideally, for accessibility, any state change shouldn't be conveyed only by a change in colors, so maybe here we should flip things: keep the node as they are now, and make the one that matches the search very visible, e.g. with a 2px outline, or a specific icon ?

@nchevobbe

Copy link
Copy Markdown
Member

Ideally, for accessibility, any state change shouldn't be conveyed only by a change in colors, so maybe here we should flip things: keep the node as they are now, and make the one that matches the search very visible, e.g. with a 2px outline, or a specific icon ?

or maybe we remove the background color from the "dimmed" nodes and only have a border on them. They would appear quite differently from the matching ones and it would be less tricky to find the right colors. We could still tweak the dimmed node text color so they feel less important

@fatadel
fatadelforce-pushed the highlight-node-1818 branch from c9c8f24 to 91c3350CompareApril 14, 2026 10:15
@fatadel

Copy link
Copy Markdown
ContributorAuthor

Thanks everyone for your feedback! Could you please have another look? Now I use a neutral color to make nodes look dimmed and I change the font colors too, keeping the nodes accessible. Should work fine in both light and dark modes. This is close to the way Chrome does (@canova's screenshot above).

Here is the link.

@nchevobbe

Copy link
Copy Markdown
Member

@fatadel I'm still seeing the dimmed nodes failing AA contrast (using https://vispero.com/lp/color-contrast-checker/):

4.4:1 in light mode, and 3:1 in dark mode (see screenshots below)
I didn't check high contrast mode yet

CleanShot 2026-04-14 at 12 46 10CleanShot 2026-04-14 at 12 46 59

@fatadel

Copy link
Copy Markdown
ContributorAuthor

@nchevobbe That's strange tbh. I did the same measurements and I got the following. Are you sure you're checking correctly in the light mode? I will tweak the font colors in the dark mode.

Screenshot 2026-04-14 at 13 26 14Screenshot 2026-04-14 at 13 27 56

@fatadel
fatadelforce-pushed the highlight-node-1818 branch from 91c3350 to 800a532CompareApril 14, 2026 11:36
@fatadel

Copy link
Copy Markdown
ContributorAuthor

Now the dark mode should also pass the contrast ratio tests.

@nchevobbe

Copy link
Copy Markdown
Member

@nchevobbe That's strange tbh. I did the same measurements and I got the following. Are you sure you're checking correctly in the light mode?

Ah, must have picked a subpixel area which didn't hold the correct color. Looks fine given your screenshot then :)

Now the dark mode should also pass the contrast ratio tests.

Nice, thanks! Would you have a link / screenshot for it?

@nchevobbe

Copy link
Copy Markdown
Member

It looks fine on Windows light and dark High Contrast Mode
The stacktrace and flame graphs are not necessarily supporting HCM at the moment (I think we're not using High Contrast specific colors for the nodes), so this dimmed nodes doesn't look at odd with the current style.
Maybe worth adding as an item to check (in #5218) when adding proper HCM support in those panels

@fatadel

Copy link
Copy Markdown
ContributorAuthor

@nchevobbe That's strange tbh. I did the same measurements and I got the following. Are you sure you're checking correctly in the light mode?

Ah, must have picked a subpixel area which didn't hold the correct color. Looks fine given your screenshot then :)

Now the dark mode should also pass the contrast ratio tests.

Nice, thanks! Would you have a link / screenshot for it?

Sure, here you are.

image

@fatadel

Copy link
Copy Markdown
ContributorAuthor

It looks fine on Windows light and dark High Contrast Mode The stacktrace and flame graphs are not necessarily supporting HCM at the moment (I think we're not using High Contrast specific colors for the nodes), so this dimmed nodes doesn't look at odd with the current style. Maybe worth adding as an item to check (in #5218) when adding proper HCM support in those panels

Sounds good 👍🏻 Did you already add it, or should I?

@nchevobbe

Copy link
Copy Markdown
Member

Sure, here you are.
image

that's great, thanks!

It looks fine on Windows light and dark High Contrast Mode The stacktrace and flame graphs are not necessarily supporting HCM at the moment (I think we're not using High Contrast specific colors for the nodes), so this dimmed nodes doesn't look at odd with the current style. Maybe worth adding as an item to check (in #5218) when adding proper HCM support in those panels

Sounds good 👍🏻 Did you already add it, or should I?

I added an item in the list of tasks there :)

@fatadel
fatadelforce-pushed the highlight-node-1818 branch from 800a532 to dcde905CompareApril 14, 2026 13:43
@fatadel
fatadel requested review from fqueze and mstangeApril 15, 2026 08:35

@canovacanova left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! The UI-wise it looks good to me. I believe the performance-wise we can improve it, but the suggestion I made below is a much larger change. And I didn't notice a lot of perf issues using the deploy preview. So I'm okay with landing it this way and filing an issue for the improvements.

Comment threadsrc/components/stack-chart/Canvas.tsx Outdated
Comment threadsrc/components/stack-chart/Canvas.tsx Outdated
@fatadel
fatadelforce-pushed the highlight-node-1818 branch from dcde905 to 181fe4bCompareApril 16, 2026 12:03
@fatadel
fatadel requested a review from canovaApril 17, 2026 07:55
@fatadel
fatadelforce-pushed the highlight-node-1818 branch from f6711c7 to b8b0c30CompareApril 17, 2026 08:12
Comment threadsrc/selectors/per-thread/thread.tsx Outdated
Comment threadsrc/selectors/per-thread/thread.tsx Outdated
Extract computeFuncMatchesSearchString from _computeStackMatchesSearchString
so it can be reused. Add a getSearchFilteredFuncMatchesBitSet selector that
computes a BitSet of matching func indices, memoized so it only recomputes
when the search string or thread changes. The stack chart canvas now does a
simple checkBit lookup per node instead of rebuilding a Set with string
matching on every draw call.
Replace the separate memoized computeFuncMatchesSearchString and
computeTransformOutputForSearchStringFilter with a single
computeSearchStringFilterOutput that returns both the stack-drop
TransformOutput and the combined func-match BitSet. getFilteredThread
and getSearchFilteredFuncMatchesBitSet now share one selector and the
per-string func bitset is computed only once.
Also fix multi-string highlighting: funcs are now OR-combined across
search strings (highlight if any match) while stacks keep the existing
AND semantics (drop unless every search string matches somewhere in
the ancestry). Adds combineTwoBitSetsWithOr alongside the existing
combineTwoBitSetsWithAnd helper.
@fatadel
fatadelforce-pushed the highlight-node-1818 branch from b8b0c30 to ecb79e5CompareApril 20, 2026 08:54
@fatadel

Copy link
Copy Markdown
ContributorAuthor

Thanks for your feedback, @canova! I hope I have now fully addressed it.

@fatadel
fatadel requested a review from canovaApril 20, 2026 09:25

@canovacanova left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! It looks like we now successfully use the already computed funcTable output. Looks good to me!

One another nit that could be a follow-up: I see that there are tests for the highlighting in the stack chart. But we don't really have tests for the logic where we find which frames to highlight (for example AND -> OR change didn't require any test change). It would be good to add tests for that logic as a follow-up. It would be good to file an issue for it at least.

Comment threadsrc/profile-logic/profile-data.ts Outdated
Comment threadsrc/profile-logic/profile-data.ts Outdated
Comment threadsrc/profile-logic/profile-data.ts Outdated
- Rename SearchStringFilterOutput.funcMatches to funcMatchesSearchStrings
for a more explicit name.
- Drop the redundant .filter((s) => s) pass; splitSearchString already
strips empty search strings.
- Initialize the combined bitsets from the first search string instead
of from null, so the loop no longer needs per-iteration null checks
and the tail no longer needs a ?? null coercion.
Covers which funcs end up highlighted in the stack chart when the
search box is active: matches by function name, filename, or library
name, and the OR semantics when multiple comma-separated search strings
are provided, including the case where two different strings each match
a different func.
@fatadel

Copy link
Copy Markdown
ContributorAuthor

@canova I've addressed your nits and added the missing test cases. Really don't want to split this into follow-ups 😅
Could you please have one last look? 🙏🏻 (you only need to check the last two commits)

@fatadel
fatadel requested a review from canovaApril 20, 2026 12:37

@canovacanova left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@fatadel
fatadel merged commit 484cfd2 into firefox-devtools:mainApr 20, 2026
20 of 21 checks passed
@fatadel
fatadel deleted the highlight-node-1818 branch April 20, 2026 15:14
@fatadelfatadel changed the title Highlight matched nodes in the stack chart when searchingDim non-matching nodes in the stack chart when searchingApr 20, 2026
@fatadelfatadel mentioned this pull request Apr 28, 2026
fatadel added a commit that referenced this pull request Apr 28, 2026
Changes:
[Nazım Can Altınova] Add Adel to the automatic dependency reviews
(#5930)
[fatadel] Fix arrow panel appearing behind marker tooltips (#5926)
[fatadel] Upgrade Node.js from v22 to v24 (#5923)
[Markus Stange] Use createStackTableBySkippingDiscarded in focusSelf.
(#5916)
[Markus Stange] Propagate isJS to symbolicated funcs (#5907)
[Markus Stange] Always render the CPU-usage-aware activity graph when
CPU information is available (#5918)
[Nazım Can Altınova] Fallback to javascript highlighting in the source
view as a backup (#5936)
[Nazım Can Altınova] Properly type the return value of
_languageExtForPath (#5937)
[Nazım Can Altınova] Update typescript eslint dependencies (#5938)
[Markus Stange] Modernize more of the transform functions (#5934)
[Paul Adenot] Fix extractGeckoLogs for structured Log marker format (bug
2022540) (#5927)
[Nazım Can Altınova] Move some profile fetching code into a separate
module. (#5939)
[Markus Stange] Update the hovered item when panning any viewport canvas
(#5903)
[Markus Stange] Migrate Home page animation to CSS transitions and
remove react-transition-group (#5649)
[Nazım Can Altınova] Fix test/lint commands on Windows and fix CI
(#5947)
[Nazım Can Altınova] Convert profile-logic/js-tracer.tsx to a ts file
(#5942)
[Markus Stange] Remove panelLayoutGeneration (#5946)
[fatadel] Add CounterDisplayConfig to counters in the processed profile
format (#5912)
[Nazım Can Altınova] Fix eslint-config-prettier silently overriding
custom rules (#5955)
[fatadel] Dim non-matching nodes in the stack chart when searching
(#5935)
[Nazım Can Altınova] Fix loading .json.gz profiles from inside zip
archives (#5959)
[Ryan Hunt] Add a fullscreen button to the bottom box (#5605)
[Markus Stange] Speed up _computeCallNodeTableHierarchy by keeping
siblings ordered by func (#5964)
[Markus Stange] Replace symbolicator-cli with a profiler-edit node tool
(#5965)
[Nazım Can Altınova] Add "Include idle samples" toggle to the call tree
settings (#5968)
[Nazım Can Altınova] Add dark mode versions of the fullscreen icons
(#5972)
[fatadel] Replace 4 counter track components with a single generic
TrackCounter (#5944)
[fatadel] Use ephemeral port for esbuild's internal dev server (#5974)
[carverdamien] Remove category from LongTaskMarkerPayload (#5975)
And special thanks to our localizers:
de: Ger de: Michael Köhler el: Jim Spentzos en-GB: Ian Neal es-CL: ravmn fr: Théo Chevalier ia: Melo46 it: Francesco Lodolo [:flod] nl: Mark Heijl pt-BR: Marcelo Ghelman ru: Valery Ledovskoy ru: berry sv-SE: Andreas Pettersson tr: Grk zh-CN: Olvcpr423 zh-CN: wxie zh-TW: Pin-guang Chen
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

When searching in the stack chart, the matched nodes should be highlighted

5 participants

@fatadel@mstange@canova@julienw@nchevobbe