Skip to content

Porting ReactPerf to the new DevTools API #6015

@gaearon

Description

@gaearon

There are a few concerns that I heard about ReactPerf, in the order of importance:

  • (1) It is gated by __DEV__ but React Native wants to have a way to enable it in production builds and pass the accumulated info into systrace
  • (2) It is often broken by refactoring
  • (3) It appears generic but depends on specific module and method names
  • (4) It has some obscure bugs that are hard to fix because of the coupling
  • (5) The console.table() visualization is poor
  • (6) We are working on a new DevTools API so they should align

If I’m mistaken here, please let me know!

In #5306, we started introducing a new set of APIs for first-class instrumentation. It makes sense that we transition ReactPerf to the new API, and fix some of these issues while we’re at it.

I talked to some people on the React Native about this. What I understand so far is:

ASAP

  • We want to remove ReactPerf function wrapping completely (addresses 2, somewhat mitigates overhead from fixing 1)
  • We want to create a devtool like ReactDOMDebugTool, e.g. ReactPerfTool (addresses 6)
  • Unlike ReactDOMDebugTool, ReactPerfTool will not be gated by __DEV__ (addresses 1)
  • ReactPerfTool will have startMeasurement() and endMeasurement() methods for profiling functions (addresses 1)
  • It can have more granular methods for specific parts of React lifecycle if needed (addresses 2, 3, 5)
  • Calls to ReactPerfTool will be gated by a runtime flag, e.g. ReactPerfTool.isActive (addresses 1)

In the Future

  • Rather than reach out into the profiled functions, startMeasurement() will accept arbitrary arguments (addresses 3)
  • We would separate generating user-meaningful data from its accumulation so it would be easy to test (addresses 4)
  • (Bonus) We can use a noop decorator + Babel plugin to insert if (ReactPerfTool.isActive) ReactPerfTool.startMeasurement() and .endMeasurement() calls (mitigates pain and potential breakage from addressing 1)
  • (Bonus) Rather than console.table() API we can provide a component that interprets that data and displays it in an overlay, both on web and native (addresses 5)

The decorator + Babel plugin part is the one I’m not sure about because it would involve complicating tooling. On the other hand, it will allow adding performance measurement to any functions in the codebase without risking having early returns, missing endMeasurement() calls, and similar breakage during refactorings.

The first actionable step, in my opinion, would be to remove the function wrapping and the __DEV__ gate from the existing ReactPerf, and replace measure() with explicit startMeasurement() and endMeasurement() calls gated by ReactPerf.isActive wherever it is used.

We would still pass the function as an argument so we don’t have to rewrite everything at once, but this would give the RN team more freedom, and unlock future refactorings. We can also combine this with introducing decorator + Babel transform if this is the way we want to go, to avoid adding manual startMeasurement() and endMeasurement() calls all over the place.

Does this make sense? What have I missed?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions