Use performance.now when possible, re-disable unconditional perf marking on all Node versions (#57875)

This commit is contained in:
Jake Bailey 2024-03-22 15:55:18 -07:00 committed by GitHub
parent b75261df74
commit 3c637400da
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 59 additions and 79 deletions

View File

@ -180,7 +180,7 @@ export function enable(system: System = sys) {
if (!enabled) {
enabled = true;
perfHooks ||= tryGetNativePerformanceHooks();
if (perfHooks) {
if (perfHooks?.performance) {
timeorigin = perfHooks.performance.timeOrigin;
// NodeJS's Web Performance API is currently slower than expected, but we'd still like
// to be able to leverage native trace events when node is run with either `--cpu-prof`

View File

@ -7,104 +7,86 @@ import {
/** @internal */
export interface PerformanceHooks {
/** Indicates whether we should write native performance events */
shouldWriteNativeEvents: boolean;
performance: Performance;
PerformanceObserver: PerformanceObserverConstructor;
performance?: Performance;
performanceTime?: PerformanceTime;
}
/** @internal */
export interface Performance {
mark(name: string): void;
measure(name: string, startMark?: string, endMark?: string): void;
clearMeasures(name?: string): void;
clearMarks(name?: string): void;
export interface PerformanceTime {
now(): number;
timeOrigin: number;
}
/** @internal */
export interface PerformanceEntry {
name: string;
entryType: string;
startTime: number;
duration: number;
export interface Performance extends PerformanceTime {
mark(name: string): void;
measure(name: string, startMark?: string, endMark?: string): void;
clearMeasures(name?: string): void;
clearMarks(name?: string): void;
}
/** @internal */
export interface PerformanceObserverEntryList {
getEntries(): PerformanceEntryList;
getEntriesByName(name: string, type?: string): PerformanceEntryList;
getEntriesByType(type: string): PerformanceEntryList;
}
/** @internal */
export interface PerformanceObserver {
disconnect(): void;
observe(options: { entryTypes: readonly ("mark" | "measure")[]; }): void;
}
/** @internal */
export type PerformanceObserverConstructor = new (callback: (list: PerformanceObserverEntryList, observer: PerformanceObserver) => void) => PerformanceObserver;
/** @internal */
export type PerformanceEntryList = PerformanceEntry[];
// Browser globals for the Web Performance User Timings API
declare const performance: Performance | undefined;
declare const PerformanceObserver: PerformanceObserverConstructor | undefined;
// eslint-disable-next-line @typescript-eslint/naming-convention
function hasRequiredAPI(performance: Performance | undefined, PerformanceObserver: PerformanceObserverConstructor | undefined) {
return typeof performance === "object" &&
typeof performance.timeOrigin === "number" &&
typeof performance.mark === "function" &&
typeof performance.measure === "function" &&
typeof performance.now === "function" &&
typeof performance.clearMarks === "function" &&
typeof performance.clearMeasures === "function" &&
typeof PerformanceObserver === "function";
}
function tryGetWebPerformanceHooks(): PerformanceHooks | undefined {
if (
typeof performance === "object" &&
typeof PerformanceObserver === "function" &&
hasRequiredAPI(performance, PerformanceObserver)
) {
return {
// For now we always write native performance events when running in the browser. We may
// make this conditional in the future if we find that native web performance hooks
// in the browser also slow down compilation.
shouldWriteNativeEvents: true,
performance,
PerformanceObserver,
};
}
}
function tryGetNodePerformanceHooks(): PerformanceHooks | undefined {
function tryGetPerformance() {
if (isNodeLikeSystem()) {
try {
const { performance, PerformanceObserver } = require("perf_hooks") as typeof import("perf_hooks");
if (hasRequiredAPI(performance, PerformanceObserver)) {
return {
// By default, only write native events when generating a cpu profile or using the v8 profiler.
shouldWriteNativeEvents: false,
performance,
PerformanceObserver,
};
}
// By default, only write native events when generating a cpu profile or using the v8 profiler.
const { performance } = require("perf_hooks") as typeof import("perf_hooks");
return {
shouldWriteNativeEvents: false,
performance,
};
}
catch {
// ignore errors
}
}
if (typeof performance === "object") {
// For now we always write native performance events when running in the browser. We may
// make this conditional in the future if we find that native web performance hooks
// in the browser also slow down compilation.
return {
shouldWriteNativeEvents: true,
performance,
};
}
return undefined;
}
// Unlike with the native Map/Set 'tryGet' functions in corePublic.ts, we eagerly evaluate these
// since we will need them for `timestamp`, below.
const nativePerformanceHooks = tryGetWebPerformanceHooks() || tryGetNodePerformanceHooks();
const nativePerformance = nativePerformanceHooks?.performance;
function tryGetPerformanceHooks(): PerformanceHooks | undefined {
const p = tryGetPerformance();
if (!p) return undefined;
const { shouldWriteNativeEvents, performance } = p;
const hooks: PerformanceHooks = {
shouldWriteNativeEvents,
performance: undefined,
performanceTime: undefined,
};
if (typeof performance.timeOrigin === "number" && typeof performance.now === "function") {
hooks.performanceTime = performance;
}
if (
hooks.performanceTime &&
typeof performance.mark === "function" &&
typeof performance.measure === "function" &&
typeof performance.clearMarks === "function" &&
typeof performance.clearMeasures === "function"
) {
hooks.performance = performance;
}
return hooks;
}
const nativePerformanceHooks = tryGetPerformanceHooks();
const nativePerformanceTime = nativePerformanceHooks?.performanceTime;
/** @internal */
export function tryGetNativePerformanceHooks() {
@ -116,6 +98,4 @@ export function tryGetNativePerformanceHooks() {
*
* @internal
*/
export const timestamp = nativePerformance ? () => nativePerformance.now() :
Date.now ? Date.now :
() => +(new Date());
export const timestamp = nativePerformanceTime ? () => nativePerformanceTime.now() : Date.now;