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
This commit is contained in:
Родитель
2db26c548b
Коммит
a64319a2b2
|
@ -39,4 +39,13 @@ void NativePerformanceObserver::setOnPerformanceEntryCallback(
|
||||||
<< (callback ? "non-empty" : "empty");
|
<< (callback ? "non-empty" : "empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NativePerformanceObserver::logEntryForDebug(
|
||||||
|
jsi::Runtime &rt,
|
||||||
|
RawPerformanceEntry entry) {
|
||||||
|
LOG(INFO) << "NativePerformanceObserver::logEntry: "
|
||||||
|
<< "name=" << entry.name << " type=" << entry.entryType
|
||||||
|
<< " startTime=" << entry.startTime
|
||||||
|
<< " duration=" << entry.duration;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace facebook::react
|
} // namespace facebook::react
|
||||||
|
|
|
@ -57,6 +57,8 @@ class NativePerformanceObserver
|
||||||
jsi::Runtime &rt,
|
jsi::Runtime &rt,
|
||||||
std::optional<AsyncCallback<>> callback);
|
std::optional<AsyncCallback<>> callback);
|
||||||
|
|
||||||
|
void logEntryForDebug(jsi::Runtime &rt, RawPerformanceEntry entry);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::optional<AsyncCallback<>> callback_;
|
std::optional<AsyncCallback<>> callback_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,7 @@ import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
|
||||||
|
|
||||||
export const RawPerformanceEntryTypeValues = {
|
export const RawPerformanceEntryTypeValues = {
|
||||||
UNDEFINED: 0,
|
UNDEFINED: 0,
|
||||||
|
MARK: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RawPerformanceEntryType = number;
|
export type RawPerformanceEntryType = number;
|
||||||
|
@ -34,6 +35,9 @@ export interface Spec extends TurboModule {
|
||||||
+stopReporting: (entryType: string) => void;
|
+stopReporting: (entryType: string) => void;
|
||||||
+getPendingEntries: () => $ReadOnlyArray<RawPerformanceEntry>;
|
+getPendingEntries: () => $ReadOnlyArray<RawPerformanceEntry>;
|
||||||
+setOnPerformanceEntryCallback: (callback?: () => void) => void;
|
+setOnPerformanceEntryCallback: (callback?: () => void) => void;
|
||||||
|
|
||||||
|
// NOTE: this is for dev-only purposes (potentially is going to be moved elsewhere)
|
||||||
|
+logEntryForDebug?: (entry: RawPerformanceEntry) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (TurboModuleRegistry.get<Spec>(
|
export default (TurboModuleRegistry.get<Spec>(
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
|
* @flow strict
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type {HighResTimeStamp} from './PerformanceObserver';
|
||||||
|
|
||||||
|
import NativePerformanceObserver, {
|
||||||
|
RawPerformanceEntryTypeValues,
|
||||||
|
} from './NativePerformanceObserver';
|
||||||
|
import {PerformanceEntry} from './PerformanceObserver';
|
||||||
|
|
||||||
|
type DetailType = mixed;
|
||||||
|
|
||||||
|
export type PerformanceMarkOptions = {
|
||||||
|
detail?: DetailType,
|
||||||
|
startTime?: HighResTimeStamp,
|
||||||
|
};
|
||||||
|
|
||||||
|
function getCurrentTimeStamp(): HighResTimeStamp {
|
||||||
|
return global.nativePerformanceNow?.() ?? Date.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PerformanceMark extends PerformanceEntry {
|
||||||
|
detail: DetailType;
|
||||||
|
|
||||||
|
constructor(markName: string, markOptions?: PerformanceMarkOptions) {
|
||||||
|
let startTime = markOptions?.startTime ?? getCurrentTimeStamp();
|
||||||
|
super({name: markName, entryType: 'mark', startTime, duration: 0});
|
||||||
|
if (markOptions !== undefined) {
|
||||||
|
this.detail = markOptions.detail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Partial implementation of the Performance interface for RN,
|
||||||
|
* corresponding to the standard in
|
||||||
|
* https://www.w3.org/TR/user-timing/#extensions-performance-interface
|
||||||
|
*/
|
||||||
|
export default class Performance {
|
||||||
|
mark(
|
||||||
|
markName: string,
|
||||||
|
markOptions?: PerformanceMarkOptions,
|
||||||
|
): PerformanceMark {
|
||||||
|
const mark = new PerformanceMark(markName, markOptions);
|
||||||
|
NativePerformanceObserver?.logEntryForDebug?.({
|
||||||
|
name: markName,
|
||||||
|
entryType: RawPerformanceEntryTypeValues.MARK,
|
||||||
|
startTime: mark.startTime,
|
||||||
|
duration: mark.duration,
|
||||||
|
});
|
||||||
|
return mark;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearMarks(markName?: string): void {}
|
||||||
|
|
||||||
|
now(): HighResTimeStamp {
|
||||||
|
return getCurrentTimeStamp();
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,8 +18,7 @@ import NativePerformanceObserver from './NativePerformanceObserver';
|
||||||
|
|
||||||
export type HighResTimeStamp = number;
|
export type HighResTimeStamp = number;
|
||||||
// TODO: Extend once new types (such as event) are supported.
|
// TODO: Extend once new types (such as event) are supported.
|
||||||
// TODO: Get rid of the "undefined" once there is at least one type supported.
|
export type PerformanceEntryType = 'undefined' | 'mark';
|
||||||
export type PerformanceEntryType = 'undefined';
|
|
||||||
|
|
||||||
export class PerformanceEntry {
|
export class PerformanceEntry {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -53,7 +52,7 @@ export class PerformanceEntry {
|
||||||
function rawToPerformanceEntryType(
|
function rawToPerformanceEntryType(
|
||||||
type: RawPerformanceEntryType,
|
type: RawPerformanceEntryType,
|
||||||
): PerformanceEntryType {
|
): PerformanceEntryType {
|
||||||
return 'undefined';
|
return 'mark';
|
||||||
}
|
}
|
||||||
|
|
||||||
function rawToPerformanceEntry(entry: RawPerformanceEntry): PerformanceEntry {
|
function rawToPerformanceEntry(entry: RawPerformanceEntry): PerformanceEntry {
|
||||||
|
@ -166,7 +165,7 @@ export default class PerformanceObserver {
|
||||||
} else {
|
} else {
|
||||||
this._entryTypes = new Set([options.type]);
|
this._entryTypes = new Set([options.type]);
|
||||||
}
|
}
|
||||||
this._entryTypes.forEach(type => {
|
for (const type of this._entryTypes) {
|
||||||
if (!_observedEntryTypeRefCount.has(type)) {
|
if (!_observedEntryTypeRefCount.has(type)) {
|
||||||
NativePerformanceObserver.startReporting(type);
|
NativePerformanceObserver.startReporting(type);
|
||||||
}
|
}
|
||||||
|
@ -174,7 +173,7 @@ export default class PerformanceObserver {
|
||||||
type,
|
type,
|
||||||
(_observedEntryTypeRefCount.get(type) ?? 0) + 1,
|
(_observedEntryTypeRefCount.get(type) ?? 0) + 1,
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
_observers.add(this);
|
_observers.add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +182,7 @@ export default class PerformanceObserver {
|
||||||
warnNoNativePerformanceObserver();
|
warnNoNativePerformanceObserver();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._entryTypes.forEach(type => {
|
for (const type of this._entryTypes) {
|
||||||
const entryTypeRefCount = _observedEntryTypeRefCount.get(type) ?? 0;
|
const entryTypeRefCount = _observedEntryTypeRefCount.get(type) ?? 0;
|
||||||
if (entryTypeRefCount === 1) {
|
if (entryTypeRefCount === 1) {
|
||||||
_observedEntryTypeRefCount.delete(type);
|
_observedEntryTypeRefCount.delete(type);
|
||||||
|
@ -191,7 +190,7 @@ export default class PerformanceObserver {
|
||||||
} else if (entryTypeRefCount !== 0) {
|
} else if (entryTypeRefCount !== 0) {
|
||||||
_observedEntryTypeRefCount.set(type, entryTypeRefCount - 1);
|
_observedEntryTypeRefCount.set(type, entryTypeRefCount - 1);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
_observers.delete(this);
|
_observers.delete(this);
|
||||||
if (_observers.size === 0) {
|
if (_observers.size === 0) {
|
||||||
NativePerformanceObserver.setOnPerformanceEntryCallback(undefined);
|
NativePerformanceObserver.setOnPerformanceEntryCallback(undefined);
|
||||||
|
@ -201,7 +200,7 @@ export default class PerformanceObserver {
|
||||||
|
|
||||||
static supportedEntryTypes: $ReadOnlyArray<PerformanceEntryType> =
|
static supportedEntryTypes: $ReadOnlyArray<PerformanceEntryType> =
|
||||||
// TODO: add types once they are fully supported
|
// TODO: add types once they are fully supported
|
||||||
Object.freeze([]);
|
Object.freeze(['mark']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a callback that gets scheduled and periodically called from the native side
|
// This is a callback that gets scheduled and periodically called from the native side
|
||||||
|
@ -211,7 +210,7 @@ function onPerformanceEntry() {
|
||||||
}
|
}
|
||||||
const rawEntries = NativePerformanceObserver.getPendingEntries();
|
const rawEntries = NativePerformanceObserver.getPendingEntries();
|
||||||
const entries = rawEntries.map(rawToPerformanceEntry);
|
const entries = rawEntries.map(rawToPerformanceEntry);
|
||||||
_observers.forEach(observer => {
|
for (const observer of _observers) {
|
||||||
const entriesForObserver: PerformanceEntryList = entries.filter(entry =>
|
const entriesForObserver: PerformanceEntryList = entries.filter(entry =>
|
||||||
observer._entryTypes.has(entry.entryType),
|
observer._entryTypes.has(entry.entryType),
|
||||||
);
|
);
|
||||||
|
@ -219,5 +218,5 @@ function onPerformanceEntry() {
|
||||||
new PerformanceObserverEntryList(entriesForObserver),
|
new PerformanceObserverEntryList(entriesForObserver),
|
||||||
observer,
|
observer,
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче