Skip to content

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

Merged
fatadel merged 6 commits intofirefox-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 intofirefox-devtools:mainfrom
fatadel:highlight-node-1818

Conversation

@fatadel
Copy link
Copy Markdown
Contributor

@fatadel fatadel commented Apr 2, 2026

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
Copy link
Copy Markdown

codecov Bot commented Apr 2, 2026

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 julienw April 2, 2026 16:01
@mstange
Copy link
Copy Markdown
Contributor

mstange commented Apr 2, 2026

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

canova commented Apr 7, 2026

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

canova commented Apr 7, 2026

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
Contributor Author

fatadel commented Apr 7, 2026

@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
Contributor Author

fatadel commented Apr 7, 2026

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 commented Apr 7, 2026

@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

julienw commented Apr 7, 2026

@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
Contributor Author

fatadel commented Apr 7, 2026

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

@fatadel fatadel force-pushed the highlight-node-1818 branch 2 times, most recently from 6d0f011 to 7c6932b Compare April 9, 2026 11:23
@fatadel
Copy link
Copy Markdown
Contributor Author

fatadel commented Apr 9, 2026

Done ✅
Looks like this. Please review :)

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

@fatadel fatadel force-pushed the highlight-node-1818 branch 2 times, most recently from 37fd131 to c9c8f24 Compare April 9, 2026 12:49
@fatadel
Copy link
Copy Markdown
Contributor Author

fatadel commented Apr 9, 2026

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 fatadel force-pushed the highlight-node-1818 branch from c9c8f24 to 91c3350 Compare April 14, 2026 10:15
@fatadel
Copy link
Copy Markdown
Contributor Author

fatadel commented Apr 14, 2026

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 10 CleanShot 2026-04-14 at 12 46 59

@fatadel
Copy link
Copy Markdown
Contributor Author

fatadel commented Apr 14, 2026

@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 14 Screenshot 2026-04-14 at 13 27 56

@fatadel fatadel force-pushed the highlight-node-1818 branch from 91c3350 to 800a532 Compare April 14, 2026 11:36
@fatadel
Copy link
Copy Markdown
Contributor Author

fatadel commented Apr 14, 2026

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
Contributor Author

fatadel commented Apr 14, 2026

@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
Contributor Author

fatadel commented Apr 14, 2026

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 fatadel force-pushed the highlight-node-1818 branch from 800a532 to dcde905 Compare April 14, 2026 13:43
@fatadel fatadel requested review from fqueze and mstange April 15, 2026 08:35
Copy link
Copy Markdown
Member

@canova canova left a comment

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 thread src/components/stack-chart/Canvas.tsx Outdated
Comment thread src/components/stack-chart/Canvas.tsx Outdated
@fatadel fatadel force-pushed the highlight-node-1818 branch from dcde905 to 181fe4b Compare April 16, 2026 12:03
@fatadel fatadel requested a review from canova April 17, 2026 07:55
@fatadel fatadel force-pushed the highlight-node-1818 branch from f6711c7 to b8b0c30 Compare April 17, 2026 08:12
Comment thread src/selectors/per-thread/thread.tsx Outdated
Comment thread src/selectors/per-thread/thread.tsx Outdated
fatadel added 3 commits April 20, 2026 10:53
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 fatadel force-pushed the highlight-node-1818 branch from b8b0c30 to ecb79e5 Compare April 20, 2026 08:54
@fatadel
Copy link
Copy Markdown
Contributor Author

fatadel commented Apr 20, 2026

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

@fatadel fatadel requested a review from canova April 20, 2026 09:25
Copy link
Copy Markdown
Member

@canova canova left a comment

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 thread src/profile-logic/profile-data.ts Outdated
Comment thread src/profile-logic/profile-data.ts Outdated
Comment thread src/profile-logic/profile-data.ts Outdated
fatadel added 2 commits April 20, 2026 13:58
- 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
Contributor Author

fatadel commented Apr 20, 2026

@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 canova April 20, 2026 12:37
Copy link
Copy Markdown
Member

@canova canova left a comment

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:main Apr 20, 2026
20 of 21 checks passed
@fatadel fatadel deleted the highlight-node-1818 branch April 20, 2026 15:14
@fatadel fatadel changed the title Highlight matched nodes in the stack chart when searching Dim non-matching nodes in the stack chart when searching Apr 20, 2026
Sign up for free to 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