Skip to content

Integrate feedback from @mihailik to performance framework #9845

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 20, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 91 additions & 89 deletions src/compiler/performance.ts
Original file line number Diff line number Diff line change
@@ -1,107 +1,109 @@
/*@internal*/
namespace ts {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this also be /*@internal*/?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we not want to publicly expose timestamp? I guess we don't have a good reason to expose it, so may as well not.

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);
}
/**
* 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;
}
}
1 change: 1 addition & 0 deletions src/harness/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
},
"files": [
"../compiler/core.ts",
"../compiler/performance.ts",
"../compiler/sys.ts",
"../compiler/types.ts",
"../compiler/scanner.ts",
Expand Down
38 changes: 19 additions & 19 deletions src/services/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ namespace ts {
}
}
IdentifierObject.prototype.kind = SyntaxKind.Identifier;

class SymbolObject implements Symbol {
flags: SymbolFlags;
name: string;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -3459,7 +3459,7 @@ namespace ts {
}
}

const semanticStart = new Date().getTime();
const semanticStart = timestamp();
let isMemberCompletion: boolean;
let isNewIdentifierLocation: boolean;
let symbols: Symbol[] = [];
Expand Down Expand Up @@ -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 };

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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) {
Expand All @@ -4314,7 +4314,7 @@ namespace ts {
}
}

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

Expand Down Expand Up @@ -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;
}
Expand Down
6 changes: 3 additions & 3 deletions src/services/shims.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/services/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
},
"files": [
"../compiler/core.ts",
"../compiler/performance.ts",
"../compiler/sys.ts",
"../compiler/types.ts",
"../compiler/scanner.ts",
Expand Down