Add performance framework from transforms branch (#9536)

* Port performance tools from transforms branch

* Use friendlier names, add compiler option to print all recorded measures

* Always print total time

* + -> .getTime
This commit is contained in:
Wesley Wigham 2016-07-19 15:10:29 -07:00 коммит произвёл GitHub
Родитель e52e1659db
Коммит 2a26beb9d8
12 изменённых файлов: 159 добавлений и 42 удалений

Просмотреть файл

@ -34,6 +34,7 @@ if (process.env.path !== undefined) {
var compilerSources = [
"core.ts",
"performance.ts",
"sys.ts",
"types.ts",
"scanner.ts",
@ -54,6 +55,7 @@ var compilerSources = [
var servicesSources = [
"core.ts",
"performance.ts",
"sys.ts",
"types.ts",
"scanner.ts",

Просмотреть файл

@ -3,8 +3,6 @@
/* @internal */
namespace ts {
export let bindTime = 0;
export const enum ModuleInstanceState {
NonInstantiated = 0,
Instantiated = 1,
@ -91,9 +89,9 @@ namespace ts {
const binder = createBinder();
export function bindSourceFile(file: SourceFile, options: CompilerOptions) {
const start = new Date().getTime();
const start = performance.mark();
binder(file, options);
bindTime += new Date().getTime() - start;
performance.measure("Bind", start);
}
function createBinder(): (file: SourceFile, options: CompilerOptions) => void {

Просмотреть файл

@ -15,8 +15,6 @@ namespace ts {
return node.id;
}
export let checkTime = 0;
export function getSymbolId(symbol: Symbol): number {
if (!symbol.id) {
symbol.id = nextSymbolId;
@ -17026,11 +17024,11 @@ namespace ts {
}
function checkSourceFile(node: SourceFile) {
const start = new Date().getTime();
const start = performance.mark();
checkSourceFileWorker(node);
checkTime += new Date().getTime() - start;
performance.measure("Check", start);
}
// Fully type check a source file and collect the relevant diagnostics.

Просмотреть файл

@ -27,6 +27,10 @@ namespace ts {
name: "diagnostics",
type: "boolean",
},
{
name: "extendedDiagnostics",
type: "boolean",
},
{
name: "emitBOM",
type: "boolean"

Просмотреть файл

@ -1,4 +1,6 @@
/// <reference path="types.ts"/>
/// <reference path="performance.ts" />
/* @internal */
namespace ts {

Просмотреть файл

@ -2,8 +2,6 @@
/// <reference path="scanner.ts"/>
namespace ts {
/* @internal */ export let parseTime = 0;
let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
@ -421,10 +419,10 @@ namespace ts {
}
export function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false, scriptKind?: ScriptKind): SourceFile {
const start = new Date().getTime();
const start = performance.mark();
const result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind);
parseTime += new Date().getTime() - start;
performance.measure("Parse", start);
return result;
}

107
src/compiler/performance.ts Normal file
Просмотреть файл

@ -0,0 +1,107 @@
/*@internal*/
namespace ts {
/** 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>;
/**
* 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;
}
}
}

Просмотреть файл

@ -3,11 +3,6 @@
/// <reference path="core.ts" />
namespace ts {
/* @internal */ export let programTime = 0;
/* @internal */ export let emitTime = 0;
/* @internal */ export let ioReadTime = 0;
/* @internal */ export let ioWriteTime = 0;
/** The version of the TypeScript compiler release */
export const version = "2.1.0";
@ -865,9 +860,9 @@ namespace ts {
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile {
let text: string;
try {
const start = new Date().getTime();
const start = performance.mark();
text = sys.readFile(fileName, options.charset);
ioReadTime += new Date().getTime() - start;
performance.measure("I/O Read", start);
}
catch (e) {
if (onError) {
@ -934,7 +929,7 @@ namespace ts {
function writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) {
try {
const start = new Date().getTime();
const start = performance.mark();
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
if (isWatchSet(options) && sys.createHash && sys.getModifiedTime) {
@ -944,7 +939,7 @@ namespace ts {
sys.writeFile(fileName, data, writeByteOrderMark);
}
ioWriteTime += new Date().getTime() - start;
performance.measure("I/O Write", start);
}
catch (e) {
if (onError) {
@ -1121,7 +1116,7 @@ namespace ts {
// Track source files that are source files found by searching under node_modules, as these shouldn't be compiled.
const sourceFilesFoundSearchingNodeModules: Map<boolean> = {};
const start = new Date().getTime();
const start = performance.mark();
host = host || createCompilerHost(options);
@ -1220,7 +1215,7 @@ namespace ts {
verifyCompilerOptions();
programTime += new Date().getTime() - start;
performance.measure("Program", start);
return program;
@ -1463,14 +1458,14 @@ namespace ts {
// checked is to not pass the file to getEmitResolver.
const emitResolver = getDiagnosticsProducingTypeChecker().getEmitResolver((options.outFile || options.out) ? undefined : sourceFile);
const start = new Date().getTime();
const start = performance.mark();
const emitResult = emitFiles(
emitResolver,
getEmitHost(writeFileCallback),
sourceFile);
emitTime += new Date().getTime() - start;
performance.measure("Emit", start);
return emitResult;
}

Просмотреть файл

@ -240,6 +240,8 @@ namespace ts {
return;
}
const start = performance.mark();
const sourceLinePos = getLineAndCharacterOfPosition(currentSourceFile, pos);
// Convert the location to be one-based.
@ -279,6 +281,8 @@ namespace ts {
}
updateLastEncodedAndRecordedSpans();
performance.measure("Source Map", start);
}
function getStartPos(range: TextRange) {

Просмотреть файл

@ -550,12 +550,8 @@ namespace ts {
}
function compile(fileNames: string[], compilerOptions: CompilerOptions, compilerHost: CompilerHost) {
ioReadTime = 0;
ioWriteTime = 0;
programTime = 0;
bindTime = 0;
checkTime = 0;
emitTime = 0;
const hasDiagnostics = compilerOptions.diagnostics || compilerOptions.extendedDiagnostics;
if (hasDiagnostics) performance.enable();
const program = createProgram(fileNames, compilerOptions, compilerHost);
const exitStatus = compileProgram();
@ -566,7 +562,7 @@ namespace ts {
});
}
if (compilerOptions.diagnostics) {
if (hasDiagnostics) {
const memoryUsed = sys.getMemoryUsage ? sys.getMemoryUsage() : -1;
reportCountStatistic("Files", program.getSourceFiles().length);
reportCountStatistic("Lines", countLines(program));
@ -579,17 +575,28 @@ namespace ts {
reportStatisticalValue("Memory used", Math.round(memoryUsed / 1000) + "K");
}
// Individual component times.
// Note: To match the behavior of previous versions of the compiler, the reported parse time includes
// I/O read time and processing time for triple-slash references and module imports, and the reported
// emit time includes I/O write time. We preserve this behavior so we can accurately compare times.
reportTimeStatistic("I/O read", ioReadTime);
reportTimeStatistic("I/O write", ioWriteTime);
reportTimeStatistic("Parse time", programTime);
reportTimeStatistic("Bind time", bindTime);
reportTimeStatistic("Check time", checkTime);
reportTimeStatistic("Emit time", emitTime);
const programTime = performance.getDuration("Program");
const bindTime = performance.getDuration("Bind");
const checkTime = performance.getDuration("Check");
const emitTime = performance.getDuration("Emit");
if (compilerOptions.extendedDiagnostics) {
performance.forEachMeasure((name, duration) => reportTimeStatistic(`${name} time`, duration));
}
else {
// Individual component times.
// Note: To match the behavior of previous versions of the compiler, the reported parse time includes
// I/O read time and processing time for triple-slash references and module imports, and the reported
// emit time includes I/O write time. We preserve this behavior so we can accurately compare times.
reportTimeStatistic("I/O read", performance.getDuration("I/O Read"));
reportTimeStatistic("I/O write", performance.getDuration("I/O Write"));
reportTimeStatistic("Parse time", programTime);
reportTimeStatistic("Bind time", bindTime);
reportTimeStatistic("Check time", checkTime);
reportTimeStatistic("Emit time", emitTime);
}
reportTimeStatistic("Total time", programTime + bindTime + checkTime + emitTime);
performance.disable();
}
return { program, exitStatus };

Просмотреть файл

@ -12,6 +12,7 @@
},
"files": [
"core.ts",
"performance.ts",
"sys.ts",
"types.ts",
"scanner.ts",

Просмотреть файл

@ -2539,6 +2539,7 @@ namespace ts {
declaration?: boolean;
declarationDir?: string;
/* @internal */ diagnostics?: boolean;
/* @internal */ extendedDiagnostics?: boolean;
disableSizeLimit?: boolean;
emitBOM?: boolean;
emitDecoratorMetadata?: boolean;