Skip to content

Hide the user interface components showing stacks for tracks that don't have stack samples#4133

Merged
canova merged 1 commit into
firefox-devtools:mainfrom
fqueze:nostacksampling
Jul 19, 2022
Merged

Hide the user interface components showing stacks for tracks that don't have stack samples#4133
canova merged 1 commit into
firefox-devtools:mainfrom
fqueze:nostacksampling

Conversation

@fqueze

@fqueze fqueze commented Jul 7, 2022

Copy link
Copy Markdown
Contributor

This is to help with profiles where either the nostacksampling or the markersallthreads.

When nostacksampling is used, we have samples that only contain a '(root)' frame. When markersallthreads is used, we have some tracks that have no samples at all. In both cases, the Call Tree, Flame Graph and Stack Chart panels are useless, and having the Marker Chart selected by default would be a lot more useful.

Additionally, when we didn't sample the stack but still sampled the CPU, hovering the timeline in areas where some CPU was used shows a tooltip with the CPU percentage (good!) but also a broken empty stack with the unknown category and a single "(root)" frame. I think it's better to hide this stack to avoid distracting the user from the CPU use information that actually exists.

Example profiles:

@fqueze fqueze requested a review from canova July 7, 2022 22:06
@codecov

codecov Bot commented Jul 7, 2022

Copy link
Copy Markdown

Codecov Report

Merging #4133 (541ebe8) into main (4899f7e) will decrease coverage by 0.00%.
The diff coverage is 93.93%.

❗ Current head 541ebe8 differs from pull request most recent head 59456aa. Consider uploading reports for the commit 59456aa to get more accurate results

@@            Coverage Diff             @@
##             main    #4133      +/-   ##
==========================================
- Coverage   88.27%   88.27%   -0.01%     
==========================================
  Files         280      280              
  Lines       24388    24410      +22     
  Branches     6477     6496      +19     
==========================================
+ Hits        21529    21548      +19     
- Misses       2655     2658       +3     
  Partials      204      204              
Impacted Files Coverage Δ
src/actions/profile-view.js 83.30% <83.33%> (ø)
src/components/shared/SampleTooltipContents.js 93.75% <91.66%> (-1.25%) ⬇️
src/app-logic/tabs-handling.js 100.00% <100.00%> (ø)
src/selectors/per-thread/composed.js 100.00% <100.00%> (ø)
src/test/fixtures/utils.js 95.65% <0.00%> (-0.39%) ⬇️
src/components/timeline/TrackMemoryGraph.js 92.10% <0.00%> (-0.16%) ⬇️
src/components/timeline/TrackPowerGraph.js 92.61% <0.00%> (-0.15%) ⬇️
src/components/timeline/TrackProcessCPUGraph.js 93.61% <0.00%> (-0.14%) ⬇️
src/components/timeline/LocalTrack.js 71.87% <0.00%> (-0.08%) ⬇️
src/selectors/profile.js 96.98% <0.00%> (-0.02%) ⬇️
... and 4 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4899f7e...59456aa. Read the comment docs.

@canova canova 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 for the PR Florian and sorry for the late review. This PR somehow slipped through the cracks.

Looks pretty good to me! Thanks for hiding these unnecessary tabs and UI elements when they are not useful. I've added some small nits, we can land it after these small changes.

Comment thread src/selectors/per-thread/composed.js Outdated
threadSelectors.getJsTracerTable,
({ processType }, isNetworkChartEmpty, jsTracerTable) => {
(
{ processType, samples, stackTable, stringTable, frameTable, funcTable },

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.

nit: It could be better to do this destruction below inside the function. I think it's easy to understand when we only destruct one or two fields here, but when it gets crowded, it becomes a bit hard to read. Instead we can do
const { processType, samples, stackTable, stringTable, frameTable, funcTable } = thread;
below.

if (stringTable.getString(stringIndex) === '(root)') {
// If the first sample's stack is only the root, check if any other
// sample is different.
hasSamples = samples.stack.some((s) => s !== stackIndex);

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.

Hm, this looks a bit costly, but probably it's going to return early after two iterations for most of our profiles. And not sure how else we can do it without looping. I think it's okay to keep like this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

it could be faster to:

  1. get the string index for (root) outside of the loop
  2. compare string indexes here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The .some call (assuming that's what is being called 'loop' in these comments) should only be done for profiles where the first sample contains a single frame, and then we only compare one integer with an array of integers. That should be fast enough, and we will only compare the entire array of integers (one per sample) when the profile was captured with nostacksampling and all the sample contain only "(root)".

Comment thread src/selectors/per-thread/composed.js Outdated
if (!hasSamples) {
visibleTabs = visibleTabs.filter(
(tabSlug) =>
!['calltree', 'flame-graph', 'stack-chart'].includes(tabSlug)

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.

Could you move this array to app-logic/tab-handling.js file so we can keep them in sync in case we add another tab that shows samples related visualization? Maybe we can name it something like tabsShowingSampleData or sampleDataTabs or something else?

rangeFilteredThread
);
hasStack = stack.length > 1 || stack[0].funcName !== '(root)';
}

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.

It's a good idea to hide the stacks if we only have (root)! It wasn't looking good anyways.

@@ -33,9 +33,6 @@ describe('getUsefulTabs', function () {
const profile = getProfileWithMarkers(getNetworkMarkers());

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.

Could you add a small tests for this new behavior too? We already see that in some of the tests, we don't have the sample related tabs anymore since the profiles only include markers, but it could be nice to add a simple test that checks this new behavior only.
The test name could be something like does not show sample related tabs when there is no sample data in the profile and it could test a profile like const profile = getMarkerTableProfile() or getProfileWithMarkers(getNetworkMarkers());

@fqueze fqueze force-pushed the nostacksampling branch from 3c0d0f3 to 541ebe8 Compare July 18, 2022 18:37
@fqueze fqueze requested a review from canova July 18, 2022 18:43

@canova canova 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 for adding some tests and working on this! Looks great to me.

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.

3 participants