Commit Graph

32 Commits

Author SHA1 Message Date
Ruslan Shestopalyuk 1629b9f0a1 Refactor BUCK file for WebPerformance (use TurboModule plugins) (#36197)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/36197

[Changelog][Internal]

This turns NativePerformance* module dependencies into "TurboModule plugins", which allows for more streamlined client integration (as it makes them register automatically once the dependency is there).

Reviewed By: rubennorte

Differential Revision: D43353204

fbshipit-source-id: 01d0089750a4873088dc4aefe34fd48693ee9791
2023-02-17 19:10:41 -08:00
Ruslan Shestopalyuk cf194aebfe Implement durationThreshold option for PerformanceObserver (#36152)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/36152

[Changelog][Internal]

By [the W3C standard](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver/observe), `PerformanceObserver.observer` can optionally take a `durationThreshold` option, so that only entries with duration larger than the threshold are reported.

This diff adds support for this on the RN side, as well as unit tests for this feature on the JS side.

NOTE: The standard suggests that default value for this is 104s. I left it at 0 for now, as for the RN use cases t may be to too high (needs discussion).

Reviewed By: rubennorte

Differential Revision: D43154319

fbshipit-source-id: 0f9d435506f48d8e8521e408211347e8391d22fc
2023-02-16 06:21:43 -08:00
Ruslan Shestopalyuk 581357bc9b Implement EventCounts Web Performance API for React Native (#36181)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/36181

[Changelog][Internal]

Implements EventCounts API (`Performance.eventCounts`) for Web Performance, according to the W3C standard, see the specs here: https://www.w3.org/TR/event-timing/#eventcounts

The rationale for why we need it is to support some advanced metrics computations, such as a ratio of "slow events" to total event count, per event type.

Reviewed By: rubennorte

Differential Revision: D43285073

fbshipit-source-id: 2c53d04d9a57c1301e37f2a5879072c8d33efbbf
2023-02-16 06:21:43 -08:00
Xin Chen 70fb2dce45 Add performance.memory API
Summary:
This diff adds new performance API `memory`, which is a read-only property that gets the current JS heap size from native side.

Note that the JSI API returns an unordered map with unknown list of memory information, which is different from the [web spec](https://fburl.com/p0vpbt33). We may enforce specific memory info type on the JSI API so that it can be properly translate to the web spec.

- Update the JS spec
- Update Native implementation and return memory information with JSI API `jsi::instrumentation()::getHeapInfo()`
- Add native performance module to catalyst package

Changelog:
[General][Added] - Add performance memory API with native memory Info

Reviewed By: rubennorte

Differential Revision: D43137071

fbshipit-source-id: 319f1a6ba78fce61e665b00849ecf2579094af83
2023-02-15 20:52:48 -08:00
Ruslan Shestopalyuk f76d4dee6f Reference implementation (mock) for NativePerformanceObserver (#36116)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/36116

[Changelog][Internal]

Add a minimal/reference JavaScript implementation for NativePerformanceObserver - the purpose is both unit testing (JS and native sides separately) and potentially shimming the part of functionality that is not dependent on native side.

This is both a setup for adding general unit tests for the Performance* APIs, but also to be able to do non-trivial changes on JS side for WebPerformance (such as in (D43154319).

Reviewed By: rubennorte

Differential Revision: D43167392

fbshipit-source-id: 213d9534d810dece1dd464f910e92e08dbf39508
2023-02-15 06:03:12 -08:00
Ruslan Shestopalyuk aef7194996 API symmetry when passing PerformanceEntryType to/from native module
Summary:
[Changelog][Internal]

`NativePerformanceObserver` TurboModule API would get the type for performance entries as strings in one direction (`start/stopReporting`) and as integers in another direction (inside `RawPerformanceEntry`, for optimization on the native side).

This makes is symmetrical and consistent, all the conversions are now handled on the JS side.

Reviewed By: christophpurrer

Differential Revision: D43236466

fbshipit-source-id: 08e1b62df90e6d26a11577d6b6b1d91a6bce8339
2023-02-13 10:44:06 -08:00
Xin Chen 6faddc3870 Fix string key issue with constexpr StrKey in Performance C++ native module
Summary:
I encountered build error when using performance API in catalyst android mobile app. The error message P617433618 points at using non-const `std::strlen` API in a `constexpr`.

```
$ buck install catalyst-android
...
stderr: xplat/js/react-native-github/Libraries/WebPerformance/PerformanceEntryReporter.cpp:208:13: error: constexpr constructor never produces a constant expression [-Winvalid-constexpr]
  constexpr StrKey(const char *s)
            ^
xplat/js/react-native-github/Libraries/WebPerformance/PerformanceEntryReporter.cpp:209:39: note: non-constexpr function 'strlen' cannot be used in a constant expression
      : key(folly::hash::fnv32_buf(s, std::strlen(s))) {}
```

Changelog:
[General][Fixed] - Fixed string key calculation in constexpr from Performance C++ native module.

Reviewed By: javache

Differential Revision: D43136624

fbshipit-source-id: c691671b157b507745c67a505c91f75cf6b878d1
2023-02-09 11:23:11 -08:00
Ruslan Shestopalyuk 21dbc67c03 Use a more robust method of finding out which events to report
Summary:
[Changelog][Internal]

Use the [list of supported events](https://www.w3.org/TR/event-timing/#sec-events-exposed) explicitly to both filter and transform reported event types, which makes this both more robust and less ambiguous.

The mapping is using a compile-time hash/lookup, similarly to how we do it with the ViewProps in the RN core.

Reviewed By: rubennorte

Differential Revision: D42342655

fbshipit-source-id: 3d0b2465fd5611db110c4792913e0a92e76cd067
2023-01-04 08:57:40 -08:00
Ruslan Shestopalyuk 3aea05651d Remove "first-input" event type from Event Timing API logging implementation (#35771)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/35771

[Changelog][Internal]
Based on the internal discussion, we don't want to report `first-input` event types for RN (just use plain `event` instead), in the way that [Event Timing API standard suggests](https://www.w3.org/TR/event-timing), as this is doesn't have that clear semantics in the context of RN, also to keep it simpler.

Reviewed By: rubennorte

Differential Revision: D42341923

fbshipit-source-id: eff2487dee17ef082604e4c807b4d41485328114
2023-01-04 08:29:15 -08:00
Ruslan Shestopalyuk 09ad0cc0c6 Implement reporting of events from native side to WebPerformance API (#35768)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/35768

Changelog: [Internal]

This implements native side mechanics for reporting user events timing to JS  (PerformanceObserver API).

See the standard for more details: https://www.w3.org/TR/event-timing/

The events are only logged when there are any active subscriptions (via `PerformanceObserver.observe`), also we only log "discrete events" (i.e. no likes of mouse move), so the overhead is non-existing.

There are two main metrics of interest for an event lifecycle:
* Time the event is spent in the queue, i.e. the time between it's created and dispatched
* Time that is spend in the event handler on the JS side (event dispatch), or processing time

Both of these are measured, and the corresponding fields are populated.

Reviewed By: sammy-SC

Differential Revision: D42294947

fbshipit-source-id: 4fd7938c04b942400befa4057d4929fb2763cee1
2023-01-03 11:11:37 -08:00
Ruslan Shestopalyuk afd954efbb Add PerformanceEventTiming API, according to the standard
Summary:
Changelog: [Internal]

This adds definition of `PerformanceEventTiming` interface, according to the W3C standard, so that [event timing](https://www.w3.org/TR/event-timing) data can be reported from native (the C++ part is in the next diff).

See here: https://www.w3.org/TR/event-timing/#performanceeventtiming

Reviewed By: christophpurrer

Differential Revision: D42279486

fbshipit-source-id: 0dfbcd6e5a08fc1b89651bd35b24fb4e731f8b05
2022-12-29 14:30:53 -08:00
Ruslan Shestopalyuk 4eecab3a76 API to report events
Summary:
Extends the WebPerformance API with ability to report events, [according to the standard](https://www.w3.org/TR/event-timing/#sec-performance-event-timing).

This is an API-only change, the actual reporting comes in a separate diff, to simplify reviewing.

Changelog: [Internal]

Reviewed By: christophpurrer

Differential Revision: D42097695

fbshipit-source-id: d8b468ffed50c1c3d889151df5e8ca644d6e1a68
2022-12-16 11:45:06 -08:00
Ruslan Shestopalyuk d09c5fd7a9 Limit perf entry buffer size and send back 'droppedEntriesCount' to PerformanceObserver callback
Summary:
Prevents scenarios when internal performance buffer may grow indefinitely (e.g. due to a broken logging), communicating back to `PerformanceObserver` the corresponding amount of dropped entries, `droppedEntriesCount`, [according to the standard](https://w3c.github.io/performance-timeline/#dom-performanceobservercallbackoptions-droppedentriescount).

NOTE: The backwards compatibility check is failing, which is an orthogonal issue. I am looking into it and won't land this one before it is sorted.

Changelog: [Internal]

Reviewed By: christophpurrer

Differential Revision: D42008409

fbshipit-source-id: 40d30e44d39e643bfb58a6254572823cb2b3b8df
2022-12-16 11:45:06 -08:00
Ruslan Shestopalyuk 70a1e2b053 Clean up NativePerformanceObserver API from unused methods
Summary:
Now that D42097191 allows it, get rid of unused API in the related WebPerformance native modules (these were kept there only to pacify the backwards compatibility checks).

Changelog: [Internal]

Reviewed By: christophpurrer

Differential Revision: D42037757

fbshipit-source-id: 5f5e7e76722cade9e730aba037f9e8ab51fc16d9
2022-12-16 11:45:06 -08:00
Ruslan Shestopalyuk 14307b8212 Setup a global Performance singleton, according to the standard
Summary:
Makes sure that the global (standard) `performance` instance is initialized to still both provide `Performance.now()` as before, but also allows for the newly implemented functionality from the WebPerf API, such as marks/measures.

Changelog: [Internal]

Reviewed By: christophpurrer

Differential Revision: D42017812

fbshipit-source-id: ddbe79e91b45a84871de94018305f2a4536ada4b
2022-12-14 22:38:12 -08:00
Ruslan Shestopalyuk 41c17ddd56 Batch/throttle reporting of the performance entries
Summary:
Makes sure that we don't spam too often the JS performance entry reporting callback, which further dispatches entries to `PerformanceObserver` instances.

The logic is as following:
* ~~~If internal buffer of entries reaches the limit, we schedule the callback (with background priority)~~~
*~~~ Once the callback is processed, we schedule the next flush after a timeout of 500ms, this will also be scheduled from native with background priority~~~
* ~~~Whenever new performance type starts to be observed, we also schedule the callback, in order to prime the above~~~
* Schedule the flush with low priority, whenever there is the first entry coming into an empty buffer, and rely on the Scheduler to "do the right thing" when asked to flush it with background priority and not doo it exceedingly often (see the prolonged discussion)

Changelog: [internal]

Reviewed By: rubennorte

Differential Revision: D41875085

fbshipit-source-id: 368b525203215350ceabb43d5e9e8e3bd5242aca
2022-12-12 04:53:31 -08:00
Rubén Norte 5d8fae9cc0 Improve spec-compliance of PerformanceObserver.prototype.observe
Summary:
Our implementation of `PerformanceObserver.prototype.observe` diverges a little bit from the [spec](https://w3c.github.io/performance-timeline/#dom-performanceobserver-observe) regarding the behavior when calling it multiple times. E.g.:

1. We don't throw errors if both `type ` and `entryTypes` are passed.
2. We don't throw errors if neither `type ` nor `entryTypes` are passed.
3. We don't throw errors if we call observe with `type` and we call again later with `entryTypes`, and vice versa.
4. The logic to consolidate entry types in subsequent observe calls is incorrect.

This fixes those issues and also applies some minor naming improvements.

Changelog: [internal]

Reviewed By: rshest

Differential Revision: D41872269

fbshipit-source-id: 9a6b485f4ef2f479c8b6f0307012322f65a11879
2022-12-09 12:15:42 -08:00
Rubén Norte 120e87b86e Show warning when native module for performance marks and measures is not available
Summary:
We're currently showing warnings when we call `performanceObserver.observe` and the native module for performance observers isn't available, but we don't do the same for `performance.mark`, `performance.measure`, etc.

This adds the warning in those cases.

Changelog: [internal]

Reviewed By: rshest

Differential Revision: D41872270

fbshipit-source-id: d720580b930550f27c827a58243579c42a4f6da9
2022-12-09 12:15:42 -08:00
Rubén Norte 4328259f66 Minor stylistic and type coverage changes for Web Performance modules in RN
Summary:
Improved Flow coverage to 100% in both modules.

[Changelog][Internal]

Reviewed By: rshest

Differential Revision: D41872271

fbshipit-source-id: f93553dcabd6d78a3946fdf9d2d2d40cb6c8ca23
2022-12-09 12:15:42 -08:00
Ruslan Shestopalyuk 62a28e4bdb Native side implementation for Performance.measure()
Summary:
Changelog: [Internal]

This implements the C++ side logic of handling `Performance.measure` calls.

Since measures may refer to earlier logged marks by name, we need to keep track of the former. I also use a fixed size (circular) buffer to prevent the marks from piling forever.

Also adds implementation of clearing marks/measures, as per standard.

Reviewed By: mdvacca

Differential Revision: D41756928

fbshipit-source-id: 19dce28d6af4c5646274e6d5db20b41869282780
2022-12-06 17:34:24 -08:00
Ruslan Shestopalyuk d8bcab2be7 Implement Performance.measure support for RN (JS side)
Summary:
Changelog: [Internal]

This adds JS side implementation (including the API) for the `Performance.measure` functionality, [as described in the corresponding standard](https://www.w3.org/TR/user-timing/#measure-method).

The JS part is separated from the C++ implementation (further down the stack) to help the review being more focused.

Reviewed By: mdvacca

Differential Revision: D41733190

fbshipit-source-id: 72b69f6bb332aed4b9477a186b0e818b62009220
2022-12-06 17:34:24 -08:00
Ruslan Shestopalyuk cb552f62f2 Create NativePerformance C++ module
Summary:
[Changelog][Internal]

The NativePerformance module functionality corresponds to the [timing extensions of the Performance API standard interface](https://www.w3.org/TR/user-timing/#extensions-performance-interface).

As this is logically separate from `PerformanceObserver` (which may exist without it), it makes sense to have it as a different native module, so there is no coupling between both.

Reviewed By: christophpurrer

Differential Revision: D41690145

fbshipit-source-id: 7443f4c51f54cc2fdddbdb2e89f9a1fa457ab280
2022-12-03 08:32:58 -08:00
Ruslan Shestopalyuk 1c7e678e08 Handle the case when PerformanceObserver.observe is called multiple times
Summary:
[Changelog][Internal]
Addresses the corresponding TODO in code, to make sure that PerformanceObserver.observe may be called multiple times with different entry types to observe.

Reviewed By: christophpurrer

Differential Revision: D41686237

fbshipit-source-id: 4287f63f7e71e5b1056d30ed616149841ba4f892
2022-12-02 17:23:58 -08:00
Ruslan Shestopalyuk 862a99c491 Use NativePerformanceObserver.popPendingEntries instead of getPendingEntries
Summary:
[Changelog][Internal]

The name corresponds more precisely to what the method does.

Reviewed By: christophpurrer

Differential Revision: D41686205

fbshipit-source-id: 36c47b57fdeb757515cd14b890f38247f7fe8d02
2022-12-02 17:23:58 -08:00
Ruslan Shestopalyuk dfbb63996a Don't use public fields in PerformanceObserver API
Summary:
[Changelog][Internal]

A follow up to the [discussion](https://www.internalfb.com/diff/D41496082 (https://github.com/facebook/react-native/commit/14e69db4826c2a14f3bc7bcd3a81fc56644b4f9b)?dst_version_fbid=831443041436872&transaction_fbid=1281583632681733) in D41496082 (https://github.com/facebook/react-native/commit/14e69db4826c2a14f3bc7bcd3a81fc56644b4f9b), this gets rid of the non-private fields in the `PerformanceObserver` - both to prevent abuse and better conform to the standard.

Reviewed By: rubennorte

Differential Revision: D41683363

fbshipit-source-id: 1fc98ff77e0bcdbf66c2a768e8b27a726831f106
2022-12-02 11:17:27 -08:00
Ruslan Shestopalyuk 14e69db482 Implement native logic for performance event reporting (#35526)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/35526

[Changelog][Internal]

This closes the full loop according to the [technical design](https://fb.quip.com/MdqgAk1Eb2dV) of the WebPerf API implementation, with the main components and the working central data flow in place.

The next step is to add some buffering/throttling, as in this diff we just spawn an idle-priority task after every performance entry coming (even though they still naturally do come in batches, because they manage to accumulate before the task is executed).

Reviewed By: christophpurrer

Differential Revision: D41496082

fbshipit-source-id: 5fd4cf22e75806f7bc98d1d1b6691596ccadf8b9
2022-12-01 09:49:44 -08:00
Ruslan Shestopalyuk a64319a2b2 Add API and scaffolding for Performance.mark implementation
Summary:
[Changelog][Internal]

Adds API definition for [Performance.mark](https://www.w3.org/TR/user-timing/#mark-method) support.

This is a bare bone implementation, that just logs events on the native side. The next step is the native logic for queuing, flushing etc.

Note that here I route both JS and native marks to native for now, for simplicity sake - ultimately this may not be what we want,  as it may be more efficient to process marks, logged from JS, on the JS side.

Reviewed By: rubennorte

Differential Revision: D41472148

fbshipit-source-id: bdf2b182b8472a71a5500235849bca5af1c2f360
2022-11-30 09:28:53 -08:00
Christoph Purrer c0a06d2e6f react-native code-gen > C++ TurboModules struct support (#35265)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/35265

This adds a templating layer for C++ TurboModules to automatically generate struct templates from TurboModule specs.

You have to define concrete types for those templates to use them in your C++ TurboModule.

E.g. for the JS flow type:
```
export type ObjectStruct = {|
  a: number,
  b: string,
  c?: ?string,
|};
```
code-gen will now generate the following template code:
```
#pragma mark - NativeCxxModuleExampleCxxBaseObjectStruct

template <typename P0, typename P1, typename P2>
struct NativeCxxModuleExampleCxxBaseObjectStruct {
  P0 a;
  P1 b;
  P2 c;
  bool operator==(const NativeCxxModuleExampleCxxBaseObjectStruct &other) const {
    return a == other.a && b == other.b && c == other.c;
  }
};

template <typename P0, typename P1, typename P2>
struct NativeCxxModuleExampleCxxBaseObjectStructBridging {
  static NativeCxxModuleExampleCxxBaseObjectStruct<P0, P1, P2> fromJs(
      jsi::Runtime &rt,
      const jsi::Object &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    NativeCxxModuleExampleCxxBaseObjectStruct<P0, P1, P2> result{
      bridging::fromJs<P0>(rt, value.getProperty(rt, "a"), jsInvoker),
      bridging::fromJs<P1>(rt, value.getProperty(rt, "b"), jsInvoker),
      bridging::fromJs<P2>(rt, value.getProperty(rt, "c"), jsInvoker)};
    return result;
  }

  static jsi::Object toJs(
      jsi::Runtime &rt,
      const NativeCxxModuleExampleCxxBaseObjectStruct<P0, P1, P2> &value) {
    auto result = facebook::jsi::Object(rt);
    result.setProperty(rt, "a", bridging::toJs(rt, value.a));
    result.setProperty(rt, "b", bridging::toJs(rt, value.b));
    if (value.c) {
      result.setProperty(rt, "c", bridging::toJs(rt, value.c.value()));
    }
    return result;
  }
};
```
and you can use it in our C++ TurboModule for example as:
```
using ObjectStruct = NativeCxxModuleExampleCxxBaseObjectStruct<
    int32_t,
    std::string,
    std::optional<std::string>>;

template <>
struct Bridging<ObjectStruct>
    : NativeCxxModuleExampleCxxBaseObjectStructBridging<
          int32_t,
          std::string,
          std::optional<std::string>> {};
```
or as
```
using ObjectStruct = NativeCxxModuleExampleCxxBaseObjectStruct<
    float,
    folly::StringPiece,
    std::optional<std::string>>;

template <>
struct Bridging<ObjectStruct>
    : NativeCxxModuleExampleCxxBaseObjectStructBridging<
          float,
          folly::StringPiece,
          std::optional<std::string>> {};
```
Or as
...

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D41133761

fbshipit-source-id: fdf36e51073cb46c5234f6121842c79a884899c7
2022-11-09 13:23:05 -08:00
Ruslan Shestopalyuk ea73a66936 Scaffolding for the PerformanceObserver TurboModule (C++ side) (#35226)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/35226

Changelog: [Internal]

This adds scaffolding for the C++ side of NativePerformanceObserver module.

Thanks to christophpurrer for helping set this up, as this is the first one of this kind inside core/OSS.

Reviewed By: rubennorte

Differential Revision: D41028555

fbshipit-source-id: 4acf0e71a254a42044cbbe5f94f40938342c6aa2
2022-11-08 10:01:21 -08:00
Ruslan Shestopalyuk cf55e4a14e JS side implementation of PerformanceObserver API
Summary:
[Changelog][Internal]

This adds module specs for the native part of PerformanceObserver, as well as the interaction logic vs the NativePerformanceObserver API.

See https://fb.quip.com/MdqgAk1Eb2dV for more detail.

Reviewed By: rubennorte

Differential Revision: D40897006

fbshipit-source-id: 77475f21dad9ee9dbe15df5a989eb08d314e6db2
2022-11-04 08:41:01 -07:00
Ruslan Shestopalyuk f32a3a5372 Refactor PerformanceObserver public API
Summary:
Changelog: [Internal]

This is a follow-up to D40892974 (https://github.com/facebook/react-native/commit/a671d61b6de5f106e9fd803a73fddb4b6fa6656b), addressing the post-land comments and discussions.

Reviewed By: rubennorte

Differential Revision: D40979654

fbshipit-source-id: 2e7e1d24be8211cc3363a07678745039e5606d8d
2022-11-03 09:07:14 -07:00
Ruslan Shestopalyuk f8a2dd74e8 Exclude PerformanceObserver from flow/haste
Summary:
[Changelog][Internal]

This is to prevent an accidental use of PerformanceObserver while it's still a work in progress.

PerformanceObserver is also moved into a dedicated folder, `Libraries/WebPerformance`.

Reviewed By: rubennorte

Differential Revision: D40978749

fbshipit-source-id: 09645a95bed72902870ebc00c1b4a3d81ab4c829
2022-11-03 07:14:41 -07:00