mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-20 13:45:34 -05:00
Integrate feedback from @mihailik to performance framework (#9845)
* Integrate feedback from @mihailik * Rons feedback, explicitly include in new tsconfigs
This commit is contained in:
@@ -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<number>;
|
||||
let measures: Map<number>;
|
||||
declare const onProfilerEvent: { (markName: string): void; profiler: boolean; };
|
||||
let profilerEvent: (markName: string) => void;
|
||||
let counters: Map<number>;
|
||||
let measures: Map<number>;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/** 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();
|
||||
}
|
||||
|
||||
/** Disables (and clears) performance measurements for the compiler. */
|
||||
export function disable() {
|
||||
counters = undefined;
|
||||
measures = undefined;
|
||||
profilerEvent = undefined;
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ? 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) + (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]));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
},
|
||||
"files": [
|
||||
"../compiler/core.ts",
|
||||
"../compiler/performance.ts",
|
||||
"../compiler/sys.ts",
|
||||
"../compiler/types.ts",
|
||||
"../compiler/scanner.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<string> {
|
||||
const start = new Date().getTime();
|
||||
const start = timestamp();
|
||||
const uniqueNames: Map<string> = {};
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
},
|
||||
"files": [
|
||||
"../compiler/core.ts",
|
||||
"../compiler/performance.ts",
|
||||
"../compiler/sys.ts",
|
||||
"../compiler/types.ts",
|
||||
"../compiler/scanner.ts",
|
||||
|
||||
Reference in New Issue
Block a user