Skip to content
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

Scheduling Profiler: Move preprocessing to web worker and add loading indicator #19759

Merged
merged 5 commits into from
Sep 4, 2020

Conversation

taneliang
Copy link
Contributor

@taneliang taneliang commented Sep 3, 2020

Builds on #19707 to further improve the UI/UX by:

  1. Moving our expensive preprocessData call into a new web worker. This previously caused the UI to freeze for a significant amount of time (the facebook.com we have freezes my browser for >10 seconds).
  2. Add a loading indicator. This ProcessingData component is copied from the React DevTools Profiler.
Before: freezes, errors in modal After: loading text + no freezing, full page errors
old general

cc @bvaughn, @kartikcho

Implementation notes

  1. I've used Suspense to implement the loading indicator stuff. This is the first time I'm using Suspense to do anything real, so please let me know if I'm not doing anything right 😄
  2. I've used the Resource implementation in react-devtools-shared without forking it.

UI notes

It's possible to load a second profile while the first one is still loading. I think this is fine from both UI and technical perspectives: users may want to select another profile if they selected the wrong profile/the profile is taking too long to load, and our implementation only displays the latest selected profile.

This is what it looks like:
loadover

Here's what's happening in the gif:

  1. Load large facebook.com profile.
  2. While it's loading, I loaded a smaller profile that finished loading and was displayed.
  3. I also loaded another profile that caused an error.
  4. I then waited a few seconds for the facebook.com profile to finish loading (verified afterwards, where the flamechart shows that the loading completed). Verified that the facebook.com profile's data was not displayed.
  5. We then wait for Chrome DevTools to process the performance profile.
  6. Chrome DevTools' Performance tool shows that multiple workers were created and processed their profiles in parallel.

@codesandbox-ci
Copy link

codesandbox-ci bot commented Sep 3, 2020

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit cd1f3c4:

Sandbox Source
React Configuration

@sizebot
Copy link

sizebot commented Sep 3, 2020

No significant bundle size changes to report.

Size changes (stable)

Generated by 🚫 dangerJS against cd1f3c4

@sizebot
Copy link

sizebot commented Sep 3, 2020

No significant bundle size changes to report.

Size changes (experimental)

Generated by 🚫 dangerJS against cd1f3c4

@taneliang taneliang marked this pull request as draft September 3, 2020 14:02
@taneliang
Copy link
Contributor Author

Looks like the error handling is now broken with fast refresh.

fast refresh overlay

I haven't managed to find the cause yet, but here are some guesses:

  1. I may not be using error boundaries correctly. The error boundary is catching the thrown error though. Maybe this is just not a good use case for error boundaries?
  2. The error overlay may just be too eager.

Any idea, @bvaughn? I can look into this further tomorrow too.

@bvaughn
Copy link
Contributor

bvaughn commented Sep 3, 2020

Likely won't have time to look into this today.

@taneliang
Copy link
Contributor Author

👍 No problem! I'll continue poking tomorrow.

Copy link
Contributor Author

@taneliang taneliang left a comment

Choose a reason for hiding this comment

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

Okay, it's fixed! Looks like it just wasn't a good use case for error boundaries.

This is ready for review, @bvaughn :)

@taneliang taneliang marked this pull request as ready for review September 4, 2020 13:50
const [profilerData, setProfilerData] = useState<ReactProfilerData | null>(
null,
);
type DataResource = Resource<void, File, ReactProfilerData | Error>;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also not sure if storing data + import errors in a resource is the cleanest approach. I'm doing this to handle these expected/intentional errors without throwing them and using error boundaries. Any idea how I can improve this?

@bvaughn
Copy link
Contributor

bvaughn commented Sep 4, 2020

I think this change is probably a good one, because freezing the browser when uploading a larger profile is not a good user experience, but it makes the overall upload process noticeably slower.

For example, I tested with a 95MB profile from Facebook (the largest one I had handy) and the existing app took about 1.6 seconds:
Screen Shot 2020-09-04 at 10 19 14 AM

I used the same profile on (a production build of) this branch and it took about 10 seconds, most of which was in the worker:
Screen Shot 2020-09-04 at 10 20 22 AM

But a decent chunk was still on main:
Screen Shot 2020-09-04 at 10 20 54 AM

How big is the profile you're testing with? What do the overall load durations look like for you?

@bvaughn
Copy link
Contributor

bvaughn commented Sep 4, 2020

Something else occurs to me that I don't know the answer for: Will this change make merging the new profiler into DevTools harder? I think extensions support workers but I've never done it before.

Copy link
Contributor

@bvaughn bvaughn left a comment

Choose a reason for hiding this comment

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

Going to hold off on merging this until you've had a chance to respond to the previous two messages, but overall this looks good to me 👍

@taneliang
Copy link
Contributor Author

the existing app took about 1.6 seconds ... this branch and it took about 10 seconds

Ouch!

I've just tried using the 57MB facebook.com profile that you sent us, and it seems like there's a difference between the project from the fellowship and what we currently have on master. I'm not seeing any noticeable difference between master and this branch though. Which existing app are you referring to?

On https://react-scheduling-profiler.vercel.app/ (currently still deployed from the MLH Fellowship repo), I'm getting ~5 seconds

image

On a prod build of the master branch, I'm getting ~12 seconds. Maybe something (Speedscope probably?) got deopted?

image

On a prod build of this branch, I'm getting the same ~11 seconds

image

@bvaughn
Copy link
Contributor

bvaughn commented Sep 4, 2020

Oh, interesting. I was just testing against react-scheduling-profiler.vercel.app rather than switching between master and rebuilding.

Would be good for us to follow up and figure out what deopted us, but I guess that shouldn't hold up this merge then.

@taneliang
Copy link
Contributor Author

Yeah, I'll look into this further next week.

Will this change make merging the new profiler into DevTools harder? I think extensions support workers but I've never done it before.

I don't know either 😆 I did think about this, and I figured that since there's very little code needed to use web workers it shouldn't be a big issue when integrating this into DevTools. In the worst case, we can probably just remove the web worker entirely.

@bvaughn
Copy link
Contributor

bvaughn commented Sep 4, 2020

Sounds good.

Let's merge this then for now, to keep the train rolling. We'll dig in more later.

@bvaughn bvaughn merged commit eabd18c into facebook:master Sep 4, 2020
@taneliang taneliang deleted the web-worker branch September 4, 2020 14:57
koto pushed a commit to koto/react that referenced this pull request Jun 15, 2021
… indicator (facebook#19759)

* Move preprocessData into a web worker
* Add UI feedback for loading/import error states
* Terminate worker when done handling profile
* Add display density CSS variables
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants