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
This commit is contained in:
Ruslan Shestopalyuk
2022-11-08 10:01:21 -08:00
committed by Facebook GitHub Bot
parent ea1d72921d
commit ea73a66936
6 changed files with 200 additions and 19 deletions
+28
View File
@@ -10,6 +10,9 @@ load(
)
load(
"//tools/build_defs/oss:rn_defs.bzl",
"ANDROID",
"APPLE",
"CXX",
"HERMES_BYTECODE_VERSION",
"IOS",
"RCT_IMAGE_DATA_DECODER_SOCKET",
@@ -1453,3 +1456,28 @@ rn_xplat_cxx_library2(
"//fbobjc/VendorLib/react-native-maps:react-native-maps",
],
)
rn_xplat_cxx_library2(
name = "RCTWebPerformance",
srcs = glob([
"Libraries/WebPerformance/**/*.cpp",
]),
header_namespace = "",
exported_headers = subdir_glob(
[("Libraries/WebPerformance", "*.h")],
prefix = "RCTWebPerformance",
),
fbandroid_compiler_flags = [
"-fexceptions",
"-frtti",
],
labels = [
"depslint_never_remove",
"pfh:ReactNative_CommonInfrastructurePlaceholder",
],
platforms = (ANDROID, APPLE, CXX),
visibility = ["PUBLIC"],
deps = [
":FBReactNativeSpecJSI",
],
)
@@ -0,0 +1,42 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "NativePerformanceObserver.h"
#include <glog/logging.h>
namespace facebook::react {
NativePerformanceObserver::NativePerformanceObserver(
std::shared_ptr<CallInvoker> jsInvoker)
: NativePerformanceObserverCxxSpec(std::move(jsInvoker)) {}
void NativePerformanceObserver::startReporting(
jsi::Runtime &rt,
std::string entryType) {
LOG(INFO) << "Started reporting perf entry type: " << entryType;
}
void NativePerformanceObserver::stopReporting(
jsi::Runtime &rt,
std::string entryType) {
LOG(INFO) << "Stopped reporting perf entry type: " << entryType;
}
std::vector<RawPerformanceEntry> NativePerformanceObserver::getPendingEntries(
jsi::Runtime &rt) {
return std::vector<RawPerformanceEntry>{};
}
void NativePerformanceObserver::setOnPerformanceEntryCallback(
jsi::Runtime &rt,
std::optional<AsyncCallback<>> callback) {
callback_ = callback;
LOG(INFO) << "setOnPerformanceEntryCallback: "
<< (callback ? "non-empty" : "empty");
}
} // namespace facebook::react
@@ -0,0 +1,40 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <FBReactNativeSpec/FBReactNativeSpecJSI.h>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "NativePerformanceObserver_RawPerformanceEntry.h"
namespace facebook::react {
class NativePerformanceObserver
: public NativePerformanceObserverCxxSpec<NativePerformanceObserver>,
std::enable_shared_from_this<NativePerformanceObserver> {
public:
NativePerformanceObserver(std::shared_ptr<CallInvoker> jsInvoker);
void startReporting(jsi::Runtime &rt, std::string entryType);
void stopReporting(jsi::Runtime &rt, std::string entryType);
std::vector<RawPerformanceEntry> getPendingEntries(jsi::Runtime &rt);
void setOnPerformanceEntryCallback(
jsi::Runtime &rt,
std::optional<AsyncCallback<>> callback);
private:
std::optional<AsyncCallback<>> callback_;
};
} // namespace facebook::react
@@ -8,11 +8,9 @@
* @format
*/
import type {TurboModule} from '../../TurboModule/RCTExport';
import type {TurboModule} from '../TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry';
export type RawTimeStamp = number;
import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
export const RawPerformanceEntryTypeValues = {
UNDEFINED: 0,
@@ -23,22 +21,21 @@ export type RawPerformanceEntryType = number;
export type RawPerformanceEntry = $ReadOnly<{
name: string,
entryType: RawPerformanceEntryType,
startTime: RawTimeStamp,
startTime: number,
duration: number,
// For "event" entries only:
processingStart?: RawTimeStamp,
processingEnd?: RawTimeStamp,
interactionId?: RawTimeStamp,
processingStart?: number,
processingEnd?: number,
interactionId?: number,
}>;
export type RawPerformanceEntryList = $ReadOnlyArray<RawPerformanceEntry>;
export interface Spec extends TurboModule {
+startReporting: (entryType: string) => void;
+stopReporting: (entryType: string) => void;
+getPendingEntries: () => RawPerformanceEntryList;
+getPendingEntries: () => $ReadOnlyArray<RawPerformanceEntry>;
+setOnPerformanceEntryCallback: (callback?: () => void) => void;
}
export default (TurboModuleRegistry.get<Spec>('PerformanceObserver'): ?Spec);
export default (TurboModuleRegistry.get<Spec>(
'NativePerformanceObserverCxx',
): ?Spec);
@@ -0,0 +1,76 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/bridging/Bridging.h>
#include <optional>
#include <string>
namespace facebook::react {
struct RawPerformanceEntry {
std::string name;
int32_t entryType;
double startTime;
double duration;
// For "event" entries only:
std::optional<double> processingStart;
std::optional<double> processingEnd;
std::optional<double> interactionId;
};
template <>
struct Bridging<RawPerformanceEntry> {
static RawPerformanceEntry fromJs(
jsi::Runtime &rt,
const jsi::Object &value,
const std::shared_ptr<CallInvoker> &jsInvoker) {
RawPerformanceEntry result{
bridging::fromJs<std::string>(
rt, value.getProperty(rt, "name"), jsInvoker),
bridging::fromJs<int32_t>(
rt, value.getProperty(rt, "entryType"), jsInvoker),
bridging::fromJs<double>(
rt, value.getProperty(rt, "startTime"), jsInvoker),
bridging::fromJs<double>(
rt, value.getProperty(rt, "duration"), jsInvoker),
bridging::fromJs<std::optional<double>>(
rt, value.getProperty(rt, "processingStart"), jsInvoker),
bridging::fromJs<std::optional<double>>(
rt, value.getProperty(rt, "processingEnd"), jsInvoker),
bridging::fromJs<std::optional<double>>(
rt, value.getProperty(rt, "interactionId"), jsInvoker),
};
return result;
}
static jsi::Object toJs(jsi::Runtime &rt, const RawPerformanceEntry &value) {
auto result = facebook::jsi::Object(rt);
result.setProperty(rt, "name", bridging::toJs(rt, value.name));
result.setProperty(rt, "entryType", bridging::toJs(rt, value.entryType));
result.setProperty(rt, "startTime", bridging::toJs(rt, value.startTime));
result.setProperty(rt, "duration", bridging::toJs(rt, value.duration));
if (value.processingStart) {
result.setProperty(
rt,
"processingStart",
bridging::toJs(rt, value.processingStart.value()));
}
if (value.processingEnd) {
result.setProperty(
rt, "processingEnd", bridging::toJs(rt, value.processingEnd.value()));
}
if (value.interactionId) {
result.setProperty(
rt, "interactionId", bridging::toJs(rt, value.interactionId.value()));
}
return result;
}
};
} // namespace facebook::react
@@ -10,12 +10,11 @@
import type {
RawPerformanceEntry,
RawPerformanceEntryList,
RawPerformanceEntryType,
} from '../NativeModules/specs/NativePerformanceObserverCxx';
} from './NativePerformanceObserver';
import NativePerformanceObserver from '../NativeModules/specs/NativePerformanceObserverCxx';
import warnOnce from '../Utilities/warnOnce';
import NativePerformanceObserver from './NativePerformanceObserver';
export type HighResTimeStamp = number;
// TODO: Extend once new types (such as event) are supported.
@@ -195,7 +194,7 @@ export default class PerformanceObserver {
});
_observers.delete(this);
if (_observers.size === 0) {
NativePerformanceObserver.setOnPerformanceEntryCallback();
NativePerformanceObserver.setOnPerformanceEntryCallback(undefined);
_onPerformanceEntryCallbackIsSet = false;
}
}
@@ -210,8 +209,7 @@ function onPerformanceEntry() {
if (!NativePerformanceObserver) {
return;
}
const rawEntries: RawPerformanceEntryList =
NativePerformanceObserver.getPendingEntries();
const rawEntries = NativePerformanceObserver.getPendingEntries();
const entries = rawEntries.map(rawToPerformanceEntry);
_observers.forEach(observer => {
const entriesForObserver: PerformanceEntryList = entries.filter(entry =>