diff --git a/src/compiler/performance.ts b/src/compiler/performance.ts index f40b191a1a591..63f929c0a2620 100644 --- a/src/compiler/performance.ts +++ b/src/compiler/performance.ts @@ -1,107 +1,109 @@ /*@internal*/ namespace ts { + declare const performance: { now?(): number } | undefined; + /** Gets a timestamp with (at least) ms resolution */ + export const timestamp = typeof performance !== "undefined" && performance.now ? performance.now : Date.now ? Date.now : () => +(new Date()); +} + +/*@internal*/ +namespace ts.performance { /** Performance measurements for the compiler. */ - export namespace performance { - declare const onProfilerEvent: { (markName: string): void; profiler: boolean; }; - declare const performance: { now?(): number } | undefined; - let profilerEvent: (markName: string) => void; - let markInternal: () => number; - let counters: Map; - let measures: Map; + declare const onProfilerEvent: { (markName: string): void; profiler: boolean; }; + let profilerEvent: (markName: string) => void; + let counters: Map; + let measures: Map; - /** - * Emit a performance event if ts-profiler is connected. This is primarily used - * to generate heap snapshots. - * - * @param eventName A name for the event. - */ - export function emit(eventName: string) { - if (profilerEvent) { - profilerEvent(eventName); - } + /** + * Emit a performance event if ts-profiler is connected. This is primarily used + * to generate heap snapshots. + * + * @param eventName A name for the event. + */ + export function emit(eventName: string) { + if (profilerEvent) { + profilerEvent(eventName); } + } - /** - * Increments a counter with the specified name. - * - * @param counterName The name of the counter. - */ - export function increment(counterName: string) { - if (counters) { - counters[counterName] = (getProperty(counters, counterName) || 0) + 1; - } + /** + * Increments a counter with the specified name. + * + * @param counterName The name of the counter. + */ + export function increment(counterName: string) { + if (counters) { + counters[counterName] = (getProperty(counters, counterName) || 0) + 1; } + } - /** - * Gets the value of the counter with the specified name. - * - * @param counterName The name of the counter. - */ - export function getCount(counterName: string) { - return counters && getProperty(counters, counterName) || 0; - } + /** + * Gets the value of the counter with the specified name. + * + * @param counterName The name of the counter. + */ + export function getCount(counterName: string) { + return counters && getProperty(counters, counterName) || 0; + } - /** - * Marks the start of a performance measurement. - */ - export function mark() { - return measures ? markInternal() : 0; - } + /** + * Marks the start of a performance measurement. + */ + export function mark() { + return measures ? timestamp() : 0; + } - /** - * Adds a performance measurement with the specified name. - * - * @param measureName The name of the performance measurement. - * @param marker The timestamp of the starting mark. - */ - export function measure(measureName: string, marker: number) { - if (measures) { - measures[measureName] = (getProperty(measures, measureName) || 0) + (Date.now() - marker); - } + /** + * Adds a performance measurement with the specified name. + * + * @param measureName The name of the performance measurement. + * @param marker The timestamp of the starting mark. + */ + export function measure(measureName: string, marker: number) { + if (measures) { + measures[measureName] = (getProperty(measures, measureName) || 0) + (timestamp() - marker); } + } - /** - * 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) { - return forEachKey(measures, key => cb(key, measures[key])); - } + /** + * 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) { + return forEachKey(measures, key => cb(key, measures[key])); + } - /** - * 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 measures && getProperty(measures, measureName) || 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 measures && getProperty(measures, measureName) || 0; + } - /** Enables (and resets) performance measurements for the compiler. */ - export function enable() { - counters = { }; - measures = { - "I/O Read": 0, - "I/O Write": 0, - "Program": 0, - "Parse": 0, - "Bind": 0, - "Check": 0, - "Emit": 0, - }; + /** Enables (and resets) performance measurements for the compiler. */ + export function enable() { + counters = { }; + measures = { + "I/O Read": 0, + "I/O Write": 0, + "Program": 0, + "Parse": 0, + "Bind": 0, + "Check": 0, + "Emit": 0, + }; - profilerEvent = typeof onProfilerEvent === "function" && onProfilerEvent.profiler === true - ? onProfilerEvent - : undefined; - markInternal = performance && performance.now ? performance.now : Date.now ? Date.now : () => new Date().getTime(); - } + profilerEvent = typeof onProfilerEvent === "function" && onProfilerEvent.profiler === true + ? onProfilerEvent + : undefined; + } - /** Disables (and clears) performance measurements for the compiler. */ - export function disable() { - counters = undefined; - measures = undefined; - profilerEvent = undefined; - } + /** Disables (and clears) performance measurements for the compiler. */ + export function disable() { + counters = undefined; + measures = undefined; + profilerEvent = undefined; } } \ No newline at end of file diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json index 5853bee327419..3b9025c27c362 100644 --- a/src/harness/tsconfig.json +++ b/src/harness/tsconfig.json @@ -14,6 +14,7 @@ }, "files": [ "../compiler/core.ts", + "../compiler/performance.ts", "../compiler/sys.ts", "../compiler/types.ts", "../compiler/scanner.ts", diff --git a/src/services/services.ts b/src/services/services.ts index d9e025cf8fd0c..226d18f77dc61 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -434,7 +434,7 @@ namespace ts { } } IdentifierObject.prototype.kind = SyntaxKind.Identifier; - + class SymbolObject implements Symbol { flags: SymbolFlags; name: string; @@ -3349,14 +3349,14 @@ namespace ts { let isJsDocTagName = false; - let start = new Date().getTime(); + let start = timestamp(); const currentToken = getTokenAtPosition(sourceFile, position); - log("getCompletionData: Get current token: " + (new Date().getTime() - start)); + log("getCompletionData: Get current token: " + (timestamp() - start)); - start = new Date().getTime(); + start = timestamp(); // Completion not allowed inside comments, bail out if this is the case const insideComment = isInsideComment(sourceFile, currentToken, position); - log("getCompletionData: Is inside comment: " + (new Date().getTime() - start)); + log("getCompletionData: Is inside comment: " + (timestamp() - start)); if (insideComment) { // The current position is next to the '@' sign, when no tag name being provided yet. @@ -3399,9 +3399,9 @@ namespace ts { } } - start = new Date().getTime(); + start = timestamp(); const previousToken = findPrecedingToken(position, sourceFile); - log("getCompletionData: Get previous token 1: " + (new Date().getTime() - start)); + log("getCompletionData: Get previous token 1: " + (timestamp() - start)); // The decision to provide completion depends on the contextToken, which is determined through the previousToken. // Note: 'previousToken' (and thus 'contextToken') can be undefined if we are the beginning of the file @@ -3410,9 +3410,9 @@ namespace ts { // 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| // Skip this partial identifier and adjust the contextToken to the token that precedes it. if (contextToken && position <= contextToken.end && isWord(contextToken.kind)) { - const start = new Date().getTime(); + const start = timestamp(); contextToken = findPrecedingToken(contextToken.getFullStart(), sourceFile); - log("getCompletionData: Get previous token 2: " + (new Date().getTime() - start)); + log("getCompletionData: Get previous token 2: " + (timestamp() - start)); } // Find the node where completion is requested on. @@ -3459,7 +3459,7 @@ namespace ts { } } - const semanticStart = new Date().getTime(); + const semanticStart = timestamp(); let isMemberCompletion: boolean; let isNewIdentifierLocation: boolean; let symbols: Symbol[] = []; @@ -3497,7 +3497,7 @@ namespace ts { } } - log("getCompletionData: Semantic work: " + (new Date().getTime() - semanticStart)); + log("getCompletionData: Semantic work: " + (timestamp() - semanticStart)); return { symbols, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), isJsDocTagName }; @@ -3641,12 +3641,12 @@ namespace ts { } function isCompletionListBlocker(contextToken: Node): boolean { - const start = new Date().getTime(); + const start = timestamp(); const result = isInStringOrRegularExpressionOrTemplateLiteral(contextToken) || isSolelyIdentifierDefinitionLocation(contextToken) || isDotOfNumericLiteral(contextToken) || isInJsxText(contextToken); - log("getCompletionsAtPosition: isCompletionListBlocker: " + (new Date().getTime() - start)); + log("getCompletionsAtPosition: isCompletionListBlocker: " + (timestamp() - start)); return result; } @@ -4299,7 +4299,7 @@ namespace ts { } function getCompletionEntriesFromSymbols(symbols: Symbol[], entries: CompletionEntry[], location: Node, performCharacterChecks: boolean): Map { - const start = new Date().getTime(); + const start = timestamp(); const uniqueNames: Map = {}; if (symbols) { for (const symbol of symbols) { @@ -4314,7 +4314,7 @@ namespace ts { } } - log("getCompletionsAtPosition: getCompletionEntriesFromSymbols: " + (new Date().getTime() - start)); + log("getCompletionsAtPosition: getCompletionEntriesFromSymbols: " + (timestamp() - start)); return uniqueNames; } @@ -7735,14 +7735,14 @@ namespace ts { } function getIndentationAtPosition(fileName: string, position: number, editorOptions: EditorOptions) { - let start = new Date().getTime(); + let start = timestamp(); const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); - log("getIndentationAtPosition: getCurrentSourceFile: " + (new Date().getTime() - start)); + log("getIndentationAtPosition: getCurrentSourceFile: " + (timestamp() - start)); - start = new Date().getTime(); + start = timestamp(); const result = formatting.SmartIndenter.getIndentation(position, sourceFile, editorOptions); - log("getIndentationAtPosition: computeIndentation : " + (new Date().getTime() - start)); + log("getIndentationAtPosition: computeIndentation : " + (timestamp() - start)); return result; } diff --git a/src/services/shims.ts b/src/services/shims.ts index e85bf537d30fb..271d6f2d6e205 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -423,7 +423,7 @@ namespace ts { } public isCancellationRequested(): boolean { - const time = Date.now(); + const time = timestamp(); const duration = Math.abs(time - this.lastCancellationCheckTime); if (duration > 10) { // Check no more than once every 10 ms. @@ -498,13 +498,13 @@ namespace ts { let start: number; if (logPerformance) { logger.log(actionDescription); - start = Date.now(); + start = timestamp(); } const result = action(); if (logPerformance) { - const end = Date.now(); + const end = timestamp(); logger.log(`${actionDescription} completed in ${end - start} msec`); if (typeof result === "string") { let str = result; diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 86efd25493720..cfeb7c2fcd582 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -13,6 +13,7 @@ }, "files": [ "../compiler/core.ts", + "../compiler/performance.ts", "../compiler/sys.ts", "../compiler/types.ts", "../compiler/scanner.ts",