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");
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -57,6 +57,8 @@ class NativePerformanceObserver
|
|||
jsi::Runtime &rt,
|
||||
std::optional<AsyncCallback<>> callback);
|
||||
|
||||
void logEntryForDebug(jsi::Runtime &rt, RawPerformanceEntry entry);
|
||||
|
||||
private:
|
||||
std::optional<AsyncCallback<>> callback_;
|
||||
};
|
||||
|
|
|
@ -14,6 +14,7 @@ import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
|
|||
|
||||
export const RawPerformanceEntryTypeValues = {
|
||||
UNDEFINED: 0,
|
||||
MARK: 1,
|
||||
};
|
||||
|
||||
export type RawPerformanceEntryType = number;
|
||||
|
@ -34,6 +35,9 @@ export interface Spec extends TurboModule {
|
|||
+stopReporting: (entryType: string) => void;
|
||||
+getPendingEntries: () => $ReadOnlyArray<RawPerformanceEntry>;
|
||||
+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>(
|
||||
|
|
|
@ -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;
|
||||
// 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';
|
||||
export type PerformanceEntryType = 'undefined' | 'mark';
|
||||
|
||||
export class PerformanceEntry {
|
||||
name: string;
|
||||
|
@ -53,7 +52,7 @@ export class PerformanceEntry {
|
|||
function rawToPerformanceEntryType(
|
||||
type: RawPerformanceEntryType,
|
||||
): PerformanceEntryType {
|
||||
return 'undefined';
|
||||
return 'mark';
|
||||
}
|
||||
|
||||
function rawToPerformanceEntry(entry: RawPerformanceEntry): PerformanceEntry {
|
||||
|
@ -166,7 +165,7 @@ export default class PerformanceObserver {
|
|||
} else {
|
||||
this._entryTypes = new Set([options.type]);
|
||||
}
|
||||
this._entryTypes.forEach(type => {
|
||||
for (const type of this._entryTypes) {
|
||||
if (!_observedEntryTypeRefCount.has(type)) {
|
||||
NativePerformanceObserver.startReporting(type);
|
||||
}
|
||||
|
@ -174,7 +173,7 @@ export default class PerformanceObserver {
|
|||
type,
|
||||
(_observedEntryTypeRefCount.get(type) ?? 0) + 1,
|
||||
);
|
||||
});
|
||||
}
|
||||
_observers.add(this);
|
||||
}
|
||||
|
||||
|
@ -183,7 +182,7 @@ export default class PerformanceObserver {
|
|||
warnNoNativePerformanceObserver();
|
||||
return;
|
||||
}
|
||||
this._entryTypes.forEach(type => {
|
||||
for (const type of this._entryTypes) {
|
||||
const entryTypeRefCount = _observedEntryTypeRefCount.get(type) ?? 0;
|
||||
if (entryTypeRefCount === 1) {
|
||||
_observedEntryTypeRefCount.delete(type);
|
||||
|
@ -191,7 +190,7 @@ export default class PerformanceObserver {
|
|||
} else if (entryTypeRefCount !== 0) {
|
||||
_observedEntryTypeRefCount.set(type, entryTypeRefCount - 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
_observers.delete(this);
|
||||
if (_observers.size === 0) {
|
||||
NativePerformanceObserver.setOnPerformanceEntryCallback(undefined);
|
||||
|
@ -201,7 +200,7 @@ export default class PerformanceObserver {
|
|||
|
||||
static supportedEntryTypes: $ReadOnlyArray<PerformanceEntryType> =
|
||||
// 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
|
||||
|
@ -211,7 +210,7 @@ function onPerformanceEntry() {
|
|||
}
|
||||
const rawEntries = NativePerformanceObserver.getPendingEntries();
|
||||
const entries = rawEntries.map(rawToPerformanceEntry);
|
||||
_observers.forEach(observer => {
|
||||
for (const observer of _observers) {
|
||||
const entriesForObserver: PerformanceEntryList = entries.filter(entry =>
|
||||
observer._entryTypes.has(entry.entryType),
|
||||
);
|
||||
|
@ -219,5 +218,5 @@ function onPerformanceEntry() {
|
|||
new PerformanceObserverEntryList(entriesForObserver),
|
||||
observer,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче