Skip to content

Simplifies performance API #10327

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
Aug 15, 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
5 changes: 3 additions & 2 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,10 @@ namespace ts {
const binder = createBinder();

export function bindSourceFile(file: SourceFile, options: CompilerOptions) {
const start = performance.mark();
performance.mark("beforeBind");
binder(file, options);
performance.measure("Bind", start);
performance.mark("afterBind");
performance.measure("Bind", "beforeBind", "afterBind");
}

function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
Expand Down
7 changes: 3 additions & 4 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17535,11 +17535,10 @@ namespace ts {
}

function checkSourceFile(node: SourceFile) {
const start = performance.mark();

performance.mark("beforeCheck");
checkSourceFileWorker(node);

performance.measure("Check", start);
performance.mark("afterCheck");
Copy link
Contributor

Choose a reason for hiding this comment

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

question: it seems you don't have to call mark here then as the function 'measure' will call timestamp() if you don't pass the end mark anyway?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I call mark to emit the performance event, that way I can query a cpuprofile for things like between(checkStart, checkEnd).

performance.measure("Check", "beforeCheck", "afterCheck");
}

// Fully type check a source file and collect the relevant diagnostics.
Expand Down
6 changes: 3 additions & 3 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,10 +421,10 @@ namespace ts {
}

export function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false, scriptKind?: ScriptKind): SourceFile {
const start = performance.mark();
performance.mark("beforeParse");
const result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind);

performance.measure("Parse", start);
performance.mark("afterParse");
performance.measure("Parse", "beforeParse", "afterParse");
return result;
}

Expand Down
110 changes: 48 additions & 62 deletions src/compiler/performance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,104 +6,90 @@ namespace ts {
}

/*@internal*/
/** Performance measurements for the compiler. */
namespace ts.performance {
/** Performance measurements for the compiler. */
declare const onProfilerEvent: { (markName: string): void; profiler: boolean; };
let profilerEvent: (markName: string) => void;
let counters: MapLike<number>;
let measures: MapLike<number>;

const profilerEvent = typeof onProfilerEvent === "function" && onProfilerEvent.profiler === true
? onProfilerEvent
: (markName: string) => { };

let enabled = false;
let profilerStart = 0;
let counts: Map<number>;
let marks: Map<number>;
let measures: Map<number>;

/**
* Emit a performance event if ts-profiler is connected. This is primarily used
* to generate heap snapshots.
* Marks a performance event.
*
* @param eventName A name for the event.
* @param markName The name of the mark.
*/
export function emit(eventName: string) {
if (profilerEvent) {
profilerEvent(eventName);
export function mark(markName: string) {
if (enabled) {
marks[markName] = timestamp();
counts[markName] = (counts[markName] || 0) + 1;
profilerEvent(markName);
}
}

/**
* Increments a counter with the specified name.
* Adds a performance measurement with the specified name.
*
* @param counterName The name of the counter.
* @param measureName The name of the performance measurement.
* @param startMarkName The name of the starting mark. If not supplied, the point at which the
* profiler was enabled is used.
* @param endMarkName The name of the ending mark. If not supplied, the current timestamp is
* used.
*/
export function increment(counterName: string) {
if (counters) {
counters[counterName] = (getProperty(counters, counterName) || 0) + 1;
export function measure(measureName: string, startMarkName?: string, endMarkName?: string) {
if (enabled) {
const end = endMarkName && marks[endMarkName] || timestamp();
const start = startMarkName && marks[startMarkName] || profilerStart;
measures[measureName] = (measures[measureName] || 0) + (end - start);
}
}

/**
* Gets the value of the counter with the specified name.
* Gets the number of times a marker was encountered.
*
* @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.
* @param markName The name of the mark.
*/
export function mark() {
return measures ? timestamp() : 0;
export function getCount(markName: string) {
return counts && counts[markName] || 0;
}

/**
* Adds a performance measurement with the specified name.
* Gets the total duration of all measurements with the supplied name.
*
* @param measureName The name of the performance measurement.
* @param marker The timestamp of the starting mark.
* @param measureName The name of the measure whose durations should be accumulated.
*/
export function measure(measureName: string, marker: number) {
if (measures) {
measures[measureName] = (getProperty(measures, measureName) || 0) + (timestamp() - marker);
}
export function getDuration(measureName: string) {
return measures && measures[measureName] || 0;
}

/**
* 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;
for (const key in measures) {
cb(key, measures[key]);
}
}

/** 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;
counts = createMap<number>();
marks = createMap<number>();
measures = createMap<number>();
enabled = true;
profilerStart = timestamp();
}

/** Disables (and clears) performance measurements for the compiler. */
/** Disables performance measurements for the compiler. */
export function disable() {
counters = undefined;
measures = undefined;
profilerEvent = undefined;
enabled = false;
}
}
21 changes: 12 additions & 9 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -857,9 +857,10 @@ namespace ts {
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile {
let text: string;
try {
const start = performance.mark();
performance.mark("beforeIORead");
text = sys.readFile(fileName, options.charset);
performance.measure("I/O Read", start);
performance.mark("afterIORead");
performance.measure("I/O Read", "beforeIORead", "afterIORead");
}
catch (e) {
if (onError) {
Expand Down Expand Up @@ -926,7 +927,7 @@ namespace ts {

function writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) {
try {
const start = performance.mark();
performance.mark("beforeIOWrite");
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));

if (isWatchSet(options) && sys.createHash && sys.getModifiedTime) {
Expand All @@ -936,7 +937,8 @@ namespace ts {
sys.writeFile(fileName, data, writeByteOrderMark);
}

performance.measure("I/O Write", start);
performance.mark("afterIOWrite");
performance.measure("I/O Write", "beforeIOWrite", "afterIOWrite");
}
catch (e) {
if (onError) {
Expand Down Expand Up @@ -1118,7 +1120,7 @@ namespace ts {
// Track source files that are source files found by searching under node_modules, as these shouldn't be compiled.
const sourceFilesFoundSearchingNodeModules = createMap<boolean>();

const start = performance.mark();
performance.mark("beforeProgram");

host = host || createCompilerHost(options);

Expand Down Expand Up @@ -1216,8 +1218,8 @@ namespace ts {
};

verifyCompilerOptions();

performance.measure("Program", start);
performance.mark("afterProgram");
performance.measure("Program", "beforeProgram", "afterProgram");

return program;

Expand Down Expand Up @@ -1460,14 +1462,15 @@ namespace ts {
// checked is to not pass the file to getEmitResolver.
const emitResolver = getDiagnosticsProducingTypeChecker().getEmitResolver((options.outFile || options.out) ? undefined : sourceFile);

const start = performance.mark();
performance.mark("beforeEmit");

const emitResult = emitFiles(
emitResolver,
getEmitHost(writeFileCallback),
sourceFile);

performance.measure("Emit", start);
performance.mark("afterEmit");
performance.measure("Emit", "beforeEmit", "afterEmit");
return emitResult;
}

Expand Down
10 changes: 8 additions & 2 deletions src/compiler/sourcemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ namespace ts {

export function createSourceMapWriter(host: EmitHost, writer: EmitTextWriter): SourceMapWriter {
const compilerOptions = host.getCompilerOptions();
const extendedDiagnostics = compilerOptions.extendedDiagnostics;
let currentSourceFile: SourceFile;
let sourceMapDir: string; // The directory in which sourcemap will be
let stopOverridingSpan = false;
Expand Down Expand Up @@ -240,7 +241,9 @@ namespace ts {
return;
}

const start = performance.mark();
if (extendedDiagnostics) {
performance.mark("beforeSourcemap");
}

const sourceLinePos = getLineAndCharacterOfPosition(currentSourceFile, pos);

Expand Down Expand Up @@ -282,7 +285,10 @@ namespace ts {

updateLastEncodedAndRecordedSpans();

performance.measure("Source Map", start);
if (extendedDiagnostics) {
performance.mark("afterSourcemap");
performance.measure("Source Map", "beforeSourcemap", "afterSourcemap");
}
}

function getStartPos(range: TextRange) {
Expand Down