Index: tools/plot-timer-events.js |
diff --git a/tools/plot-timer-events.js b/tools/plot-timer-events.js |
index a41f0803fee408ef54b977b80438b98816d9deee..5f8b951b89974532975bb1514d550496a80c5cef 100644 |
--- a/tools/plot-timer-events.js |
+++ b/tools/plot-timer-events.js |
@@ -43,9 +43,6 @@ var kNumPauseLabels = 7; |
var kTickHalfDuration = 0.5; // Milliseconds |
var kCodeKindLabelPadding = 100; |
-var kOverrideRangeStart = undefined; |
-var kOverrideRangeEnd = undefined; |
- |
var num_timer_event = kY1Offset + 0.5; |
@@ -103,6 +100,14 @@ var obj_index = 0; |
var execution_pauses = []; |
var code_map = new CodeMap(); |
+var xrange_start_override = undefined; |
+var xrange_end_override = undefined; |
+var distortion_per_entry = 0.005; // Milliseconds |
+ |
+var sort_by_start = []; |
+var sort_by_end = []; |
+var sorted_ticks = []; |
+ |
function Range(start, end) { |
// Everthing from here are in milliseconds. |
@@ -111,6 +116,11 @@ function Range(start, end) { |
} |
+function Tick(tick) { |
+ this.tick = tick; |
+} |
+ |
+ |
Range.prototype.duration = function() { return this.end - this.start; } |
@@ -120,11 +130,10 @@ function ProcessTimerEvent(name, start, length) { |
start /= 1000; // Convert to milliseconds. |
length /= 1000; |
var end = start + length; |
- event.ranges.push(new Range(start, end)); |
- if (event == kExecutionEvent) { |
- if (start < xrange_start) xrange_start = start; |
- if (end > xrange_end) xrange_end = end; |
- } |
+ var range = new Range(start, end); |
+ event.ranges.push(range); |
+ sort_by_start.push(range); |
+ sort_by_end.push(range); |
} |
@@ -170,11 +179,13 @@ function FindCodeKind(kind) { |
function ProcessTickEvent(pc, sp, timer, unused_x, unused_y, vmstate, stack) { |
timer /= 1000; |
- var tick = new Range(timer - kTickHalfDuration, timer + kTickHalfDuration); |
+ var tick = new Tick(timer); |
+ var entered = false; |
var entry = code_map.findEntry(pc); |
if (entry) { |
FindCodeKind(entry.kind).in_execution.push(tick); |
+ entered = true; |
} |
for (var i = 0; i < kStackFrames; i++) { |
@@ -182,6 +193,76 @@ function ProcessTickEvent(pc, sp, timer, unused_x, unused_y, vmstate, stack) { |
var entry = code_map.findEntry(stack[i]); |
if (entry) { |
FindCodeKind(entry.kind).stack_frames[i].push(tick); |
+ entered = true; |
+ } |
+ } |
+ |
+ if (entered) sorted_ticks.push(tick); |
+} |
+ |
+ |
+function ProcessDistortion(distortion_in_picoseconds) { |
+ distortion_per_entry = distortion_in_picoseconds / 1000000; |
+} |
+ |
+ |
+function ProcessPlotRange(start, end) { |
+ xrange_start_override = start; |
+ xrange_end_override = end; |
+} |
+ |
+ |
+function Undistort() { |
+ // Undistort timers wrt instrumentation overhead. |
+ sort_by_start.sort(function(a, b) { return b.start - a.start; }); |
+ sort_by_end.sort(function(a, b) { return b.end - a.end; }); |
+ sorted_ticks.sort(function(a, b) { return b.tick - a.tick; }); |
+ var distortion = 0; |
+ |
+ var next_start = sort_by_start.pop(); |
+ var next_end = sort_by_end.pop(); |
+ var next_tick = sorted_ticks.pop(); |
+ |
+ function UndistortTicksUntil(tick) { |
+ while (next_tick) { |
+ if (next_tick.tick > tick) return; |
+ next_tick.tick -= distortion; |
+ next_tick = sorted_ticks.pop(); |
+ } |
+ } |
+ |
+ while (true) { |
+ var next_start_start = next_start ? next_start.start : Infinity; |
+ var next_end_end = next_end ? next_end.end : Infinity; |
+ if (!next_start && !next_end) { |
+ UndistortTicksUntil(Infinity); |
+ break; |
+ } |
+ if (next_start_start <= next_end_end) { |
+ UndistortTicksUntil(next_start_start); |
+ // Undistort the start time stamp. |
+ next_start.start -= distortion; |
+ next_start = sort_by_start.pop(); |
+ } else { |
+ // Undistort the end time stamp. We completely attribute the overhead |
+ // to the point when we stop and log the timer, so we increase the |
+ // distortion only here. |
+ UndistortTicksUntil(next_end_end); |
+ distortion += distortion_per_entry; |
+ next_end.end -= distortion; |
+ next_end = sort_by_end.pop(); |
+ } |
+ } |
+ |
+ sort_by_start = undefined; |
+ sort_by_end = undefined; |
+ sorted_ticks = undefined; |
+ |
+ // Make sure that start <= end applies for every range. |
+ for (name in TimerEvents) { |
+ var ranges = TimerEvents[name].ranges; |
+ for (var j = 0; j < ranges.length; j++) { |
+ if (ranges[j].end < ranges[j].start) ranges[j].end = ranges[j].start; |
} |
} |
} |
@@ -203,6 +284,10 @@ function CollectData() { |
'tick': { parsers: [parseInt, parseInt, parseInt, |
null, null, parseInt, 'var-args'], |
processor: ProcessTickEvent }, |
+ 'distortion': { parsers: [parseInt], |
+ processor: ProcessDistortion }, |
+ 'plot-range': { parsers: [parseInt, parseInt], |
+ processor: ProcessPlotRange }, |
}); |
var line; |
@@ -210,6 +295,19 @@ function CollectData() { |
logreader.processLogLine(line); |
} |
+ Undistort(); |
+ |
+ // Figure out plot range. |
+ var execution_ranges = kExecutionEvent.ranges; |
+ for (var i = 0; i < execution_ranges.length; i++) { |
+ if (execution_ranges[i].start < xrange_start) { |
+ xrange_start = execution_ranges[i].start; |
+ } |
+ if (execution_ranges[i].end > xrange_end) { |
+ xrange_end = execution_ranges[i].end; |
+ } |
+ } |
+ |
// Collect execution pauses. |
for (name in TimerEvents) { |
var event = TimerEvents[name]; |
@@ -250,6 +348,16 @@ function DrawBar(row, color, start, end, width) { |
} |
+function TicksToRanges(ticks) { |
+ var ranges = []; |
+ for (var i = 0; i < ticks.length; i++) { |
+ var tick = ticks[i].tick; |
+ ranges.push(new Range(tick - kTickHalfDuration, tick + kTickHalfDuration)); |
+ } |
+ return ranges; |
+} |
+ |
+ |
function MergeRanges(ranges) { |
ranges.sort(function(a, b) { return a.start - b.start; }); |
var result = []; |
@@ -268,6 +376,7 @@ function MergeRanges(ranges) { |
} |
} |
if (merge_end < xrange_start) continue; // Out of plot range. |
+ if (merge_end < merge_start) continue; // Not an actual range. |
result.push(new Range(merge_start, merge_end)); |
} |
return result; |
@@ -357,8 +466,10 @@ function ExcludeRanges(include, exclude) { |
function GnuplotOutput() { |
- xrange_start = kOverrideRangeStart ? kOverrideRangeStart : xrange_start; |
- xrange_end = kOverrideRangeEnd ? kOverrideRangeEnd : xrange_end; |
+ xrange_start = (xrange_start_override || xrange_start_override == 0) |
+ ? xrange_start_override : xrange_start; |
+ xrange_end = (xrange_end_override || xrange_end_override == 0) |
+ ? xrange_end_override : xrange_end; |
print("set terminal pngcairo size " + kResX + "," + kResY + |
" enhanced font 'Helvetica,10'"); |
print("set yrange [0:" + (num_timer_event + 1) + "]"); |
@@ -398,7 +509,7 @@ function GnuplotOutput() { |
var code_kind = CodeKinds[name]; |
var offset = kY1Offset - 1; |
// Top most frame. |
- var row = MergeRanges(code_kind.in_execution); |
+ var row = MergeRanges(TicksToRanges(code_kind.in_execution)); |
for (var j = 0; j < row.length; j++) { |
DrawBar(offset, code_kind.color, |
row[j].start, row[j].end, kExecutionFrameWidth); |
@@ -407,7 +518,7 @@ function GnuplotOutput() { |
// Javascript frames. |
for (var i = 0; i < kStackFrames; i++) { |
offset = offset - 2 * kStackFrameWidth - kGapWidth; |
- row = MergeRanges(code_kind.stack_frames[i]); |
+ row = MergeRanges(TicksToRanges(code_kind.stack_frames[i])); |
for (var j = 0; j < row.length; j++) { |
DrawBar(offset, code_kind.color, |
row[j].start, row[j].end, kStackFrameWidth); |