Skip to content

Commit 1be59b2

Browse files
committed
Merge branch 'aggregateTimes' into declEmit
2 parents db8d2f8 + 150c981 commit 1be59b2

File tree

4 files changed

+309
-175
lines changed

4 files changed

+309
-175
lines changed

src/compiler/performance.ts

Lines changed: 176 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,146 +1,209 @@
11
/*@internal*/
22
/** Performance measurements for the compiler. */
3-
namespace ts.performance {
4-
let perfHooks: PerformanceHooks | undefined;
5-
// when set, indicates the implementation of `Performance` to use for user timing.
6-
// when unset, indicates user timing is unavailable or disabled.
7-
let performanceImpl: Performance | undefined;
8-
9-
export interface Timer {
3+
namespace ts {
4+
interface Timer {
105
enter(): void;
116
exit(): void;
127
}
138

14-
export function createTimerIf(condition: boolean, measureName: string, startMarkName: string, endMarkName: string) {
15-
return condition ? createTimer(measureName, startMarkName, endMarkName) : nullTimer;
9+
export interface Statistic {
10+
name: string;
11+
value: number;
12+
type: StatisticType
13+
}
14+
15+
export enum StatisticType {
16+
time,
17+
count,
18+
memory,
1619
}
1720

18-
export function createTimer(measureName: string, startMarkName: string, endMarkName: string): Timer {
19-
let enterCount = 0;
21+
const nullTimer: Timer = { enter: noop, exit: noop };
22+
export const performance = createPerformanceTracker();
23+
export const buildPerformance = createPerformanceTracker();
24+
25+
function createPerformanceTracker() {
26+
let perfHooks: PerformanceHooks | undefined;
27+
// when set, indicates the implementation of `Performance` to use for user timing.
28+
// when unset, indicates user timing is unavailable or disabled.
29+
let performanceImpl: Performance | undefined;
30+
let enabled = false;
31+
let timeorigin = timestamp();
32+
const marks = new Map<string, number>();
33+
const counts = new Map<string, number>();
34+
const durations = new Map<string, number>();
35+
const durationMarks = new Set<string>();
36+
let statistics: ESMap<string, Statistic> | undefined;
37+
2038
return {
21-
enter,
22-
exit
39+
createTimerIf,
40+
createTimer,
41+
mark,
42+
measure,
43+
addStatistics,
44+
getCount,
45+
getDuration,
46+
forEachMeasure,
47+
forEachCount,
48+
forEachStatistics,
49+
isEnabled,
50+
enable,
51+
disable,
2352
};
2453

25-
function enter() {
26-
if (++enterCount === 1) {
27-
mark(startMarkName);
54+
function createTimerIf(condition: boolean, measureName: string, startMarkName: string, endMarkName: string) {
55+
return condition ? createTimer(measureName, startMarkName, endMarkName) : nullTimer;
56+
}
57+
58+
function createTimer(measureName: string, startMarkName: string, endMarkName: string): Timer {
59+
let enterCount = 0;
60+
return {
61+
enter,
62+
exit
63+
};
64+
65+
function enter() {
66+
if (++enterCount === 1) {
67+
mark(startMarkName);
68+
}
69+
}
70+
71+
function exit() {
72+
if (--enterCount === 0) {
73+
mark(endMarkName);
74+
measure(measureName, startMarkName, endMarkName);
75+
}
76+
else if (enterCount < 0) {
77+
Debug.fail("enter/exit count does not match.");
78+
}
2879
}
2980
}
3081

31-
function exit() {
32-
if (--enterCount === 0) {
33-
mark(endMarkName);
34-
measure(measureName, startMarkName, endMarkName);
82+
/**
83+
* Marks a performance event.
84+
*
85+
* @param markName The name of the mark.
86+
*/
87+
function mark(markName: string) {
88+
if (enabled) {
89+
const count = counts.get(markName) ?? 0;
90+
counts.set(markName, count + 1);
91+
marks.set(markName, timestamp());
92+
performanceImpl?.mark(markName);
3593
}
36-
else if (enterCount < 0) {
37-
Debug.fail("enter/exit count does not match.");
94+
}
95+
96+
/**
97+
* Adds a performance measurement with the specified name.
98+
*
99+
* @param measureName The name of the performance measurement.
100+
* @param startMarkName The name of the starting mark. If not supplied, the point at which the
101+
* profiler was enabled is used.
102+
* @param endMarkName The name of the ending mark. If not supplied, the current timestamp is
103+
* used.
104+
*/
105+
function measure(measureName: string, startMarkName: string, endMarkName: string) {
106+
if (enabled) {
107+
durationMarks.add(startMarkName).add(endMarkName);
108+
const end = marks.get(endMarkName) ?? timestamp();
109+
const start = marks.get(startMarkName) ?? timeorigin;
110+
const previousDuration = durations.get(measureName) || 0;
111+
durations.set(measureName, previousDuration + (end - start));
112+
performanceImpl?.measure(measureName, startMarkName, endMarkName);
113+
}
114+
}
115+
116+
function addStatistics(s: Statistic) {
117+
if (enabled) {
118+
const existing = statistics?.get(s.name);
119+
if (existing) {
120+
if (existing.type === StatisticType.memory) existing.value = Math.max(existing.value, s.value);
121+
else existing.value += s.value;
122+
}
123+
else {
124+
(statistics ??= new Map()).set(s.name, s);
125+
}
38126
}
39127
}
40-
}
41128

42-
export const nullTimer: Timer = { enter: noop, exit: noop };
43-
44-
let enabled = false;
45-
let timeorigin = timestamp();
46-
const marks = new Map<string, number>();
47-
const counts = new Map<string, number>();
48-
const durations = new Map<string, number>();
49-
50-
/**
51-
* Marks a performance event.
52-
*
53-
* @param markName The name of the mark.
54-
*/
55-
export function mark(markName: string) {
56-
if (enabled) {
57-
const count = counts.get(markName) ?? 0;
58-
counts.set(markName, count + 1);
59-
marks.set(markName, timestamp());
60-
performanceImpl?.mark(markName);
129+
/**
130+
* Gets the number of times a marker was encountered.
131+
*
132+
* @param markName The name of the mark.
133+
*/
134+
function getCount(markName: string) {
135+
return counts.get(markName) || 0;
61136
}
62-
}
63137

64-
/**
65-
* Adds a performance measurement with the specified name.
66-
*
67-
* @param measureName The name of the performance measurement.
68-
* @param startMarkName The name of the starting mark. If not supplied, the point at which the
69-
* profiler was enabled is used.
70-
* @param endMarkName The name of the ending mark. If not supplied, the current timestamp is
71-
* used.
72-
*/
73-
export function measure(measureName: string, startMarkName?: string, endMarkName?: string) {
74-
if (enabled) {
75-
const end = (endMarkName !== undefined ? marks.get(endMarkName) : undefined) ?? timestamp();
76-
const start = (startMarkName !== undefined ? marks.get(startMarkName) : undefined) ?? timeorigin;
77-
const previousDuration = durations.get(measureName) || 0;
78-
durations.set(measureName, previousDuration + (end - start));
79-
performanceImpl?.measure(measureName, startMarkName, endMarkName);
138+
/**
139+
* Gets the total duration of all measurements with the supplied name.
140+
*
141+
* @param measureName The name of the measure whose durations should be accumulated.
142+
*/
143+
function getDuration(measureName: string) {
144+
return durations.get(measureName) || 0;
80145
}
81-
}
82146

83-
/**
84-
* Gets the number of times a marker was encountered.
85-
*
86-
* @param markName The name of the mark.
87-
*/
88-
export function getCount(markName: string) {
89-
return counts.get(markName) || 0;
90-
}
147+
/**
148+
* Iterate over each measure, performing some action
149+
*
150+
* @param cb The action to perform for each measure
151+
*/
152+
function forEachMeasure(cb: (duration: number, measureName: string) => void) {
153+
durations.forEach(cb);
154+
}
91155

92-
/**
93-
* Gets the total duration of all measurements with the supplied name.
94-
*
95-
* @param measureName The name of the measure whose durations should be accumulated.
96-
*/
97-
export function getDuration(measureName: string) {
98-
return durations.get(measureName) || 0;
99-
}
156+
/**
157+
* Iterate over each count which is not duration mark, performing some action
158+
*
159+
* @param cb The action to perform for each measure
160+
*/
161+
function forEachCount(cb: (count: number, countName: string) => void) {
162+
counts.forEach((count, countName) => !durationMarks.has(countName) && cb(count, countName));
163+
}
100164

101-
/**
102-
* Iterate over each measure, performing some action
103-
*
104-
* @param cb The action to perform for each measure
105-
*/
106-
export function forEachMeasure(cb: (measureName: string, duration: number) => void) {
107-
durations.forEach((duration, measureName) => cb(measureName, duration));
108-
}
109165

110-
/**
111-
* Indicates whether the performance API is enabled.
112-
*/
113-
export function isEnabled() {
114-
return enabled;
115-
}
166+
function forEachStatistics(cb: (statistic: Statistic, name: string) => void) {
167+
statistics?.forEach(cb);
168+
}
116169

117-
/** Enables (and resets) performance measurements for the compiler. */
118-
export function enable(system: System = sys) {
119-
if (!enabled) {
120-
enabled = true;
121-
perfHooks ||= tryGetNativePerformanceHooks();
122-
if (perfHooks) {
123-
timeorigin = perfHooks.performance.timeOrigin;
124-
// NodeJS's Web Performance API is currently slower than expected, but we'd still like
125-
// to be able to leverage native trace events when node is run with either `--cpu-prof`
126-
// or `--prof`, if we're running with our own `--generateCpuProfile` flag, or when
127-
// running in debug mode (since its possible to generate a cpu profile while debugging).
128-
if (perfHooks.shouldWriteNativeEvents || system?.cpuProfilingEnabled?.() || system?.debugMode) {
129-
performanceImpl = perfHooks.performance;
170+
/**
171+
* Indicates whether the performance API is enabled.
172+
*/
173+
function isEnabled() {
174+
return enabled;
175+
}
176+
177+
/** Enables (and resets) performance measurements for the compiler. */
178+
function enable(system: System = sys) {
179+
if (!enabled) {
180+
enabled = true;
181+
perfHooks ||= tryGetNativePerformanceHooks();
182+
if (perfHooks) {
183+
timeorigin = perfHooks.performance.timeOrigin;
184+
// NodeJS's Web Performance API is currently slower than expected, but we'd still like
185+
// to be able to leverage native trace events when node is run with either `--cpu-prof`
186+
// or `--prof`, if we're running with our own `--generateCpuProfile` flag, or when
187+
// running in debug mode (since its possible to generate a cpu profile while debugging).
188+
if (perfHooks.shouldWriteNativeEvents || system?.cpuProfilingEnabled?.() || system?.debugMode) {
189+
performanceImpl = perfHooks.performance;
190+
}
130191
}
131192
}
193+
return true;
132194
}
133-
return true;
134-
}
135195

136-
/** Disables performance measurements for the compiler. */
137-
export function disable() {
138-
if (enabled) {
139-
marks.clear();
140-
counts.clear();
141-
durations.clear();
142-
performanceImpl = undefined;
143-
enabled = false;
196+
/** Disables performance measurements for the compiler. */
197+
function disable() {
198+
if (enabled) {
199+
marks.clear();
200+
counts.clear();
201+
durations.clear();
202+
durationMarks.clear();
203+
statistics?.clear();
204+
performanceImpl = undefined;
205+
enabled = false;
206+
}
144207
}
145208
}
146209
}

src/compiler/sourcemap.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ namespace ts {
55
}
66

77
export function createSourceMapGenerator(host: EmitHost, file: string, sourceRoot: string, sourcesDirectoryPath: string, generatorOptions: SourceMapGeneratorOptions): SourceMapGenerator {
8-
const { enter, exit } = generatorOptions.extendedDiagnostics
9-
? performance.createTimer("Source Map", "beforeSourcemap", "afterSourcemap")
10-
: performance.nullTimer;
8+
const { enter, exit } = performance.createTimerIf(!!generatorOptions.extendedDiagnostics, "Source Map", "beforeSourcemap", "afterSourcemap");
119

1210
// Current source map file and its index in the sources list
1311
const rawSources: string[] = [];

0 commit comments

Comments
 (0)