Skip to content

Conversation

@JonasBa
Copy link
Member

@JonasBa JonasBa commented Feb 10, 2022

Still very rough - I didnt take most of the design, but the functionality is there (we need to make it more bulletproof and add some limitations). I dont want to optimize anything early, but once we have some traces that we can stress test the search with, we should have a good idea of where the bottlenecks are.
CleanShot 2022-02-10 at 11 11 33

@JonasBa JonasBa requested a review from a team as a code owner February 10, 2022 10:23
@JonasBa JonasBa requested a review from Zylphrex February 10, 2022 10:23
// where flamegraphRenderer is not null (see check on L86)
if (flamegraphRenderer === null) {
return;
if (flamegraphRenderer) {
Copy link
Member

Choose a reason for hiding this comment

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

If you change these to use arrow functions, I think the scoping rules ensures that flamegraphRenderer is non null after the check from above

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually, I think my comment was wrong and why I removed it. Imagine if we at some point clear the flamegraph renderer but forget to clear the handlers, then our scheduler may still call the draw call and it would throw because flamegraphRenderer is now null

Comment on lines +215 to +227
newScheduler.on('searchResults', (results: Record<string, FlamegraphFrame>) => {
newScheduler.unregisterBeforeFrameCallback(drawRectangles);

function newDrawRectangles() {
if (flamegraphRenderer) {
flamegraphRenderer.draw(results);
}
}
newScheduler.registerBeforeFrameCallback(newDrawRectangles);

newScheduler.onDispose(() =>
newScheduler.unregisterBeforeFrameCallback(newDrawRectangles)
);
Copy link
Member

Choose a reason for hiding this comment

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

not a big fan of this approach, would storing the results as a state be cleaner?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I was debating between that and storing the results. The difference here is that if we pass searchresults to this effect, we end up recreating all the renderers (unless we split each renderer to it's own useEffect init), but here we instead just replace the draw call. I think we need to figure out a good sort of "swap" mechanism here, I'm not even sure about the whole canvasScheduler and how well that will scale tbh

Copy link
Member Author

Choose a reason for hiding this comment

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

If you have some ideas about this, I'd love to hear them. We want a system that allows us to enqueue calls in some order and replace them. Maybe the easiest way here is to just isolate each renderer to it's own effect

Copy link
Member

Choose a reason for hiding this comment

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

I took a pass over in #31639 where I lifted all the renderers out of useEffect using useMemo. In that scenario, I think if we used a ref to store the search results to avoid recreating everything, the .draw immediately after should accomplish what we want here. It's quite a refactor for an already large PR, so I'm happy to leave this as is and resolve this in a follow up.

for (let i = 0; i < allFrames.length; i++) {
const frame = allFrames[i];

if (userQuery.test(frame.frame.name.trim())) {
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes it will indeed. Wdyt would be a good way of handling it? we could disable /g flag, but we need to add a warning for it then

Copy link
Member

Choose a reason for hiding this comment

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

We could recreate the regex on every iteration or manually reset lastIndex

Copy link
Member Author

Choose a reason for hiding this comment

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

That's what I went with in the end, I was a bit worried we may have a large performance overhead, but then I read that it seems that regexp objects are pretty heavily optimized and cached. Not going to worry about it until it becomes a problem

@JonasBa JonasBa force-pushed the jb/profiling/flamegraph-view-select branch from fff0334 to 64af0cd Compare February 11, 2022 07:27
Copy link
Member

@Zylphrex Zylphrex left a comment

Choose a reason for hiding this comment

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

Mostly just missing dependencies, otherwise, looks good to me

}
}

return results;
Copy link
Member

Choose a reason for hiding this comment

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

Nit: could just return at the end of the if block instead of returning in both the try and catch

threshold: 0.3,
includeMatches: true,
});
}, [allFrames.length]);
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this be allFrames?

Copy link
Member Author

Choose a reason for hiding this comment

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

Most def

canvasPoolManager.dispatch('zoomIntoFrame', [frame]);
setSelectedNode(frame);
},
[canvasPoolManager]
Copy link
Member

Choose a reason for hiding this comment

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

Should setSelectedNode be in the dependencies here?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's not necessary, react guarantees that the setState fn is stable between rerenders (https://reactjs.org/docs/hooks-reference.html)

Note
React guarantees that setState function identity is stable and won’t change on re-renders. This is why it’s safe to > omit from the useEffect or useCallback dependency list.

setSearchResults(results);
canvasPoolManager.dispatch('searchResults', [results]);
},
[searchIndex, frames, canvasPoolManager]
Copy link
Member

Choose a reason for hiding this comment

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

This is missing setSearchResults and allFrames

setOpen(false);
}
},
[open, setSearchResults]
Copy link
Member

Choose a reason for hiding this comment

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

Add setOpen?

onPreviousSearchClick();
}
},
[onNextSearchClick, onPreviousSearchClick, setSearchResults]
Copy link
Member

Choose a reason for hiding this comment

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

Add setOpen?

@JonasBa
Copy link
Member Author

JonasBa commented Feb 14, 2022

@Zylphrex I think I'll add the react-hooks-exhaustive dependencies to our eslint config, the linting should have caught this. But good eye 👁️

Base automatically changed from jb/profiling/flamegraph-view-select to jb/profiling/tooltip February 15, 2022 08:18
@github-actions
Copy link
Contributor

size-limit report 📦

Path Size
src/sentry/static/sentry/dist/entrypoints/app.js 54 KB (-0.02% 🔽)
src/sentry/static/sentry/dist/entrypoints/sentry.css 68.96 KB (0%)

@JonasBa JonasBa merged this pull request into jb/profiling/tooltip Feb 15, 2022
@JonasBa JonasBa deleted the jb/profiling/flamegraph-search branch February 15, 2022 08:38
JonasBa added a commit that referenced this pull request Feb 15, 2022
* feat(flamegraph): add view select menu

* feat(profiling): use buttonbar

* feat(profiling): add search

* style(lint): Auto commit lint changes

* style(lint): Auto commit lint changes

* feat(profiling): decouple search fn

* fix(flamegraphsearch): missing hook deps

Co-authored-by: getsantry[bot] <66042841+getsantry[bot]@users.noreply.github.com>
JonasBa added a commit that referenced this pull request Feb 15, 2022
* feat(profiling): flamegraph

* feat(profiling): add flamegraph renderer and tests

* fix(profiling): ignore unused renderer in test

* fix(profiling): ignore unused renderer in test

* feat(profiling): add util hooks

* ref(hook): add usememowithprevious tests

* feat(profiling): zoom view

* fix(flamegraphrenderer): adjust for profiles that do not start at 0 and trim text more accurately

* feat(profiling): add tooltip component

* fix(flamegraph): remove merge marker

* test(utils): fix tests

* fix(tooltip): code review

* feat(tooltip): add useDevicePixelRatio hook

* feat(profiling): add view select menu (#31698)

* feat(flamegraph): add view select menu

* feat(profiling): use buttonbar

* fix(viewselectmenu): use locale

* test(gridrenderer): update tests

* feat(profiling): add ability to search for frames (#31723)

* feat(flamegraph): add view select menu

* feat(profiling): use buttonbar

* feat(profiling): add search

* style(lint): Auto commit lint changes

* style(lint): Auto commit lint changes

* feat(profiling): decouple search fn

* fix(flamegraphsearch): missing hook deps

Co-authored-by: getsantry[bot] <66042841+getsantry[bot]@users.noreply.github.com>

* fix(flamegraphtooltip): update deps

Co-authored-by: getsantry[bot] <66042841+getsantry[bot]@users.noreply.github.com>
@github-actions github-actions bot locked and limited conversation to collaborators Mar 2, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants