Skip to content

Commit

Permalink
Expand the Tracer output to include a manifset of the node types in t…
Browse files Browse the repository at this point in the history
…he AST when compilation begins.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=258806366
  • Loading branch information
nreid260 authored and lauraharker committed Jul 19, 2019
1 parent f0e7813 commit 33a97c3
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 62 deletions.
83 changes: 58 additions & 25 deletions src/com/google/javascript/jscomp/PerformanceTracker.java
Expand Up @@ -21,10 +21,12 @@


import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultiset;
import com.google.javascript.jscomp.CompilerOptions.TracerMode; import com.google.javascript.jscomp.CompilerOptions.TracerMode;
import com.google.javascript.jscomp.parsing.parser.util.format.SimpleFormat; import com.google.javascript.jscomp.parsing.parser.util.format.SimpleFormat;
import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.StaticSourceFile; import com.google.javascript.rhino.StaticSourceFile;
import com.google.javascript.rhino.Token;
import java.io.FilterOutputStream; import java.io.FilterOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
Expand Down Expand Up @@ -85,7 +87,9 @@ public final class PerformanceTracker {
private final Deque<Stats> currentPass = new ArrayDeque<>(); private final Deque<Stats> currentPass = new ArrayDeque<>();


/** Cumulative stats for each compiler pass. */ /** Cumulative stats for each compiler pass. */
private ImmutableMap<String, Stats> summary; private ImmutableMap<String, Stats> passSummary;

private ImmutableMultiset<Token> astManifest;


/** Stats a single run of a compiler pass. */ /** Stats a single run of a compiler pass. */
private final List<Stats> log = new ArrayList<>(); private final List<Stats> log = new ArrayList<>();
Expand Down Expand Up @@ -162,6 +166,9 @@ void recordPassStop(String passName, long runtime) {
} }


private void recordParsingStop(Stats logStats) { private void recordParsingStop(Stats logStats) {
if (tracksAstManifest()) {
populateAstManifest();
}
recordInputCount(); recordInputCount();
if (!tracksAstSize()) { if (!tracksAstSize()) {
return; return;
Expand Down Expand Up @@ -239,6 +246,10 @@ public boolean tracksAstSize() {
return this.mode != TracerMode.TIMING_ONLY; return this.mode != TracerMode.TIMING_ONLY;
} }


public boolean tracksAstManifest() {
return this.mode.isOn();
}

public int getRuntime() { public int getRuntime() {
calcTotalStats(); calcTotalStats();
return this.passesRuntime; return this.passesRuntime;
Expand Down Expand Up @@ -285,19 +296,19 @@ int getLoopRuns() {


public ImmutableMap<String, Stats> getStats() { public ImmutableMap<String, Stats> getStats() {
calcTotalStats(); calcTotalStats();
return this.summary; return this.passSummary;
} }


private void calcTotalStats() { private void calcTotalStats() {
// This method only does work the first time it is called // This method only does work the first time it is called
if (this.summary != null) { if (this.passSummary != null) {
return; return;
} }
this.endTime = System.currentTimeMillis(); this.endTime = System.currentTimeMillis();


populateSummary(); populatePassSummary();


for (Entry<String, Stats> entry : this.summary.entrySet()) { for (Entry<String, Stats> entry : this.passSummary.entrySet()) {
Stats stats = entry.getValue(); Stats stats = entry.getValue();
this.passesRuntime += stats.runtime; this.passesRuntime += stats.runtime;
this.maxMem = Math.max(this.maxMem, stats.allocMem); this.maxMem = Math.max(this.maxMem, stats.allocMem);
Expand All @@ -316,15 +327,15 @@ private void calcTotalStats() {
checkState(!tracksGzSize() || this.initGzCodeSize == this.gzDiff + this.gzCodeSize); checkState(!tracksGzSize() || this.initGzCodeSize == this.gzDiff + this.gzCodeSize);
} }


private void populateSummary() { private void populatePassSummary() {
HashMap<String, Stats> tmpSummary = new HashMap<>(); HashMap<String, Stats> tmpPassSummary = new HashMap<>();


for (Stats logStat : this.log) { for (Stats logStat : this.log) {
String passName = logStat.pass; String passName = logStat.pass;
Stats entry = tmpSummary.get(passName); Stats entry = tmpPassSummary.get(passName);
if (entry == null) { if (entry == null) {
entry = new Stats(passName, logStat.isOneTime); entry = new Stats(passName, logStat.isOneTime);
tmpSummary.put(passName, entry); tmpPassSummary.put(passName, entry);
} }
entry.runtime += logStat.runtime; entry.runtime += logStat.runtime;
entry.allocMem = Math.max(entry.allocMem, logStat.allocMem); entry.allocMem = Math.max(entry.allocMem, logStat.allocMem);
Expand All @@ -333,12 +344,22 @@ private void populateSummary() {
entry.astDiff += logStat.astDiff; entry.astDiff += logStat.astDiff;
entry.diff += logStat.diff; entry.diff += logStat.diff;
entry.gzDiff += logStat.gzDiff; entry.gzDiff += logStat.gzDiff;
// We don't populate the size fields in the summary stats. // We don't populate the size fields in the passSummary stats.
// We used to put the size after the last time a pass was run, but that is // We used to put the size after the last time a pass was run, but that is
// a pretty meaningless thing to measure. // a pretty meaningless thing to measure.
} }


this.summary = ImmutableMap.copyOf(tmpSummary); this.passSummary = ImmutableMap.copyOf(tmpPassSummary);
}

private void populateAstManifest() {
if (this.astManifest != null) {
return;
}

ImmutableMultiset.Builder<Token> builder = ImmutableMultiset.builder();
NodeUtil.visitPreOrder(this.jsRoot, (n) -> builder.add(n.getToken()));
this.astManifest = builder.build();
} }


/** /**
Expand Down Expand Up @@ -383,24 +404,24 @@ public void outputTracerReport(PrintStream output) {
"", "",
"Summary:", "Summary:",
"pass,runtime,allocMem,runs,changingRuns,astReduction,reduction,gzReduction")); "pass,runtime,allocMem,runs,changingRuns,astReduction,reduction,gzReduction"));
this.summary.entrySet().stream() this.passSummary.entrySet().stream()
.sorted((e1, e2) -> Long.compare(e1.getValue().runtime, e2.getValue().runtime)) .sorted((e1, e2) -> Long.compare(e1.getValue().runtime, e2.getValue().runtime))
.forEach( .map(
(entry) -> { (entry) -> {
String key = entry.getKey(); String key = entry.getKey();
Stats stats = entry.getValue(); Stats stats = entry.getValue();
output.print( return SimpleFormat.format(
SimpleFormat.format( "%s,%d,%d,%d,%d,%d,%d,%d",
"%s,%d,%d,%d,%d,%d,%d,%d\n", key,
key, stats.runtime,
stats.runtime, stats.allocMem,
stats.allocMem, stats.runs,
stats.runs, stats.changes,
stats.changes, stats.astDiff,
stats.astDiff, stats.diff,
stats.diff, stats.gzDiff);
stats.gzDiff)); })
}); .forEach(output::println);


output.println( output.println(
lines( lines(
Expand All @@ -423,6 +444,18 @@ public void outputTracerReport(PrintStream output) {
stats.gzSize)); stats.gzSize));
} }


if (this.astManifest != null) {
output.println(
lines(
"", //
"Input AST Manifest:",
"token,count"));
this.astManifest.entrySet().stream()
.map((e) -> SimpleFormat.format("%s,%d", e.getElement(), e.getCount()))
.sorted()
.forEach(output::println);
}

output.println(); output.println();


// this.output can be System.out, so don't close it to not lose subsequent // this.output can be System.out, so don't close it to not lose subsequent
Expand Down
122 changes: 85 additions & 37 deletions test/com/google/javascript/jscomp/PerformanceTrackerTest.java
Expand Up @@ -18,10 +18,10 @@


import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;


import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.javascript.jscomp.CompilerOptions.TracerMode; import com.google.javascript.jscomp.CompilerOptions.TracerMode;
import com.google.javascript.jscomp.PerformanceTracker.Stats; import com.google.javascript.jscomp.PerformanceTracker.Stats;
import com.google.javascript.rhino.IR;
import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token; import com.google.javascript.rhino.Token;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
Expand Down Expand Up @@ -106,47 +106,95 @@ public void testStatsCalculation() {
assertThat(st.changes).isEqualTo(0); assertThat(st.changes).isEqualTo(0);
} }


@Test
public void testAstSummaryAndFormat() {
// Given
Node main =
IR.root(
IR.script(
IR.block(
IR.block(
IR.exprResult( //
IR.hook(IR.string("a"), IR.string("b"), IR.string("c")))),
IR.function(IR.name("name"), IR.paramList(), IR.block()))));
PerformanceTracker tracker =
new PerformanceTracker(emptyExternRoot, main, TracerMode.TIMING_ONLY);

// When
tracker.recordPassStart(PassNames.PARSE_INPUTS, true);
tracker.recordPassStop(PassNames.PARSE_INPUTS, 0); // This is what triggers the counting.
String report = extractReport(tracker);

// Then
assertThat(report)
.containsMatch(
Pattern.compile(
lines(
"Input AST Manifest:",
"token,count",
"BLOCK,3",
"EXPR_RESULT,1",
"FUNCTION,1",
"HOOK,1",
"NAME,1",
"PARAM_LIST,1",
"ROOT,1",
"SCRIPT,1",
"STRING,3"),
Pattern.DOTALL));
}

@Test @Test
public void testOutputFormat() { public void testOutputFormat() {
PerformanceTracker tracker =
new PerformanceTracker(emptyExternRoot, emptyJsRoot, TracerMode.ALL);
String report = extractReport(tracker);
Pattern p =
Pattern.compile(
lines(
".*TOTAL:",
"Start time\\(ms\\): [0-9]+",
"End time\\(ms\\): [0-9]+",
"Wall time\\(ms\\): [0-9]+",
"Passes runtime\\(ms\\): [0-9]+",
"Max mem usage \\(measured after each pass\\)\\(MB\\): -?[0-9]+",
"#Runs: [0-9]+",
"#Changing runs: [0-9]+",
"#Loopable runs: [0-9]+",
"#Changing loopable runs: [0-9]+",
"Estimated AST reduction\\(#nodes\\): [0-9]+",
"Estimated Reduction\\(bytes\\): [0-9]+",
"Estimated GzReduction\\(bytes\\): [0-9]+",
"Estimated AST size\\(#nodes\\): -?[0-9]+",
"Estimated Size\\(bytes\\): -?[0-9]+",
"Estimated GzSize\\(bytes\\): -?[0-9]+",
"",
"Inputs:",
"JS lines: [0-9]+",
"JS sources: [0-9]+",
"Extern lines: [0-9]+",
"Extern sources: [0-9]+",
"",
"Summary:",
"pass,runtime,allocMem,runs,changingRuns,astReduction,reduction,gzReduction",
"",
"Log:",
"pass,runtime,allocMem,codeChanged,astReduction,reduction,gzReduction,astSize,size,gzSize",
".*"),
Pattern.DOTALL);

assertThat(report).matches(p);
}

private static final String extractReport(PerformanceTracker tracker) {
ByteArrayOutputStream output = new ByteArrayOutputStream(); ByteArrayOutputStream output = new ByteArrayOutputStream();
try (PrintStream outstream = new PrintStream(output)) { try (PrintStream outstream = new PrintStream(output)) {
PerformanceTracker tracker =
new PerformanceTracker(emptyExternRoot, emptyJsRoot, TracerMode.ALL);
tracker.outputTracerReport(outstream); tracker.outputTracerReport(outstream);
} }
Pattern p = Pattern.compile(Joiner.on("\n").join( return output.toString();
".*TOTAL:", }
"Start time\\(ms\\): [0-9]+",
"End time\\(ms\\): [0-9]+", private static String lines(String... lines) {
"Wall time\\(ms\\): [0-9]+", return String.join("\n", lines);
"Passes runtime\\(ms\\): [0-9]+",
"Max mem usage \\(measured after each pass\\)\\(MB\\): -?[0-9]+",
"#Runs: [0-9]+",
"#Changing runs: [0-9]+",
"#Loopable runs: [0-9]+",
"#Changing loopable runs: [0-9]+",
"Estimated AST reduction\\(#nodes\\): [0-9]+",
"Estimated Reduction\\(bytes\\): [0-9]+",
"Estimated GzReduction\\(bytes\\): [0-9]+",
"Estimated AST size\\(#nodes\\): -?[0-9]+",
"Estimated Size\\(bytes\\): -?[0-9]+",
"Estimated GzSize\\(bytes\\): -?[0-9]+",
"",
"Inputs:",
"JS lines: [0-9]+",
"JS sources: [0-9]+",
"Extern lines: [0-9]+",
"Extern sources: [0-9]+",
"",
"Summary:",
"pass,runtime,allocMem,runs,changingRuns,astReduction,reduction,gzReduction",
"",
"Log:",
"pass,runtime,allocMem,codeChanged,astReduction,reduction,gzReduction,astSize,size,gzSize",
"",
".*"),
Pattern.DOTALL);
String outputString = output.toString();
assertThat(outputString).matches(p);
} }
} }

0 comments on commit 33a97c3

Please sign in to comment.