Skip to content

Commit 729464d

Browse files
authored
Integrate feedback from @mihailik to performance framework (microsoft#9845)
* Integrate feedback from @mihailik * Rons feedback, explicitly include in new tsconfigs
1 parent 80db0f2 commit 729464d

File tree

5 files changed

+115
-111
lines changed

5 files changed

+115
-111
lines changed

src/compiler/performance.ts

+91-89
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,109 @@
11
/*@internal*/
22
namespace ts {
3+
declare const performance: { now?(): number } | undefined;
4+
/** Gets a timestamp with (at least) ms resolution */
5+
export const timestamp = typeof performance !== "undefined" && performance.now ? performance.now : Date.now ? Date.now : () => +(new Date());
6+
}
7+
8+
/*@internal*/
9+
namespace ts.performance {
310
/** 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+
declare const onProfilerEvent: { (markName: string): void; profiler: boolean; };
12+
let profilerEvent: (markName: string) => void;
13+
let counters: Map<number>;
14+
let measures: Map<number>;
1115

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-
}
16+
/**
17+
* Emit a performance event if ts-profiler is connected. This is primarily used
18+
* to generate heap snapshots.
19+
*
20+
* @param eventName A name for the event.
21+
*/
22+
export function emit(eventName: string) {
23+
if (profilerEvent) {
24+
profilerEvent(eventName);
2225
}
26+
}
2327

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-
}
28+
/**
29+
* Increments a counter with the specified name.
30+
*
31+
* @param counterName The name of the counter.
32+
*/
33+
export function increment(counterName: string) {
34+
if (counters) {
35+
counters[counterName] = (getProperty(counters, counterName) || 0) + 1;
3336
}
37+
}
3438

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-
}
39+
/**
40+
* Gets the value of the counter with the specified name.
41+
*
42+
* @param counterName The name of the counter.
43+
*/
44+
export function getCount(counterName: string) {
45+
return counters && getProperty(counters, counterName) || 0;
46+
}
4347

44-
/**
45-
* Marks the start of a performance measurement.
46-
*/
47-
export function mark() {
48-
return measures ? markInternal() : 0;
49-
}
48+
/**
49+
* Marks the start of a performance measurement.
50+
*/
51+
export function mark() {
52+
return measures ? timestamp() : 0;
53+
}
5054

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-
}
55+
/**
56+
* Adds a performance measurement with the specified name.
57+
*
58+
* @param measureName The name of the performance measurement.
59+
* @param marker The timestamp of the starting mark.
60+
*/
61+
export function measure(measureName: string, marker: number) {
62+
if (measures) {
63+
measures[measureName] = (getProperty(measures, measureName) || 0) + (timestamp() - marker);
6164
}
65+
}
6266

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-
}
67+
/**
68+
* Iterate over each measure, performing some action
69+
*
70+
* @param cb The action to perform for each measure
71+
*/
72+
export function forEachMeasure(cb: (measureName: string, duration: number) => void) {
73+
return forEachKey(measures, key => cb(key, measures[key]));
74+
}
7175

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-
}
76+
/**
77+
* Gets the total duration of all measurements with the supplied name.
78+
*
79+
* @param measureName The name of the measure whose durations should be accumulated.
80+
*/
81+
export function getDuration(measureName: string) {
82+
return measures && getProperty(measures, measureName) || 0;
83+
}
8084

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-
};
85+
/** Enables (and resets) performance measurements for the compiler. */
86+
export function enable() {
87+
counters = { };
88+
measures = {
89+
"I/O Read": 0,
90+
"I/O Write": 0,
91+
"Program": 0,
92+
"Parse": 0,
93+
"Bind": 0,
94+
"Check": 0,
95+
"Emit": 0,
96+
};
9397

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-
}
98+
profilerEvent = typeof onProfilerEvent === "function" && onProfilerEvent.profiler === true
99+
? onProfilerEvent
100+
: undefined;
101+
}
99102

100-
/** Disables (and clears) performance measurements for the compiler. */
101-
export function disable() {
102-
counters = undefined;
103-
measures = undefined;
104-
profilerEvent = undefined;
105-
}
103+
/** Disables (and clears) performance measurements for the compiler. */
104+
export function disable() {
105+
counters = undefined;
106+
measures = undefined;
107+
profilerEvent = undefined;
106108
}
107109
}

src/harness/tsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
},
1515
"files": [
1616
"../compiler/core.ts",
17+
"../compiler/performance.ts",
1718
"../compiler/sys.ts",
1819
"../compiler/types.ts",
1920
"../compiler/scanner.ts",

src/services/services.ts

+19-19
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ namespace ts {
434434
}
435435
}
436436
IdentifierObject.prototype.kind = SyntaxKind.Identifier;
437-
437+
438438
class SymbolObject implements Symbol {
439439
flags: SymbolFlags;
440440
name: string;
@@ -3349,14 +3349,14 @@ namespace ts {
33493349

33503350
let isJsDocTagName = false;
33513351

3352-
let start = new Date().getTime();
3352+
let start = timestamp();
33533353
const currentToken = getTokenAtPosition(sourceFile, position);
3354-
log("getCompletionData: Get current token: " + (new Date().getTime() - start));
3354+
log("getCompletionData: Get current token: " + (timestamp() - start));
33553355

3356-
start = new Date().getTime();
3356+
start = timestamp();
33573357
// Completion not allowed inside comments, bail out if this is the case
33583358
const insideComment = isInsideComment(sourceFile, currentToken, position);
3359-
log("getCompletionData: Is inside comment: " + (new Date().getTime() - start));
3359+
log("getCompletionData: Is inside comment: " + (timestamp() - start));
33603360

33613361
if (insideComment) {
33623362
// The current position is next to the '@' sign, when no tag name being provided yet.
@@ -3399,9 +3399,9 @@ namespace ts {
33993399
}
34003400
}
34013401

3402-
start = new Date().getTime();
3402+
start = timestamp();
34033403
const previousToken = findPrecedingToken(position, sourceFile);
3404-
log("getCompletionData: Get previous token 1: " + (new Date().getTime() - start));
3404+
log("getCompletionData: Get previous token 1: " + (timestamp() - start));
34053405

34063406
// The decision to provide completion depends on the contextToken, which is determined through the previousToken.
34073407
// Note: 'previousToken' (and thus 'contextToken') can be undefined if we are the beginning of the file
@@ -3410,9 +3410,9 @@ namespace ts {
34103410
// Check if the caret is at the end of an identifier; this is a partial identifier that we want to complete: e.g. a.toS|
34113411
// Skip this partial identifier and adjust the contextToken to the token that precedes it.
34123412
if (contextToken && position <= contextToken.end && isWord(contextToken.kind)) {
3413-
const start = new Date().getTime();
3413+
const start = timestamp();
34143414
contextToken = findPrecedingToken(contextToken.getFullStart(), sourceFile);
3415-
log("getCompletionData: Get previous token 2: " + (new Date().getTime() - start));
3415+
log("getCompletionData: Get previous token 2: " + (timestamp() - start));
34163416
}
34173417

34183418
// Find the node where completion is requested on.
@@ -3459,7 +3459,7 @@ namespace ts {
34593459
}
34603460
}
34613461

3462-
const semanticStart = new Date().getTime();
3462+
const semanticStart = timestamp();
34633463
let isMemberCompletion: boolean;
34643464
let isNewIdentifierLocation: boolean;
34653465
let symbols: Symbol[] = [];
@@ -3497,7 +3497,7 @@ namespace ts {
34973497
}
34983498
}
34993499

3500-
log("getCompletionData: Semantic work: " + (new Date().getTime() - semanticStart));
3500+
log("getCompletionData: Semantic work: " + (timestamp() - semanticStart));
35013501

35023502
return { symbols, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), isJsDocTagName };
35033503

@@ -3641,12 +3641,12 @@ namespace ts {
36413641
}
36423642

36433643
function isCompletionListBlocker(contextToken: Node): boolean {
3644-
const start = new Date().getTime();
3644+
const start = timestamp();
36453645
const result = isInStringOrRegularExpressionOrTemplateLiteral(contextToken) ||
36463646
isSolelyIdentifierDefinitionLocation(contextToken) ||
36473647
isDotOfNumericLiteral(contextToken) ||
36483648
isInJsxText(contextToken);
3649-
log("getCompletionsAtPosition: isCompletionListBlocker: " + (new Date().getTime() - start));
3649+
log("getCompletionsAtPosition: isCompletionListBlocker: " + (timestamp() - start));
36503650
return result;
36513651
}
36523652

@@ -4299,7 +4299,7 @@ namespace ts {
42994299
}
43004300

43014301
function getCompletionEntriesFromSymbols(symbols: Symbol[], entries: CompletionEntry[], location: Node, performCharacterChecks: boolean): Map<string> {
4302-
const start = new Date().getTime();
4302+
const start = timestamp();
43034303
const uniqueNames: Map<string> = {};
43044304
if (symbols) {
43054305
for (const symbol of symbols) {
@@ -4314,7 +4314,7 @@ namespace ts {
43144314
}
43154315
}
43164316

4317-
log("getCompletionsAtPosition: getCompletionEntriesFromSymbols: " + (new Date().getTime() - start));
4317+
log("getCompletionsAtPosition: getCompletionEntriesFromSymbols: " + (timestamp() - start));
43184318
return uniqueNames;
43194319
}
43204320

@@ -7735,14 +7735,14 @@ namespace ts {
77357735
}
77367736

77377737
function getIndentationAtPosition(fileName: string, position: number, editorOptions: EditorOptions) {
7738-
let start = new Date().getTime();
7738+
let start = timestamp();
77397739
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
7740-
log("getIndentationAtPosition: getCurrentSourceFile: " + (new Date().getTime() - start));
7740+
log("getIndentationAtPosition: getCurrentSourceFile: " + (timestamp() - start));
77417741

7742-
start = new Date().getTime();
7742+
start = timestamp();
77437743

77447744
const result = formatting.SmartIndenter.getIndentation(position, sourceFile, editorOptions);
7745-
log("getIndentationAtPosition: computeIndentation : " + (new Date().getTime() - start));
7745+
log("getIndentationAtPosition: computeIndentation : " + (timestamp() - start));
77467746

77477747
return result;
77487748
}

src/services/shims.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ namespace ts {
423423
}
424424

425425
public isCancellationRequested(): boolean {
426-
const time = Date.now();
426+
const time = timestamp();
427427
const duration = Math.abs(time - this.lastCancellationCheckTime);
428428
if (duration > 10) {
429429
// Check no more than once every 10 ms.
@@ -498,13 +498,13 @@ namespace ts {
498498
let start: number;
499499
if (logPerformance) {
500500
logger.log(actionDescription);
501-
start = Date.now();
501+
start = timestamp();
502502
}
503503

504504
const result = action();
505505

506506
if (logPerformance) {
507-
const end = Date.now();
507+
const end = timestamp();
508508
logger.log(`${actionDescription} completed in ${end - start} msec`);
509509
if (typeof result === "string") {
510510
let str = result;

src/services/tsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
},
1414
"files": [
1515
"../compiler/core.ts",
16+
"../compiler/performance.ts",
1617
"../compiler/sys.ts",
1718
"../compiler/types.ts",
1819
"../compiler/scanner.ts",

0 commit comments

Comments
 (0)