-
Notifications
You must be signed in to change notification settings - Fork 12.6k
/
performance.ts
131 lines (116 loc) · 4.41 KB
/
performance.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*@internal*/
/** Performance measurements for the compiler. */
namespace ts.performance {
let perfHooks: PerformanceHooks | undefined;
let perfObserver: PerformanceObserver | undefined;
// when set, indicates the implementation of `Performance` to use for user timing.
// when unset, indicates user timing is unavailable or disabled.
let performanceImpl: Performance | undefined;
export interface Timer {
enter(): void;
exit(): void;
}
export function createTimerIf(condition: boolean, measureName: string, startMarkName: string, endMarkName: string) {
return condition ? createTimer(measureName, startMarkName, endMarkName) : nullTimer;
}
export function createTimer(measureName: string, startMarkName: string, endMarkName: string): Timer {
let enterCount = 0;
return {
enter,
exit
};
function enter() {
if (++enterCount === 1) {
mark(startMarkName);
}
}
function exit() {
if (--enterCount === 0) {
mark(endMarkName);
measure(measureName, startMarkName, endMarkName);
}
else if (enterCount < 0) {
Debug.fail("enter/exit count does not match.");
}
}
}
export const nullTimer: Timer = { enter: noop, exit: noop };
const counts = new Map<string, number>();
const durations = new Map<string, number>();
/**
* Marks a performance event.
*
* @param markName The name of the mark.
*/
export function mark(markName: string) {
performanceImpl?.mark(markName);
}
/**
* Adds a performance measurement with the specified name.
*
* @param measureName The name of the performance measurement.
* @param startMarkName The name of the starting mark. If not supplied, the point at which the
* profiler was enabled is used.
* @param endMarkName The name of the ending mark. If not supplied, the current timestamp is
* used.
*/
export function measure(measureName: string, startMarkName?: string, endMarkName?: string) {
performanceImpl?.measure(measureName, startMarkName, endMarkName);
}
/**
* Gets the number of times a marker was encountered.
*
* @param markName The name of the mark.
*/
export function getCount(markName: string) {
return counts.get(markName) || 0;
}
/**
* Gets the total duration of all measurements with the supplied name.
*
* @param measureName The name of the measure whose durations should be accumulated.
*/
export function getDuration(measureName: string) {
return durations.get(measureName) || 0;
}
/**
* Iterate over each measure, performing some action
*
* @param cb The action to perform for each measure
*/
export function forEachMeasure(cb: (measureName: string, duration: number) => void) {
durations.forEach((duration, measureName) => cb(measureName, duration));
}
/**
* Indicates whether the performance API is enabled.
*/
export function isEnabled() {
return !!performanceImpl;
}
/** Enables (and resets) performance measurements for the compiler. */
export function enable() {
if (!performanceImpl) {
perfHooks ||= tryGetNativePerformanceHooks();
if (!perfHooks) return false;
perfObserver ||= new perfHooks.PerformanceObserver(updateStatisticsFromList);
perfObserver.observe({ entryTypes: ["mark", "measure"] });
performanceImpl = perfHooks.performance;
}
return true;
}
/** Disables performance measurements for the compiler. */
export function disable() {
perfObserver?.disconnect();
performanceImpl = undefined;
counts.clear();
durations.clear();
}
function updateStatisticsFromList(list: PerformanceObserverEntryList) {
for (const mark of list.getEntriesByType("mark")) {
counts.set(mark.name, (counts.get(mark.name) || 0) + 1);
}
for (const measure of list.getEntriesByType("measure")) {
durations.set(measure.name, (durations.get(measure.name) || 0) + measure.duration);
}
}
}