-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
ref(replay): refactor replayerStepper to be called less
#74540
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
758cdd2 to
f3154c6
Compare
replayerStepper to be called less
| import DomNodesChart from 'sentry/views/replays/detail/memoryPanel/domNodesChart'; | ||
| import MemoryChart from 'sentry/views/replays/detail/memoryPanel/memoryChart'; | ||
|
|
||
| function useCountDomNodes({replay}: {replay: null | ReplayReader}) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved to its own file,useCountDomNodes.tsx
| export default function extractDomNodes({ | ||
| frames, | ||
| rrwebEvents, | ||
| startTimestampMs, | ||
| }: Args): Promise<Map<ReplayFrame, Extraction>> { | ||
| return replayerStepper({ | ||
| frames, | ||
| rrwebEvents, | ||
| startTimestampMs, | ||
| shouldVisitFrame: frame => { | ||
| const nodeId = getNodeId(frame); | ||
| return nodeId !== undefined && nodeId !== -1; | ||
| }, | ||
| onVisitFrame: (frame, collection, replayer) => { | ||
| const mirror = replayer.getMirror(); | ||
| const nodeId = getNodeId(frame); | ||
| const html = extractHtml(nodeId as number, mirror); | ||
| collection.set(frame as ReplayFrame, { | ||
| frame, | ||
| html, | ||
| timestamp: frame.timestampMs, | ||
| }); | ||
| }, | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved to replayReader.tsx
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved to replayReader.tsx
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved to useExtractPageHtml.tsx
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renamed to useExtractDomNodes.tsx
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renamed to useExtractPageHtml.tsx
- closes getsentry/team-replay#450 - this is the branch off from #74540, the experimental refactor of `replayerStepper` - TLDR: memoize the `replayerStepper` calls so that we remember the results and don't have to reload the data every time. **current state of things**: we have distinct `replayerStepper` calls in the breadcrumbs + memory tabs. in total, we could be calling it 3 times because it's used by (1) the breadcrumbs tab to render the HTML snippet, (2) for hydration error text diffs, (3) and the DOM nodes chart. **the plan**: improve things by calling `replayerStepper` once (or at least less) and memoize the results. side note: it was hard to combine the hydration error text diff `replayerStepper` call with the others due to the types, so we had to keep that call separate. **the question**: is it faster to run one `replayerStepper` instance, and collect all the data at one time (iterate over the frames exactly once)? this means the speed of any tab will always be limited by the slower call, since we're going through ALL the data at once, even some that we might not need yet. like this: https://github.com/getsentry/sentry/blob/70c90544f39dcc3d87dea8c85c0a7669c9585403/static/app/utils/replays/replayReader.tsx#L363-L366 or is it better to continue to have 2 stepper instances that iterate over 2 different sets of frames (breadcrumbs loops over hundreds of frames, and DOM node count iterates over thousands, which means the speeds could be drastically different). in this situation, each tab would handle their own array of necessary frames. **the experiments**: the first PR (#74540) tried to explore a refactor where `replayerStepper` is called once for the two DOM node actions (counting, for the memory chart, and extracting, for the breadcrumbs HTML). changes were made to the stepper so it could accept a list of callbacks, and return all types of data in one shot, so we only need one hidden `replayer` instance on the page for the DOM node functions. unscientifically, it seemed like loading breadcrumbs + memory took the same amount of time as loading the memory chart. (see video below -- as soon as the breadcrumbs tab is done loading, the memory tab is already done). https://github.com/user-attachments/assets/2c882bcb-c8df-409c-8e2a-69d75c279735 this makes sense because we’re iterating over thousands of frames for the DOM nodes chart, so that’s the bottleneck. this means the breadcrumbs tab loads slower. **this PR**: compared to that is the approach where we have 1 stepper instance for breadcrumbs, and one for DOM node count, each iterating over their own lists (which is what i'm doing in this PR). this approach showed breadcrumb data on the screen about 2x as fast as the approach above. therefore 2 stepper instances on the screen is better for users, especially since breadcrumbs tab is more popular than the memory tab. the video below demonstrates the memoization in action. once the breadcrumbs or memory tabs are loaded, switching back to them does not cause re-loading, because the results are cached. notice that the breadcrumbs tab loading is not dependent on the loading of the DOM tab, unlike the video above where the breadcrumbs tab has to "wait" for the memory tab. (i'm also on slower wifi in this clip below) https://github.com/user-attachments/assets/be71add1-63b5-4308-9d26-356d544980ef
replayerStepperand all the functions relating to it. following up with a slightly better implementation (ref(replay): refactor replayerStepper calls to be memoized #74606), but this PR gives context behind it all.current state of things:
we have distinct
replayerSteppercalls in the breadcrumbs + memory tabs. in total, we could be calling it 3 times because it's used by(1) the breadcrumbs tab to render the HTML snippet,
(2) for hydration error text diffs,
(3) and the DOM nodes chart.
the plan:
improve things by calling
replayerStepperonce (or at least less) and memoize the results. side note: it was hard to combine the hydration error text diffreplayerSteppercall with the others due to the types, so we had to keep that call separate.the question:
is it faster to run one
replayerStepperinstance, and collect all the data at one time (iterate over the frames exactly once)? this means the speed of any tab will always be limited by the slower call, since we're going through ALL the data at once, even some that we might not need yet. Like this:sentry/static/app/utils/replays/replayReader.tsx
Lines 363 to 366 in 70c9054
or is it better to continue to have 2 stepper instances that iterate over 2 different sets of frames (breadcrumbs loops over hundreds of frames, and DOM node count iterates over thousands, which means the speeds could be drastically different). in this situation, each tab would handle their own array of necessary frames.
this PR:
this PR tried to explore a refactor where
replayerStepperis called once for the two DOM node actions (counting, for the memory chart, and extracting, for the breadcrumbs HTML).results:
in this PR, changes were made to the stepper so it could accept a list of callbacks, and return all types of data in one shot, so we only need one hidden
replayerinstance on the page for the DOM node functions. unscientifically, it seemed like loading breadcrumbs + memory took the same amount of time as loading the memory chart. (see video below -- as soon as the breadcrumbs tab is done loading, the memory tab is already done).Screen.Recording.2024-07-19.at.11.49.24.AM.mov
this makes sense because we’re iterating over thousands of frames for the DOM nodes chart, so that’s the bottleneck. this means the breadcrumbs tab loads slower.
compared to that is the approach where we have 1 stepper instance for breadcrumbs, and one for DOM node count, each iterating over their own lists (will make a separate PR for that one shortly: #74606). this approach showed breadcrumb data on the screen about 2x as fast as the approach above. therefore 2 stepper instances on the screen is better for users, especially since breadcrumbs tab is more popular than the memory tab.