1b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Copyright 2013 the V8 project authors. All rights reserved.
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Redistribution and use in source and binary forms, with or without
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// modification, are permitted provided that the following conditions are
4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// met:
5b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch//
6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch//     * Redistributions of source code must retain the above copyright
7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch//       notice, this list of conditions and the following disclaimer.
8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch//     * Redistributions in binary form must reproduce the above
9b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch//       copyright notice, this list of conditions and the following
10b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch//       disclaimer in the documentation and/or other materials provided
11b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch//       with the distribution.
12b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch//     * Neither the name of Google Inc. nor the names of its
13b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch//       contributors may be used to endorse or promote products derived
14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch//       from this software without specific prior written permission.
15b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch//
16b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochArray.prototype.top = function() {
29b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (this.length == 0) return undefined;
30b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return this[this.length - 1];
31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
33b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction PlotScriptComposer(kResX, kResY, error_output) {
35b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Constants.
36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var kV8BinarySuffixes = ["/d8", "/libv8.so"];
37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var kStackFrames = 8;             // Stack frames to display in the plot.
38b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
39b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var kTimerEventWidth = 0.33;      // Width of each timeline.
40b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var kExecutionFrameWidth = 0.2;   // Width of the top stack frame line.
41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var kStackFrameWidth = 0.1;       // Width of the lower stack frame lines.
42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var kGapWidth = 0.05;             // Gap between stack frame lines.
43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var kY1Offset = 11;               // Offset for stack frame vs. event lines.
45b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var kDeoptRow = 7;                // Row displaying deopts.
46b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var kGetTimeHeight = 0.5;         // Height of marker displaying timed part.
47b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var kMaxDeoptLength = 4;          // Draw size of the largest deopt.
48b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var kPauseLabelPadding = 5;       // Padding for pause time labels.
49b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var kNumPauseLabels = 7;          // Number of biggest pauses to label.
50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var kCodeKindLabelPadding = 100;  // Padding for code kind labels.
51b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
52b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var kTickHalfDuration = 0.5;      // Duration of half a tick in ms.
53b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var kMinRangeLength = 0.0005;     // Minimum length for an event in ms.
54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var kNumThreads = 2;              // Number of threads.
56b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var kExecutionThreadId = 0;       // ID of main thread.
57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Init values.
59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var num_timer_event = kY1Offset + 0.5;
60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Data structures.
62b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  function TimerEvent(label, color, pause, thread_id) {
63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    assert(thread_id >= 0 && thread_id < kNumThreads, "invalid thread id");
64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    this.label = label;
65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    this.color = color;
66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    this.pause = pause;
67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    this.ranges = [];
68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    this.thread_id = thread_id;
69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    this.index = ++num_timer_event;
70b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
71b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
72b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  function CodeKind(color, kinds) {
73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    this.color = color;
74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    this.in_execution = [];
75b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    this.stack_frames = [];
76b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (var i = 0; i < kStackFrames; i++) this.stack_frames.push([]);
77b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    this.kinds = kinds;
78b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
79b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
80b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  function Range(start, end) {
81b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    this.start = start;  // In milliseconds.
82b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    this.end = end;      // In milliseconds.
83b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
84b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
85b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  function Deopt(time, size) {
86b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    this.time = time;  // In milliseconds.
87b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    this.size = size;  // In bytes.
88b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
89b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
90b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Range.prototype.duration = function() { return this.end - this.start; }
91b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
92b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  function Tick(tick) {
93b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    this.tick = tick;
94b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
95b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
96b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var TimerEvents = {
97b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'V8.Execute':
98b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        new TimerEvent("execution", "#000000", false, 0),
99b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'V8.External':
100b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        new TimerEvent("external", "#3399FF", false, 0),
101b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'V8.CompileFullCode':
102b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        new TimerEvent("compile unopt", "#CC0000",  true, 0),
103b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'V8.RecompileSynchronous':
104b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        new TimerEvent("recompile sync", "#CC0044",  true, 0),
105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'V8.RecompileConcurrent':
106b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        new TimerEvent("recompile async", "#CC4499", false, 1),
107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'V8.CompileEval':
108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        new TimerEvent("compile eval", "#CC4400",  true, 0),
109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'V8.IcMiss':
110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        new TimerEvent("ic miss", "#CC9900", false, 0),
111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'V8.Parse':
112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        new TimerEvent("parse", "#00CC00",  true, 0),
113b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'V8.PreParse':
114b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        new TimerEvent("preparse", "#44CC00",  true, 0),
115b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'V8.ParseLazy':
116b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        new TimerEvent("lazy parse", "#00CC44",  true, 0),
117b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'V8.GCScavenger':
118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        new TimerEvent("gc scavenge", "#0044CC",  true, 0),
119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'V8.GCCompactor':
120b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        new TimerEvent("gc compaction", "#4444CC",  true, 0),
121b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'V8.GCContext':
122b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        new TimerEvent("gc context", "#4400CC",  true, 0),
123b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  };
124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var CodeKinds = {
126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'external ': new CodeKind("#3399FF", [-2]),
127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'runtime  ': new CodeKind("#000000", [-1]),
128b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'full code': new CodeKind("#DD0000", [0]),
129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'opt code ': new CodeKind("#00EE00", [1]),
130b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'code stub': new CodeKind("#FF00FF", [2]),
131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'built-in ': new CodeKind("#AA00AA", [3]),
132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'inl.cache': new CodeKind("#4444AA",
133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]),
134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'reg.exp. ': new CodeKind("#0000FF", [15]),
135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  };
136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var code_map = new CodeMap();
138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var execution_pauses = [];
139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var deopts = [];
140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var gettime = [];
141b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var event_stack = [];
142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var last_time_stamp = [];
143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (var i = 0; i < kNumThreads; i++) {
144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    event_stack[i] = [];
145b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    last_time_stamp[i] = -1;
146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var range_start = undefined;
149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var range_end = undefined;
150b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var obj_index = 0;
151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var pause_tolerance = 0.005;  // Milliseconds.
152b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var distortion = 0;
153b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
154b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Utility functions.
155b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  function assert(something, message) {
156b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (!something) {
157b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var error = new Error(message);
158b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      error_output(error.stack);
159b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
160b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
161b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
162b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  function FindCodeKind(kind) {
163b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (name in CodeKinds) {
164b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if (CodeKinds[name].kinds.indexOf(kind) >= 0) {
165b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        return CodeKinds[name];
166b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
167b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
168b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
169b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
170b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  function TicksToRanges(ticks) {
171b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var ranges = [];
172b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (var i = 0; i < ticks.length; i++) {
173b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var tick = ticks[i].tick;
174b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      ranges.push(
175b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          new Range(tick - kTickHalfDuration, tick + kTickHalfDuration));
176b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
177b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return ranges;
178b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
179b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
180b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  function MergeRanges(ranges) {
181b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    ranges.sort(function(a, b) { return a.start - b.start; });
182b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var result = [];
183b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var j = 0;
184b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (var i = 0; i < ranges.length; i = j) {
185b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var merge_start = ranges[i].start;
186b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if (merge_start > range_end) break;  // Out of plot range.
187b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var merge_end = ranges[i].end;
188b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      for (j = i + 1; j < ranges.length; j++) {
189b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        var next_range = ranges[j];
190b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        // Don't merge ranges if there is no overlap (incl. merge tolerance).
191b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if (next_range.start > merge_end + pause_tolerance) break;
192b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        // Merge ranges.
193b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if (next_range.end > merge_end) {  // Extend range end.
194b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          merge_end = next_range.end;
195b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
196b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
197b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if (merge_end < range_start) continue;  // Out of plot range.
198b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if (merge_end < merge_start) continue;  // Not an actual range.
199b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      result.push(new Range(merge_start, merge_end));
200b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
201b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return result;
202b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
203b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
204b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  function RestrictRangesTo(ranges, start, end) {
205b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var result = [];
206b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (var i = 0; i < ranges.length; i++) {
207b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if (ranges[i].start <= end && ranges[i].end >= start) {
208b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        result.push(new Range(Math.max(ranges[i].start, start),
209b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                              Math.min(ranges[i].end, end)));
210b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
211b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
212b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return result;
213b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
214b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
215b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Public methods.
216b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  this.collectData = function(input, distortion_per_entry) {
217b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
218b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var last_timestamp = 0;
219b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
220b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Parse functions.
221b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var parseTimeStamp = function(timestamp) {
222b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      int_timestamp = parseInt(timestamp);
223b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      assert(int_timestamp >= last_timestamp, "Inconsistent timestamps.");
224b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      last_timestamp = int_timestamp;
225b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      distortion += distortion_per_entry;
226b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return int_timestamp / 1000 - distortion;
227b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
228b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
229b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var processTimerEventStart = function(name, start) {
230b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // Find out the thread id.
231b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var new_event = TimerEvents[name];
232b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if (new_event === undefined) return;
233b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var thread_id = new_event.thread_id;
234b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
235b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      start = Math.max(last_time_stamp[thread_id] + kMinRangeLength, start);
236b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
237b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // Last event on this thread is done with the start of this event.
238b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var last_event = event_stack[thread_id].top();
239b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if (last_event !== undefined) {
240b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        var new_range = new Range(last_time_stamp[thread_id], start);
241b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        last_event.ranges.push(new_range);
242b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
243b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      event_stack[thread_id].push(new_event);
244b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      last_time_stamp[thread_id] = start;
245b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    };
246b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var processTimerEventEnd = function(name, end) {
248b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // Find out about the thread_id.
249b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var finished_event = TimerEvents[name];
250b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var thread_id = finished_event.thread_id;
251b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      assert(finished_event === event_stack[thread_id].pop(),
252b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch             "inconsistent event stack");
253b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
254b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      end = Math.max(last_time_stamp[thread_id] + kMinRangeLength, end);
255b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
256b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var new_range = new Range(last_time_stamp[thread_id], end);
257b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      finished_event.ranges.push(new_range);
258b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      last_time_stamp[thread_id] = end;
259b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    };
260b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
261b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var processCodeCreateEvent = function(type, kind, address, size, name) {
262b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var code_entry = new CodeMap.CodeEntry(size, name);
263b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      code_entry.kind = kind;
264b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      code_map.addCode(address, code_entry);
265b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    };
266b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
267b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var processCodeMoveEvent = function(from, to) {
268b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      code_map.moveCode(from, to);
269b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    };
270b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
271b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var processCodeDeleteEvent = function(address) {
272b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      code_map.deleteCode(address);
273b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    };
274b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
275b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var processCodeDeoptEvent = function(time, size) {
276b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      deopts.push(new Deopt(time, size));
277b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
278b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
279b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var processCurrentTimeEvent = function(time) {
280b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      gettime.push(time);
281b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
282b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
283b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var processSharedLibrary = function(name, start, end) {
284b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var code_entry = new CodeMap.CodeEntry(end - start, name);
285b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      code_entry.kind = -3;  // External code kind.
286b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      for (var i = 0; i < kV8BinarySuffixes.length; i++) {
287b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        var suffix = kV8BinarySuffixes[i];
288b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if (name.indexOf(suffix, name.length - suffix.length) >= 0) {
289b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          code_entry.kind = -1;  // V8 runtime code kind.
290b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          break;
291b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
292b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
293b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      code_map.addLibrary(start, code_entry);
294b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    };
295b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
296b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var processTickEvent = function(
297b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        pc, timer, unused_x, unused_y, vmstate, stack) {
298b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var tick = new Tick(timer);
299b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
300b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var entry = code_map.findEntry(pc);
301b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if (entry) FindCodeKind(entry.kind).in_execution.push(tick);
302b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
303b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      for (var i = 0; i < kStackFrames; i++) {
304b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if (!stack[i]) break;
305b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        var entry = code_map.findEntry(stack[i]);
306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if (entry) FindCodeKind(entry.kind).stack_frames[i].push(tick);
307b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    };
309b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Collect data from log.
310b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var logreader = new LogReader(
311b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      { 'timer-event-start': { parsers: [null, parseTimeStamp],
312b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                               processor: processTimerEventStart },
313b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        'timer-event-end':   { parsers: [null, parseTimeStamp],
314b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                               processor: processTimerEventEnd },
315b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        'shared-library': { parsers: [null, parseInt, parseInt],
316b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                            processor: processSharedLibrary },
317b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        'code-creation':  { parsers: [null, parseInt, parseInt, parseInt, null],
318b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                            processor: processCodeCreateEvent },
319b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        'code-move':      { parsers: [parseInt, parseInt],
320b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                            processor: processCodeMoveEvent },
321b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        'code-delete':    { parsers: [parseInt],
322b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                            processor: processCodeDeleteEvent },
323b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        'code-deopt':     { parsers: [parseTimeStamp, parseInt],
324b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                            processor: processCodeDeoptEvent },
325b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        'current-time':   { parsers: [parseTimeStamp],
326b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                            processor: processCurrentTimeEvent },
327b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        'tick':           { parsers: [parseInt, parseTimeStamp,
328b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                      null, null, parseInt, 'var-args'],
329b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                            processor: processTickEvent }
330b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      });
331b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
332b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var line;
333b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    while (line = input()) {
334b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      logreader.processLogLine(line);
335b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
336b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
337b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Collect execution pauses.
338b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (name in TimerEvents) {
339b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var event = TimerEvents[name];
340b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if (!event.pause) continue;
341b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var ranges = event.ranges;
342b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      for (var j = 0; j < ranges.length; j++) execution_pauses.push(ranges[j]);
343b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
344b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    execution_pauses = MergeRanges(execution_pauses);
345b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  };
346b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
347b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
348b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  this.findPlotRange = function(
349b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    range_start_override, range_end_override, result_callback) {
350b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var start_found = (range_start_override || range_start_override == 0);
351b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var end_found = (range_end_override || range_end_override == 0);
352b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    range_start = start_found ? range_start_override : Infinity;
353b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    range_end = end_found ? range_end_override : -Infinity;
354b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
355b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (!start_found || !end_found) {
356b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      for (name in TimerEvents) {
357b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        var ranges = TimerEvents[name].ranges;
358b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        for (var i = 0; i < ranges.length; i++) {
359b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          if (ranges[i].start < range_start && !start_found) {
360b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            range_start = ranges[i].start;
361b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          }
362b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          if (ranges[i].end > range_end && !end_found) {
363b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            range_end = ranges[i].end;
364b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          }
365b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
366b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
367b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
368b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      for (codekind in CodeKinds) {
369b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        var ticks = CodeKinds[codekind].in_execution;
370b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        for (var i = 0; i < ticks.length; i++) {
371b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          if (ticks[i].tick < range_start && !start_found) {
372b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            range_start = ticks[i].tick;
373b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          }
374b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          if (ticks[i].tick > range_end && !end_found) {
375b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            range_end = ticks[i].tick;
376b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          }
377b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
378b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
379b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
380b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Set pause tolerance to something appropriate for the plot resolution
381b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // to make it easier for gnuplot.
382b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    pause_tolerance = (range_end - range_start) / kResX / 10;
383b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
384b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (typeof result_callback === 'function') {
385b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      result_callback(range_start, range_end);
386b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
387b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  };
388b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
389b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
390b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  this.assembleOutput = function(output) {
391b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    output("set yrange [0:" + (num_timer_event + 1) + "]");
392b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    output("set xlabel \"execution time in ms\"");
393b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    output("set xrange [" + range_start + ":" + range_end + "]");
394b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    output("set style fill pattern 2 bo 1");
395b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    output("set style rect fs solid 1 noborder");
396b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    output("set style line 1 lt 1 lw 1 lc rgb \"#000000\"");
397b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    output("set border 15 lw 0.2");  // Draw thin border box.
398b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    output("set style line 2 lt 1 lw 1 lc rgb \"#9944CC\"");
399b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    output("set xtics out nomirror");
400b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    output("unset key");
401b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
402b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    function DrawBarBase(color, start, end, top, bottom, transparency) {
403b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      obj_index++;
404b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      command = "set object " + obj_index + " rect";
405b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      command += " from " + start + ", " + top;
406b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      command += " to " + end + ", " + bottom;
407b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      command += " fc rgb \"" + color + "\"";
408b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if (transparency) {
409b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        command += " fs transparent solid " + transparency;
410b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
411b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      output(command);
412b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
413b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
414b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    function DrawBar(row, color, start, end, width) {
415b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      DrawBarBase(color, start, end, row + width, row - width);
416b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
417b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
418b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    function DrawHalfBar(row, color, start, end, width) {
419b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      DrawBarBase(color, start, end, row, row - width);
420b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
421b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
422b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var percentages = {};
423b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var total = 0;
424b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (var name in TimerEvents) {
425b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var event = TimerEvents[name];
426b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var ranges = RestrictRangesTo(event.ranges, range_start, range_end);
427b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var sum =
428b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        ranges.map(function(range) { return range.duration(); })
429b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            .reduce(function(a, b) { return a + b; }, 0);
430b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      percentages[name] = (sum / (range_end - range_start) * 100).toFixed(1);
431b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
432b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
433b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Plot deopts.
434b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    deopts.sort(function(a, b) { return b.size - a.size; });
435b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var max_deopt_size = deopts.length > 0 ? deopts[0].size : Infinity;
436b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
437b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (var i = 0; i < deopts.length; i++) {
438b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var deopt = deopts[i];
439b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      DrawHalfBar(kDeoptRow, "#9944CC", deopt.time,
440b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                  deopt.time + 10 * pause_tolerance,
441b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                  deopt.size / max_deopt_size * kMaxDeoptLength);
442b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
443b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
444b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Plot current time polls.
445b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (gettime.length > 1) {
446b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var start = gettime[0];
447b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var end = gettime.pop();
448b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      DrawBarBase("#0000BB", start, end, kGetTimeHeight, 0, 0.2);
449b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
450b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
451b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Name Y-axis.
452b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var ytics = [];
453b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (name in TimerEvents) {
454b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var index = TimerEvents[name].index;
455b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var label = TimerEvents[name].label;
456b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      ytics.push('"' + label + ' (' + percentages[name] + '%%)" ' + index);
457b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
458b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    ytics.push('"code kind color coding" ' + kY1Offset);
459b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    ytics.push('"code kind in execution" ' + (kY1Offset - 1));
460b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    ytics.push('"top ' + kStackFrames + ' js stack frames"' + ' ' +
461b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch               (kY1Offset - 2));
462b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    ytics.push('"pause times" 0');
463b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    ytics.push('"max deopt size: ' + (max_deopt_size / 1024).toFixed(1) +
464b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch               ' kB" ' + kDeoptRow);
465b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    output("set ytics out nomirror (" + ytics.join(', ') + ")");
466b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
467b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Plot timeline.
468b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (var name in TimerEvents) {
469b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var event = TimerEvents[name];
470b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var ranges = MergeRanges(event.ranges);
471b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      for (var i = 0; i < ranges.length; i++) {
472b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        DrawBar(event.index, event.color,
473b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                ranges[i].start, ranges[i].end,
474b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                kTimerEventWidth);
475b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
476b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
477b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
478b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Plot code kind gathered from ticks.
479b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (var name in CodeKinds) {
480b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var code_kind = CodeKinds[name];
481b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var offset = kY1Offset - 1;
482b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // Top most frame.
483b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var row = MergeRanges(TicksToRanges(code_kind.in_execution));
484b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      for (var j = 0; j < row.length; j++) {
485b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        DrawBar(offset, code_kind.color,
486b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                row[j].start, row[j].end, kExecutionFrameWidth);
487b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
488b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      offset = offset - 2 * kExecutionFrameWidth - kGapWidth;
489b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // Javascript frames.
490b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      for (var i = 0; i < kStackFrames; i++) {
491b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        offset = offset - 2 * kStackFrameWidth - kGapWidth;
492b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        row = MergeRanges(TicksToRanges(code_kind.stack_frames[i]));
493b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        for (var j = 0; j < row.length; j++) {
494b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          DrawBar(offset, code_kind.color,
495b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                  row[j].start, row[j].end, kStackFrameWidth);
496b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
497b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
498b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
499b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
500b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Add labels as legend for code kind colors.
501b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var padding = kCodeKindLabelPadding * (range_end - range_start) / kResX;
502b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var label_x = range_start;
503b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var label_y = kY1Offset;
504b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (var name in CodeKinds) {
505b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      label_x += padding;
506b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      output("set label \"" + name + "\" at " + label_x + "," + label_y +
507b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch             " textcolor rgb \"" + CodeKinds[name].color + "\"" +
508b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch             " font \"Helvetica,9'\"");
509b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      obj_index++;
510b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
511b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
512b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (execution_pauses.length == 0) {
513b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // Force plot and return without plotting execution pause impulses.
514b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      output("plot 1/0");
515b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return;
516b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
517b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
518b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Label the longest pauses.
519b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    execution_pauses =
520b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        RestrictRangesTo(execution_pauses, range_start, range_end);
521b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    execution_pauses.sort(
522b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        function(a, b) { return b.duration() - a.duration(); });
523b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
524b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var max_pause_time = execution_pauses.length > 0
525b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        ? execution_pauses[0].duration() : 0;
526b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    padding = kPauseLabelPadding * (range_end - range_start) / kResX;
527b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var y_scale = kY1Offset / max_pause_time / 2;
528b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (var i = 0; i < execution_pauses.length && i < kNumPauseLabels; i++) {
529b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var pause = execution_pauses[i];
530b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var label_content = (pause.duration() | 0) + " ms";
531b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var label_x = pause.end + padding;
532b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var label_y = Math.max(1, (pause.duration() * y_scale));
533b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      output("set label \"" + label_content + "\" at " +
534b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch             label_x + "," + label_y + " font \"Helvetica,7'\"");
535b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      obj_index++;
536b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
537b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
538b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Scale second Y-axis appropriately.
539b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var y2range = max_pause_time * num_timer_event / kY1Offset * 2;
540b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    output("set y2range [0:" + y2range + "]");
541b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Plot graph with impulses as data set.
542b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    output("plot '-' using 1:2 axes x1y2 with impulses ls 1");
543b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (var i = 0; i < execution_pauses.length; i++) {
544b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var pause = execution_pauses[i];
545b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      output(pause.end + " " + pause.duration());
546b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      obj_index++;
547b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
548b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    output("e");
549b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return obj_index;
550b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  };
551b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
552