Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions packages/react-native/Libraries/Core/setUpPerformance.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,25 @@
* @format
*/

// Kept as an alias of the internal `setUpPerformance` module for external
// consumers that import this path directly.
import setUpPerformance from '../../src/private/setup/setUpPerformance';
import setUpPerformanceModern from '../../src/private/setup/setUpPerformanceModern';
import NativePerformance from '../../src/private/webapis/performance/specs/NativePerformance';

setUpPerformance();
// In case if the native implementation of the Performance API is available, use it,
// otherwise fall back to the legacy/default one, which only defines 'Performance.now()'
if (NativePerformance) {
setUpPerformanceModern();
} else {
if (!global.performance) {
// $FlowExpectedError[cannot-write]
global.performance = {
mark: () => {},
clearMarks: () => {},
measure: () => {},
clearMeasures: () => {},
now: () => {
const performanceNow = global.nativePerformanceNow || Date.now;
return performanceNow();
},
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

let initialized = false;

export default function setUpDefaultReactNativeEnvironment(
export default function setUpDefaltReactNativeEnvironment(
enableDeveloperTools: boolean = true,
) {
if (initialized) {
Expand All @@ -21,7 +21,7 @@ export default function setUpDefaultReactNativeEnvironment(

require('../../../Libraries/Core/setUpGlobals');
require('./setUpDOM').default();
require('./setUpPerformance').default();
require('../../../Libraries/Core/setUpPerformance');
require('../../../Libraries/Core/polyfillPromise');
require('../../../Libraries/Core/setUpTimers');
if (__DEV__ && enableDeveloperTools) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {polyfillGlobal} from '../../../Libraries/Utilities/PolyfillFunctions';

let initialized = false;

export default function setUpPerformance() {
export default function setUpPerformanceModern() {
if (initialized) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ import type {
} from './PerformanceEntry';

import {PerformanceEntry} from './PerformanceEntry';
import NativePerformance from './specs/NativePerformance';
import MaybeNativePerformance from './specs/NativePerformance';
import nullthrows from 'nullthrows';

const NativePerformance = nullthrows(MaybeNativePerformance);

export type PerformanceEventTimingJSON = {
...PerformanceEntryJSON,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ import {
performanceEntryTypeToRaw,
rawToPerformanceEntry,
} from './internals/RawPerformanceEntry';
import {getCurrentTimeStamp} from './internals/Utilities';
import MemoryInfo from './MemoryInfo';
import ReactNativeStartupTiming from './ReactNativeStartupTiming';
import NativePerformance from './specs/NativePerformance';
import MaybeNativePerformance from './specs/NativePerformance';
import {PerformanceMark, PerformanceMeasure} from './UserTiming';
import nullthrows from 'nullthrows';

export type PerformanceMeasureOptions =
| Readonly<{
Expand All @@ -54,8 +56,13 @@ export type PerformanceMeasureOptions =
const ENTRY_TYPES_AVAILABLE_FROM_TIMELINE: ReadonlyArray<PerformanceEntryType> =
['mark', 'measure'];

const {now, reportMark, reportMeasure, getMarkTime, clearMarks, clearMeasures} =
NativePerformance;
const NativePerformance = nullthrows(MaybeNativePerformance);

const cachedReportMark = NativePerformance.reportMark;
const cachedReportMeasure = NativePerformance.reportMeasure;
const cachedGetMarkTime = NativePerformance.getMarkTime;
const cachedNativeClearMarks = NativePerformance.clearMarks;
const cachedNativeClearMeasures = NativePerformance.clearMeasures;
let cachedTimeOrigin: ?DOMHighResTimeStamp;

const MARK_OPTIONS_REUSABLE_OBJECT: PerformanceMarkOptions = {
Expand All @@ -71,7 +78,7 @@ const MEASURE_OPTIONS_REUSABLE_OBJECT: PerformanceMeasureInit = {
};

const getMarkTimeForMeasure = (markName: string): number => {
const markTime = getMarkTime(markName);
const markTime = cachedGetMarkTime(markName);
if (markTime == null) {
throw new DOMException(
`Failed to execute 'measure' on 'Performance': The mark '${markName}' does not exist.`,
Expand Down Expand Up @@ -140,7 +147,12 @@ export default class Performance {
*/
get timeOrigin(): DOMHighResTimeStamp {
if (cachedTimeOrigin == null) {
cachedTimeOrigin = NativePerformance.timeOrigin();
if (NativePerformance.timeOrigin) {
cachedTimeOrigin = NativePerformance?.timeOrigin();
} else {
// Very naive polyfill.
cachedTimeOrigin = Date.now() - getCurrentTimeStamp();
}
}

return cachedTimeOrigin;
Expand Down Expand Up @@ -190,7 +202,7 @@ export default class Performance {
);
}
} else {
resolvedStartTime = now();
resolvedStartTime = getCurrentTimeStamp();
}

if (detail !== undefined) {
Expand All @@ -207,13 +219,13 @@ export default class Performance {
MARK_OPTIONS_REUSABLE_OBJECT,
);

reportMark(resolvedMarkName, resolvedStartTime, entry);
cachedReportMark(resolvedMarkName, resolvedStartTime, entry);

return entry;
}

clearMarks(markName?: string): void {
clearMarks(markName);
cachedNativeClearMarks(markName);
}

measure(
Expand Down Expand Up @@ -335,7 +347,7 @@ export default class Performance {
) {
resolvedDuration = resolvedEndTime - resolvedStartTime;
} else {
resolvedDuration = now() - resolvedStartTime;
resolvedDuration = getCurrentTimeStamp() - resolvedStartTime;
}
}

Expand All @@ -352,7 +364,7 @@ export default class Performance {
resolvedDuration =
getMarkTimeForMeasure(endMark) - resolvedStartTime;
} else {
resolvedDuration = now() - resolvedStartTime;
resolvedDuration = getCurrentTimeStamp() - resolvedStartTime;
}
break;
}
Expand All @@ -363,7 +375,7 @@ export default class Performance {
resolvedDuration =
getMarkTimeForMeasure(endMark) - resolvedStartTime;
} else {
resolvedDuration = now() - resolvedStartTime;
resolvedDuration = getCurrentTimeStamp() - resolvedStartTime;
}
}
}
Expand All @@ -373,7 +385,7 @@ export default class Performance {
if (endMark !== undefined) {
resolvedDuration = getMarkTimeForMeasure(endMark) - resolvedStartTime;
} else {
resolvedDuration = now() - resolvedStartTime;
resolvedDuration = getCurrentTimeStamp() - resolvedStartTime;
}
}

Expand All @@ -388,7 +400,7 @@ export default class Performance {

const entry = new PerformanceMeasure(MEASURE_OPTIONS_REUSABLE_OBJECT);

reportMeasure(
cachedReportMeasure(
resolvedMeasureName,
resolvedStartTime,
resolvedDuration,
Expand All @@ -399,14 +411,14 @@ export default class Performance {
}

clearMeasures(measureName?: string): void {
clearMeasures(measureName);
cachedNativeClearMeasures(measureName);
}

/**
* Returns a double, measured in milliseconds.
* https://developer.mozilla.org/en-US/docs/Web/API/Performance/now
*/
now: () => DOMHighResTimeStamp = now;
now: () => DOMHighResTimeStamp = getCurrentTimeStamp;

/**
* An extension that allows to get back to JS all currently logged marks/measures
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ import {
rawToPerformanceEntry,
rawToPerformanceEntryType,
} from './internals/RawPerformanceEntry';
import NativePerformance from './specs/NativePerformance';
import MaybeNativePerformance from './specs/NativePerformance';
import nullthrows from 'nullthrows';

export {PerformanceEntry} from './PerformanceEntry';

const NativePerformance = nullthrows(MaybeNativePerformance);

export class PerformanceObserverEntryList {
#entries: PerformanceEntryList;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@ import type {
ExtensionTrackEntryPayload,
} from './UserTimingExtensibility';

import {getCurrentTimeStamp} from './internals/Utilities';
import {PerformanceEntry} from './PerformanceEntry';
import NativePerformance from './specs/NativePerformance';

const {now} = NativePerformance;

export type DetailType =
| unknown
Expand Down Expand Up @@ -49,7 +47,7 @@ class PerformanceMarkTemplate extends PerformanceEntry {
constructor(markName: string, markOptions?: PerformanceMarkOptions) {
super('mark', {
name: markName,
startTime: markOptions?.startTime ?? now(),
startTime: markOptions?.startTime ?? getCurrentTimeStamp(),
duration: 0,
});

Expand All @@ -75,7 +73,7 @@ export const PerformanceMark: typeof PerformanceMarkTemplate =
) {
this.__entryType = 'mark';
this.__name = markName;
this.__startTime = markOptions?.startTime ?? now();
this.__startTime = markOptions?.startTime ?? getCurrentTimeStamp();
this.__duration = 0;

this.__detail = markOptions?.detail ?? null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* 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.
*
* @flow strict
* @format
*/

import warnOnce from '../../../../../Libraries/Utilities/warnOnce';
import NativePerformance from '../specs/NativePerformance';

export function warnNoNativePerformance() {
warnOnce(
'missing-native-performance',
'Missing native implementation of Performance',
);
}

declare var global: {
// This value is defined directly via JSI, if available.
readonly nativePerformanceNow?: ?() => number,
};

export const getCurrentTimeStamp: () => DOMHighResTimeStamp =
NativePerformance?.now ?? global.nativePerformanceNow ?? (() => Date.now());
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export type PerformanceObserverInit = {

export interface Spec extends TurboModule {
readonly now: () => number;
readonly timeOrigin: () => number;
readonly timeOrigin?: () => number;

readonly reportMark: (
name: string,
Expand Down Expand Up @@ -107,6 +107,4 @@ export interface Spec extends TurboModule {
readonly clearEventCountsForTesting: () => void;
}

export default TurboModuleRegistry.getEnforcing<Spec>(
'NativePerformanceCxx',
) as Spec;
export default TurboModuleRegistry.get<Spec>('NativePerformanceCxx') as ?Spec;
Loading