-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Add performance framework from transforms branch #9536
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
Changes from all commits
8128ce6
6eb0d71
e94ded9
005f209
5a9ba59
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
/// <reference path="types.ts"/> | ||
/// <reference path="performance.ts" /> | ||
|
||
|
||
/* @internal */ | ||
namespace ts { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -554,12 +554,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(); | ||
|
@@ -570,7 +566,7 @@ namespace ts { | |
}); | ||
} | ||
|
||
if (compilerOptions.diagnostics) { | ||
if (hasDiagnostics) { | ||
const memoryUsed = sys.getMemoryUsage ? sys.getMemoryUsage() : -1; | ||
reportCountStatistic("Files", program.getSourceFiles().length); | ||
reportCountStatistic("Lines", countLines(program)); | ||
|
@@ -583,17 +579,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)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With this you'll get different names for statistics than you do below (e.g. "I/O read time" vs. "I/O read"). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True. I could just special-case out the builtins while printing and print them via the old path (though I'd honestly prefer using a single code path if renaming them is okay). |
||
} | ||
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 }; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
}, | ||
"files": [ | ||
"core.ts", | ||
"performance.ts", | ||
"sys.ts", | ||
"types.ts", | ||
"scanner.ts", | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment below on
new Date().getTime()
performance (it should be+new Date()
instead here).Also please use
typeof performance!=='undefined'
instead of just checking for truthiness. Otherwise you'll get ReferenceError on platforms that don't have it defined.Lastly, it's quite non-obvious whether performance identifier here resolves to global-scope performance or ts.performance. I can see you've got that
declare const performance
up at line 6 — but it feels like a trick, and it may come back biting as resolution rules change all the time.Perhaps a clearer solution would be to move the whole
Date.now
thing in together with other fallback-safe utils (forEach, contains, indexOf) in core.ts around line 84?That way rather than having defined and called markInternal here in performance.ts, you'd call
ts.preciseTime()
from core.ts. Also you would replace overly optimistic Date.now at shims.ts isCancellationRequested at line 426 and editorServices.ts resolveNamesWithLocalCache line 145