Write message instead of crashing when native perf API not found.

This commit is contained in:
Ron Buckton 2020-09-16 16:46:50 -07:00 committed by Eli Barzilay
parent a197beef6d
commit dfa55add5a
4 changed files with 63 additions and 19 deletions

View file

@ -4719,6 +4719,10 @@
"code": 6385,
"reportsDeprecated": true
},
"Performance timings for '--diagnostics' or '--extendedDiagnostics' are not available in this session. A native implementation of the Web Performance API could not be found.": {
"category": "Message",
"code": 6386
},
"The expected type comes from property '{0}' which is declared here on type '{1}'": {
"category": "Message",

View file

@ -67,7 +67,17 @@ namespace ts.performance {
*/
export function measure(measureName: string, startMarkName?: string, endMarkName?: string) {
if (perfHooks && enabled) {
perfHooks.performance.measure(measureName, startMarkName, endMarkName);
// NodeJS perf_hooks depends on call arity, not 'undefined' checks, so we
// need to be sure we call 'measure' with the correct number of arguments.
if (startMarkName === undefined) {
perfHooks.performance.measure(measureName);
}
else if (endMarkName === undefined) {
perfHooks.performance.measure(measureName, startMarkName);
}
else {
perfHooks.performance.measure(measureName, startMarkName, endMarkName);
}
}
}
@ -100,15 +110,23 @@ namespace ts.performance {
});
}
/**
* Indicates whether the performance API is enabled.
*/
export function isEnabled() {
return enabled;
}
/** Enables (and resets) performance measurements for the compiler. */
export function enable() {
if (!enabled) {
perfHooks ||= tryGetNativePerformanceHooks() || ShimPerformance?.createPerformanceHooksShim(timestamp);
if (!perfHooks) throw new Error("TypeScript requires an environment that provides a compatible native Web Performance API implementation.");
if (!perfHooks) return false;
perfObserver ||= new perfHooks.PerformanceObserver(list => perfEntryList = list);
perfObserver.observe({ entryTypes: ["mark", "measure"] });
enabled = true;
}
return true;
}
/** Disables performance measurements for the compiler. */

View file

@ -1,5 +1,8 @@
/*@internal*/
namespace ts {
// The following definitions provide the minimum compatible support for the Web Performance User Timings API
// between browsers and NodeJS:
export interface PerformanceHooks {
performance: Performance;
PerformanceObserver: PerformanceObserverConstructor;
@ -34,6 +37,7 @@ namespace ts {
export type PerformanceObserverConstructor = new (callback: (list: PerformanceObserverEntryList, observer: PerformanceObserver) => void) => PerformanceObserver;
export type PerformanceEntryList = PerformanceEntry[];
// Browser globals for the Web Performance User Timings API
declare const performance: Performance | undefined;
declare const PerformanceObserver: PerformanceObserverConstructor | undefined;
@ -55,7 +59,17 @@ namespace ts {
function tryGetNodePerformanceHooks(): PerformanceHooks | undefined {
if (typeof module === "object" && typeof require === "function") {
try {
return require("perf_hooks") as typeof import("perf_hooks");
const perfHooks = require("perf_hooks") as typeof import("perf_hooks");
const { performance, PerformanceObserver } = perfHooks;
if (typeof performance === "object" &&
typeof performance.timeOrigin === "number" &&
typeof performance.clearMarks === "function" &&
typeof performance.mark === "function" &&
typeof performance.measure === "function" &&
typeof performance.now === "function" &&
typeof PerformanceObserver === "function") {
return perfHooks;
}
}
catch {
// ignore errors
@ -63,18 +77,18 @@ namespace ts {
}
}
// 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;
export function tryGetNativePerformanceHooks() {
return nativePerformanceHooks;
}
/** Gets a timestamp with (at least) ms resolution */
export const timestamp = (() => {
if (nativePerformanceHooks) {
const performance = nativePerformanceHooks.performance;
return () => performance.now();
}
return Date.now ? Date.now : () => +(new Date());
})();
export const timestamp =
nativePerformance ? () => nativePerformance.now() :
Date.now ? Date.now :
() => +(new Date());
}

View file

@ -648,19 +648,21 @@ namespace ts {
reportStatisticalValue("Memory used", Math.round(memoryUsed / 1000) + "K");
}
const programTime = performance.getDuration("Program");
const bindTime = performance.getDuration("Bind");
const checkTime = performance.getDuration("Check");
const emitTime = performance.getDuration("Emit");
const programTime = performance.isEnabled() ? performance.getDuration("Program") : 0;
const bindTime = performance.isEnabled() ? performance.getDuration("Bind") : 0;
const checkTime = performance.isEnabled() ? performance.getDuration("Check") : 0;
const emitTime = performance.isEnabled() ? performance.getDuration("Emit") : 0;
if (compilerOptions.extendedDiagnostics) {
const caches = program.getRelationCacheSizes();
reportCountStatistic("Assignability cache size", caches.assignable);
reportCountStatistic("Identity cache size", caches.identity);
reportCountStatistic("Subtype cache size", caches.subtype);
reportCountStatistic("Strict subtype cache size", caches.strictSubtype);
performance.forEachMeasure((name, duration) => reportTimeStatistic(`${name} time`, duration));
if (performance.isEnabled()) {
performance.forEachMeasure((name, duration) => reportTimeStatistic(`${name} time`, duration));
}
}
else {
else if (performance.isEnabled()) {
// Individual component times.
// Note: To match the behavior of previous versions of the compiler, the reported parse time includes
// I/O read time and processing time for triple-slash references and module imports, and the reported
@ -672,10 +674,16 @@ namespace ts {
reportTimeStatistic("Check time", checkTime);
reportTimeStatistic("Emit time", emitTime);
}
reportTimeStatistic("Total time", programTime + bindTime + checkTime + emitTime);
if (performance.isEnabled()) {
reportTimeStatistic("Total time", programTime + bindTime + checkTime + emitTime);
}
reportStatistics();
performance.disable();
if (!performance.isEnabled()) {
sys.write(Diagnostics.Performance_timings_for_diagnostics_or_extendedDiagnostics_are_not_available_in_this_session_A_native_implementation_of_the_Web_Performance_API_could_not_be_found.message + "\n");
}
else {
performance.disable();
}
}
function reportStatistics() {