Skip to content

Commit 2a26beb

Browse files
authored
Add performance framework from transforms branch (#9536)
* Port performance tools from transforms branch * Use friendlier names, add compiler option to print all recorded measures * Always print total time * + -> .getTime
1 parent e52e165 commit 2a26beb

12 files changed

+159
-42
lines changed

Jakefile.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ if (process.env.path !== undefined) {
3434

3535
var compilerSources = [
3636
"core.ts",
37+
"performance.ts",
3738
"sys.ts",
3839
"types.ts",
3940
"scanner.ts",
@@ -54,6 +55,7 @@ var compilerSources = [
5455

5556
var servicesSources = [
5657
"core.ts",
58+
"performance.ts",
5759
"sys.ts",
5860
"types.ts",
5961
"scanner.ts",

src/compiler/binder.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
/* @internal */
55
namespace ts {
6-
export let bindTime = 0;
7-
86
export const enum ModuleInstanceState {
97
NonInstantiated = 0,
108
Instantiated = 1,
@@ -91,9 +89,9 @@ namespace ts {
9189
const binder = createBinder();
9290

9391
export function bindSourceFile(file: SourceFile, options: CompilerOptions) {
94-
const start = new Date().getTime();
92+
const start = performance.mark();
9593
binder(file, options);
96-
bindTime += new Date().getTime() - start;
94+
performance.measure("Bind", start);
9795
}
9896

9997
function createBinder(): (file: SourceFile, options: CompilerOptions) => void {

src/compiler/checker.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ namespace ts {
1515
return node.id;
1616
}
1717

18-
export let checkTime = 0;
19-
2018
export function getSymbolId(symbol: Symbol): number {
2119
if (!symbol.id) {
2220
symbol.id = nextSymbolId;
@@ -17026,11 +17024,11 @@ namespace ts {
1702617024
}
1702717025

1702817026
function checkSourceFile(node: SourceFile) {
17029-
const start = new Date().getTime();
17027+
const start = performance.mark();
1703017028

1703117029
checkSourceFileWorker(node);
1703217030

17033-
checkTime += new Date().getTime() - start;
17031+
performance.measure("Check", start);
1703417032
}
1703517033

1703617034
// Fully type check a source file and collect the relevant diagnostics.

src/compiler/commandLineParser.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ namespace ts {
2727
name: "diagnostics",
2828
type: "boolean",
2929
},
30+
{
31+
name: "extendedDiagnostics",
32+
type: "boolean",
33+
},
3034
{
3135
name: "emitBOM",
3236
type: "boolean"

src/compiler/core.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/// <reference path="types.ts"/>
2+
/// <reference path="performance.ts" />
3+
24

35
/* @internal */
46
namespace ts {

src/compiler/parser.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
/// <reference path="scanner.ts"/>
33

44
namespace ts {
5-
/* @internal */ export let parseTime = 0;
6-
75
let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
86
let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
97
let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
@@ -421,10 +419,10 @@ namespace ts {
421419
}
422420

423421
export function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false, scriptKind?: ScriptKind): SourceFile {
424-
const start = new Date().getTime();
422+
const start = performance.mark();
425423
const result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind);
426424

427-
parseTime += new Date().getTime() - start;
425+
performance.measure("Parse", start);
428426
return result;
429427
}
430428

src/compiler/performance.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*@internal*/
2+
namespace ts {
3+
/** Performance measurements for the compiler. */
4+
export namespace performance {
5+
declare const onProfilerEvent: { (markName: string): void; profiler: boolean; };
6+
declare const performance: { now?(): number } | undefined;
7+
let profilerEvent: (markName: string) => void;
8+
let markInternal: () => number;
9+
let counters: Map<number>;
10+
let measures: Map<number>;
11+
12+
/**
13+
* Emit a performance event if ts-profiler is connected. This is primarily used
14+
* to generate heap snapshots.
15+
*
16+
* @param eventName A name for the event.
17+
*/
18+
export function emit(eventName: string) {
19+
if (profilerEvent) {
20+
profilerEvent(eventName);
21+
}
22+
}
23+
24+
/**
25+
* Increments a counter with the specified name.
26+
*
27+
* @param counterName The name of the counter.
28+
*/
29+
export function increment(counterName: string) {
30+
if (counters) {
31+
counters[counterName] = (getProperty(counters, counterName) || 0) + 1;
32+
}
33+
}
34+
35+
/**
36+
* Gets the value of the counter with the specified name.
37+
*
38+
* @param counterName The name of the counter.
39+
*/
40+
export function getCount(counterName: string) {
41+
return counters && getProperty(counters, counterName) || 0;
42+
}
43+
44+
/**
45+
* Marks the start of a performance measurement.
46+
*/
47+
export function mark() {
48+
return measures ? markInternal() : 0;
49+
}
50+
51+
/**
52+
* Adds a performance measurement with the specified name.
53+
*
54+
* @param measureName The name of the performance measurement.
55+
* @param marker The timestamp of the starting mark.
56+
*/
57+
export function measure(measureName: string, marker: number) {
58+
if (measures) {
59+
measures[measureName] = (getProperty(measures, measureName) || 0) + (Date.now() - marker);
60+
}
61+
}
62+
63+
/**
64+
* Iterate over each measure, performing some action
65+
*
66+
* @param cb The action to perform for each measure
67+
*/
68+
export function forEachMeasure(cb: (measureName: string, duration: number) => void) {
69+
return forEachKey(measures, key => cb(key, measures[key]));
70+
}
71+
72+
/**
73+
* Gets the total duration of all measurements with the supplied name.
74+
*
75+
* @param measureName The name of the measure whose durations should be accumulated.
76+
*/
77+
export function getDuration(measureName: string) {
78+
return measures && getProperty(measures, measureName) || 0;
79+
}
80+
81+
/** Enables (and resets) performance measurements for the compiler. */
82+
export function enable() {
83+
counters = { };
84+
measures = {
85+
"I/O Read": 0,
86+
"I/O Write": 0,
87+
"Program": 0,
88+
"Parse": 0,
89+
"Bind": 0,
90+
"Check": 0,
91+
"Emit": 0,
92+
};
93+
94+
profilerEvent = typeof onProfilerEvent === "function" && onProfilerEvent.profiler === true
95+
? onProfilerEvent
96+
: undefined;
97+
markInternal = performance && performance.now ? performance.now : Date.now ? Date.now : () => new Date().getTime();
98+
}
99+
100+
/** Disables (and clears) performance measurements for the compiler. */
101+
export function disable() {
102+
counters = undefined;
103+
measures = undefined;
104+
profilerEvent = undefined;
105+
}
106+
}
107+
}

src/compiler/program.ts

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,6 @@
33
/// <reference path="core.ts" />
44

55
namespace ts {
6-
/* @internal */ export let programTime = 0;
7-
/* @internal */ export let emitTime = 0;
8-
/* @internal */ export let ioReadTime = 0;
9-
/* @internal */ export let ioWriteTime = 0;
10-
116
/** The version of the TypeScript compiler release */
127
export const version = "2.1.0";
138

@@ -865,9 +860,9 @@ namespace ts {
865860
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile {
866861
let text: string;
867862
try {
868-
const start = new Date().getTime();
863+
const start = performance.mark();
869864
text = sys.readFile(fileName, options.charset);
870-
ioReadTime += new Date().getTime() - start;
865+
performance.measure("I/O Read", start);
871866
}
872867
catch (e) {
873868
if (onError) {
@@ -934,7 +929,7 @@ namespace ts {
934929

935930
function writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) {
936931
try {
937-
const start = new Date().getTime();
932+
const start = performance.mark();
938933
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
939934

940935
if (isWatchSet(options) && sys.createHash && sys.getModifiedTime) {
@@ -944,7 +939,7 @@ namespace ts {
944939
sys.writeFile(fileName, data, writeByteOrderMark);
945940
}
946941

947-
ioWriteTime += new Date().getTime() - start;
942+
performance.measure("I/O Write", start);
948943
}
949944
catch (e) {
950945
if (onError) {
@@ -1121,7 +1116,7 @@ namespace ts {
11211116
// Track source files that are source files found by searching under node_modules, as these shouldn't be compiled.
11221117
const sourceFilesFoundSearchingNodeModules: Map<boolean> = {};
11231118

1124-
const start = new Date().getTime();
1119+
const start = performance.mark();
11251120

11261121
host = host || createCompilerHost(options);
11271122

@@ -1220,7 +1215,7 @@ namespace ts {
12201215

12211216
verifyCompilerOptions();
12221217

1223-
programTime += new Date().getTime() - start;
1218+
performance.measure("Program", start);
12241219

12251220
return program;
12261221

@@ -1463,14 +1458,14 @@ namespace ts {
14631458
// checked is to not pass the file to getEmitResolver.
14641459
const emitResolver = getDiagnosticsProducingTypeChecker().getEmitResolver((options.outFile || options.out) ? undefined : sourceFile);
14651460

1466-
const start = new Date().getTime();
1461+
const start = performance.mark();
14671462

14681463
const emitResult = emitFiles(
14691464
emitResolver,
14701465
getEmitHost(writeFileCallback),
14711466
sourceFile);
14721467

1473-
emitTime += new Date().getTime() - start;
1468+
performance.measure("Emit", start);
14741469
return emitResult;
14751470
}
14761471

src/compiler/sourcemap.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ namespace ts {
240240
return;
241241
}
242242

243+
const start = performance.mark();
244+
243245
const sourceLinePos = getLineAndCharacterOfPosition(currentSourceFile, pos);
244246

245247
// Convert the location to be one-based.
@@ -279,6 +281,8 @@ namespace ts {
279281
}
280282

281283
updateLastEncodedAndRecordedSpans();
284+
285+
performance.measure("Source Map", start);
282286
}
283287

284288
function getStartPos(range: TextRange) {

src/compiler/tsc.ts

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -550,12 +550,8 @@ namespace ts {
550550
}
551551

552552
function compile(fileNames: string[], compilerOptions: CompilerOptions, compilerHost: CompilerHost) {
553-
ioReadTime = 0;
554-
ioWriteTime = 0;
555-
programTime = 0;
556-
bindTime = 0;
557-
checkTime = 0;
558-
emitTime = 0;
553+
const hasDiagnostics = compilerOptions.diagnostics || compilerOptions.extendedDiagnostics;
554+
if (hasDiagnostics) performance.enable();
559555

560556
const program = createProgram(fileNames, compilerOptions, compilerHost);
561557
const exitStatus = compileProgram();
@@ -566,7 +562,7 @@ namespace ts {
566562
});
567563
}
568564

569-
if (compilerOptions.diagnostics) {
565+
if (hasDiagnostics) {
570566
const memoryUsed = sys.getMemoryUsage ? sys.getMemoryUsage() : -1;
571567
reportCountStatistic("Files", program.getSourceFiles().length);
572568
reportCountStatistic("Lines", countLines(program));
@@ -579,17 +575,28 @@ namespace ts {
579575
reportStatisticalValue("Memory used", Math.round(memoryUsed / 1000) + "K");
580576
}
581577

582-
// Individual component times.
583-
// Note: To match the behavior of previous versions of the compiler, the reported parse time includes
584-
// I/O read time and processing time for triple-slash references and module imports, and the reported
585-
// emit time includes I/O write time. We preserve this behavior so we can accurately compare times.
586-
reportTimeStatistic("I/O read", ioReadTime);
587-
reportTimeStatistic("I/O write", ioWriteTime);
588-
reportTimeStatistic("Parse time", programTime);
589-
reportTimeStatistic("Bind time", bindTime);
590-
reportTimeStatistic("Check time", checkTime);
591-
reportTimeStatistic("Emit time", emitTime);
578+
const programTime = performance.getDuration("Program");
579+
const bindTime = performance.getDuration("Bind");
580+
const checkTime = performance.getDuration("Check");
581+
const emitTime = performance.getDuration("Emit");
582+
if (compilerOptions.extendedDiagnostics) {
583+
performance.forEachMeasure((name, duration) => reportTimeStatistic(`${name} time`, duration));
584+
}
585+
else {
586+
// Individual component times.
587+
// Note: To match the behavior of previous versions of the compiler, the reported parse time includes
588+
// I/O read time and processing time for triple-slash references and module imports, and the reported
589+
// emit time includes I/O write time. We preserve this behavior so we can accurately compare times.
590+
reportTimeStatistic("I/O read", performance.getDuration("I/O Read"));
591+
reportTimeStatistic("I/O write", performance.getDuration("I/O Write"));
592+
reportTimeStatistic("Parse time", programTime);
593+
reportTimeStatistic("Bind time", bindTime);
594+
reportTimeStatistic("Check time", checkTime);
595+
reportTimeStatistic("Emit time", emitTime);
596+
}
592597
reportTimeStatistic("Total time", programTime + bindTime + checkTime + emitTime);
598+
599+
performance.disable();
593600
}
594601

595602
return { program, exitStatus };

src/compiler/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
},
1313
"files": [
1414
"core.ts",
15+
"performance.ts",
1516
"sys.ts",
1617
"types.ts",
1718
"scanner.ts",

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2539,6 +2539,7 @@ namespace ts {
25392539
declaration?: boolean;
25402540
declarationDir?: string;
25412541
/* @internal */ diagnostics?: boolean;
2542+
/* @internal */ extendedDiagnostics?: boolean;
25422543
disableSizeLimit?: boolean;
25432544
emitBOM?: boolean;
25442545
emitDecoratorMetadata?: boolean;

0 commit comments

Comments
 (0)