Repository: react
Issue: Combine Profiler data sources
Labels: Type: Discussion,Component: Developer Tools,Component: Scheduling Profiler,Size: Large

### Time sensitive API changes (ideally these should land before 18.0 release):
- [x] Add DevTools API/hooks for collecting Timeline profiling data #23102, #23142, #23151
- [x] React (DEV and profiling builds) should call the new Timeline hooks when present instead of logging User Timing data  #23102, #23142, #23151

(DevTools will decide whether or not to store the data or log User Timing marks, since it knows when it's profiling.)

### Additional, non-blocking changes:
DevTools hook changes:
- [x] Log sync marks (with session ID) periodically (e.g. during commit) when profiling is active #23137
- [x] Mark internal module ranges (see [here](https://github.com/facebook/react/blob/9a7e6bf0d0cf08114b74c9fe45c06e60a5e496e4/packages/react-reconciler/src/SchedulingProfiler.js#L102-L123)) only if/when profiling is started. #23141
- [x] ~~Generate a unique session ID when profiling is started. Log it with User Timing and also store it with the main profiling data. (This will be used to match them up later.)~~
- [ ] Collect component stacks for (maybe lazily? maybe cache per Fiber in a WeakMap?)

DevTools Timeline changes:
- [x] Update pre-processing script to make use of the new React <-> DevTools data format #23185
- [x] Support optional tracing data #23185
  - [x] Verify logic for aligning data shared between React <-> DevTools with the optional performance mark data #23185
  - [x] Create UI for separate, optional import (and update the preprocessor to handle this data) #23185

Future optimizations:
- [ ] Consider merging logic between `profilingHooks` and `preprocessData` to remove redundancies. If the code was moved somewhere else, then `profilingHooks` could call it during rendering and `preprocessData` could call it too (as it processed each mark) and avoid having to build up the same in-memory representations.
- [ ] Double check that `internalModuleSourceToRanges` is being initialized correctly for the in-memory profiler. (Technically this doesn't matter yet, since we don't have JavaScript samples for the in memory profiler– but still.)

# Motivation

There are currently two React profilers: the "legacy" profiler (which reads data from Fibers during the commit phase) and the "scheduling" profiler (which reads data in the form of User Timing marks in a Chrome performance profile). This separation is confusing as both profilers live in the same extension/app but import/export different types of data.

Let's take a step back and revisit how the scheduling profiler works...

Recording a profile currently requires a user to do the following:
1. Click "record" in Chrome
2. Use the app
3. Click "stop" in Chrome
4. Export the profile JSON
5. Import it into the React DevTools

It would be nice if DevTools could start/stop recording and import the data itself, but the only way to do this is using the Chrome DevTools Protocol which would _require_ the use of an extremely powerful permission that I don't think we would want to ask users for.

This approach also has the downside of not working with React Native (or non-Chrome browsers).

So why do we do it? We do it because the profile gives us a lot of nice extra data: CPU samples of the JavaScript stack, Network requests, screenshots (if enabled), user events (e.g. "click").

But we don't _need_ this data. The scheduling profiler could still be a useful tool even if included only the React specific marks.

My proposal then is that we consider doing this:
* Replace the user timing API with a direct React-to-DevTools API (where these marks are logged to DevTools directly).
* When profiling starts in React DevTools, generate a unique ID string
* Log this unique ID to the User Profiling API along with each commit (e.g. `"react-sync-marker-<uid>-<index>-<timestamp>"`)
* Allow users to export/import additional native profiling information (which can be aligned using the sync marks) _but is not required_.

Doing this has a few benefits:
* We could start _both_ profilers and join the commit and scheduling profiler data streams (huge benefit).
* It would make the profiler easier to use in the simple case (if you didn't want/need native profiler info) since you could start/stop it from within React DevTools.
* It would let us add component and call stacks without the extra serialization overhead.

It would have the following downside though:
* Recording profiles with native information would be a little more complicated, since you'd need to start React DevTools _and then_ start the browser profiler. (We could show instructions for doing this in the DevTools profiler though.)

## A note about component and call stacks

The scheduling profiler currently shows component _names_ for things like state-updates (e.g. "state update scheduled by Foo") but it does not include component or call stacks. These would both be useful because:
* Component stack would help identify _which instance of foo_ was e.g. scheduling the update
* Call stack would show e.g. which piece of state was being updated (and by what)

The reason we don't include this information is because we won't want to pay the cost of string serializing it all and logging it as a User Timing mark.