• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<html>
2<!--
3Copyright 2016 the V8 project authors. All rights reserved.  Use of this source
4code is governed by a BSD-style license that can be found in the LICENSE file.
5-->
6
7<head>
8  <style>
9    .entry-details {}
10
11    .entry-details TD {}
12
13    .details {
14      width: 2em;
15      border: 1px black dotted;
16    }
17
18    .count {
19      text-align: right;
20      width: 5em;
21      font-family: monospace;
22    }
23
24    .percentage {
25      text-align: right;
26      width: 5em;
27      font-family: monospace;
28    }
29
30    .key {
31      padding-left: 1em;
32    }
33
34    .drilldown-group-title {
35      font-weight: bold;
36      padding: 0.5em 0 0.2em 0;
37    }
38  </style>
39  <script>
40    "use strict"
41    var entries = [];
42
43    var properties = ['type', 'category', 'file', 'filePosition', 'state',
44      'key', 'isNative', 'map', 'propertiesMode', 'numberOfOwnProperties',
45      'instanceType'
46    ]
47
48    class Entry {
49      constructor(id, line) {
50        this.id = id;
51        this.line = line;
52        var parts = line.split(" ");
53        if (parts.length < 6) return
54        this.isValid = false;
55        if (parts[0][0] !== "[") return;
56        if (parts[1] === "patching") return;
57        this.type = parts[0].substr(1);
58        this.category = "unknown";
59        this.map = "unknown";
60        this.propertiesMode = "unknown";
61        this.numberOfOwnProperties = 0;
62        this.instanceType = "unknown";
63        if (this.type.indexOf("Store") !== -1) {
64          this.category = "Store";
65        } else if (this.type.indexOf("Load") !== -1) {
66          this.category = "Load";
67        }
68        if (this.type.length == 0) return;
69        if (this.type.indexOf('BinaryOpIC(') === 0) {
70          this.type = "BinaryOpIC";
71          var split = parts[0].split('(');
72          this.state = "(" + split[1] + " => " + parts[2];
73          var offset = this.parsePositionAndFile(parts, 6);
74          if (offset == -1) return
75          if (this.file === undefined) return
76          this.file = this.file.slice(0, -1);
77        } else {
78          var offset = this.parsePositionAndFile(parts, 2);
79          if (offset == -1) return
80          this.state = parts[++offset];
81          var mapPart = parts[offset + 1];
82          if (mapPart !== undefined && mapPart.startsWith("map=")) {
83            if (mapPart[4] == "(") {
84              if (mapPart.endsWith(")")) {
85                this.map = mapPart.substr(5, mapPart.length-6);
86              } else {
87                this.map = mapPart.substr(5);
88              }
89              offset++;
90              offset = this.parseMapProperties(parts, offset);
91            } else {
92              this.map = mapPart.substr(4);
93              offset++;
94            }
95            if (this.map == "(nil)") this.map = "unknown";
96          }
97          if (this.type !== "CompareIC") {
98            // if there is no address we have a smi key
99            var address = parts[++offset];
100            if (address !== undefined && address.indexOf("0x") === 0) {
101              this.key = parts.slice(++offset).join(" ");
102            } else {
103              this.key = address;
104            }
105          }
106        }
107        this.filePosition = this.file + " " + this.position;
108        if (this.key) {
109          var isStringKey = false
110          if (this.key.indexOf("<String[") === 0) {
111            isStringKey = true;
112            this.key = "\"" + this.key.slice(this.key.indexOf(']') + 3);
113          } else if (this.key.indexOf("<") === 0) {
114            this.key = this.key.slice(1);
115          }
116          if (this.key.endsWith(">]")) {
117            this.key = this.key.slice(0, -2);
118          } else if (this.key.endsWith("]")) {
119            this.key = this.key.slice(0, -1);
120          }
121          if (isStringKey) {
122            this.key = this.key + "\"";
123          }
124        }
125        this.isValid = true;
126      }
127
128      parseMapProperties(parts, offset) {
129        var next = parts[++offset];
130        if (!next.startsWith('dict')) return offset;
131        this.propertiesMode =
132            next.substr(5) == "0" ? "fast" : "slow";
133        this.numberOfOwnProperties  = parts[++offset].substr(4);
134        next = parts[++offset];
135        this.instanceType = next.substr(5, next.length-6);
136        return offset;
137      }
138
139      parsePositionAndFile(parts, start) {
140        // find the position of 'at' in the parts array.
141        var offset = start;
142        for (var i = start + 1; i < parts.length; i++) {
143          offset++;
144          if (parts[i] == 'at') break;
145        }
146        if (parts[offset] !== 'at') return -1;
147        this.position = parts.slice(start, offset).join(' ');
148        offset += 1;
149        this.isNative = parts[offset] == "native"
150        offset += this.isNative ? 1 : 0;
151        this.file = parts[offset];
152        return offset;
153      }
154    }
155
156    function loadFile() {
157      var files = document.getElementById("uploadInput").files;
158
159      var file = files[0];
160      var reader = new FileReader();
161
162      reader.onload = function(evt) {
163        entries = [];
164        var end = this.result.length;
165        var current = 0;
166        var next = 0;
167        var line;
168        var i = 0;
169        var entry;
170        while (current < end) {
171          next = this.result.indexOf("\n", current);
172          if (next === -1) break;
173          i++;
174          line = this.result.substring(current, next);
175          current = next + 1;
176          entry = new Entry(i, line);
177          if (entry.isValid) entries.push(entry);
178        }
179
180        document.getElementById("count").innerHTML = i;
181        updateTable();
182      }
183      reader.readAsText(file);
184      initGroupKeySelect();
185    }
186
187
188    class Group {
189      constructor(property, key, entry) {
190        this.property = property;
191        this.key = key;
192        this.count = 1;
193        this.entries = [entry];
194        this.percentage = undefined;
195        this.groups = undefined;
196      }
197
198      add(entry) {
199        this.count++;
200        this.entries.push(entry)
201      }
202
203      createSubGroups() {
204        this.groups = {};
205        for (var i = 0; i < properties.length; i++) {
206          var subProperty = properties[i];
207          if (this.property == subProperty) continue;
208          this.groups[subProperty] = groupBy(this.entries, subProperty);
209        }
210      }
211    }
212
213    function groupBy(entries, property) {
214      var accumulator = {};
215      accumulator.__proto__ = null;
216      var length = entries.length;
217      for (var i = 0; i < length; i++) {
218        var entry = entries[i];
219        var key = entry[property];
220        if (accumulator[key] == undefined) {
221          accumulator[key] = new Group(property, key, entry)
222        } else {
223          var group = accumulator[key];
224          if (group.entries == undefined) console.log([group, entry]);
225          group.add(entry)
226        }
227      }
228      var result = []
229      for (var key in accumulator) {
230        var group = accumulator[key];
231        group.percentage = Math.round(group.count / length * 100 * 100) / 100;
232        result.push(group);
233      }
234      result.sort((a, b) => {
235        return b.count - a.count
236      });
237      return result;
238    }
239
240
241
242    function escapeHtml(unsafe) {
243      if (!unsafe) return "";
244      return unsafe.toString()
245           .replace(/&/g, "&amp;")
246           .replace(/</g, "&lt;")
247           .replace(/>/g, "&gt;")
248           .replace(/"/g, "&quot;")
249           .replace(/'/g, "&#039;");
250    }
251
252    function updateTable() {
253      var select = document.getElementById("group-key");
254      var key = select.options[select.selectedIndex].text;
255      console.log(key);
256      var tableBody = document.getElementById("table-body");
257      removeAllChildren(tableBody);
258      var groups = groupBy(entries, key, true);
259      display(groups, tableBody);
260    }
261
262    function selecedOption(node) {
263      return node.options[node.selectedIndex]
264    }
265
266    function removeAllChildren(node) {
267      while (node.firstChild) {
268        node.removeChild(node.firstChild);
269      }
270    }
271
272    function display(entries, parent) {
273      var fragment = document.createDocumentFragment();
274
275      function td(tr, content, className) {
276        var td = document.createElement("td");
277        td.innerHTML = content;
278        td.className = className
279        tr.appendChild(td);
280        return td
281      }
282      var max = Math.min(1000, entries.length)
283      for (var i = 0; i < max; i++) {
284        var entry = entries[i];
285        var tr = document.createElement("tr");
286        tr.entry = entry;
287        td(tr, '<span onclick="toggleDetails(this)">details</a>', 'details');
288        td(tr, entry.percentage + "%", 'percentage');
289        td(tr, entry.count, 'count');
290        td(tr, escapeHtml(entry.key), 'key');
291        fragment.appendChild(tr);
292      }
293      var omitted = entries.length - max;
294      if (omitted > 0) {
295        var tr = document.createElement("tr");
296        var td = td(tr, 'Omitted ' + omitted + " entries.");
297        td.colSpan = 4;
298        fragment.appendChild(tr);
299      }
300      parent.appendChild(fragment);
301    }
302
303    function displayDrilldown(entry, previousSibling) {
304      var tr = document.createElement('tr');
305      tr.className = "entry-details";
306      tr.style.display = "none";
307      // indent by one td.
308      tr.appendChild(document.createElement("td"));
309      var td = document.createElement("td");
310      td.colSpan = 3;
311      for (var key in entry.groups) {
312        td.appendChild(displayDrilldownGroup(entry, key));
313      }
314      tr.appendChild(td);
315      // Append the new TR after previousSibling.
316      previousSibling.parentNode.insertBefore(tr, previousSibling.nextSibling)
317    }
318
319    function displayDrilldownGroup(entry, key) {
320      var max = 20;
321      var group = entry.groups[key];
322      var div = document.createElement("div")
323      div.className = 'drilldown-group-title'
324      div.innerHTML = key + ' [top ' + max + ' out of ' + group.length + ']';
325      var table = document.createElement("table");
326      display(group.slice(0, max), table, false)
327      div.appendChild(table);
328      return div;
329    }
330
331    function toggleDetails(node) {
332      var tr = node.parentNode.parentNode;
333      var entry = tr.entry;
334
335      // Create subgroup in-place if the don't exist yet.
336      if (entry.groups === undefined) {
337        entry.createSubGroups();
338        displayDrilldown(entry, tr);
339      }
340      var details = tr.nextSibling;
341      var display = details.style.display;
342      if (display != "none") {
343        display = "none";
344      } else {
345        display = "table-row"
346      };
347      details.style.display = display;
348    }
349
350    function initGroupKeySelect() {
351      var select = document.getElementById("group-key");
352      for (var i in properties) {
353        var option = document.createElement("option");
354        option.text = properties[i];
355        select.add(option);
356      }
357    }
358
359    function handleOnLoad() {
360      document.querySelector("#uploadInput").focus();
361    }
362  </script>
363</head>
364
365<body onload="handleOnLoad()">
366  <h1>
367      <span style="color: #00FF00">I</span>
368      <span style="color: #FF00FF">C</span>
369      <span style="color: #00FFFF">E</span>
370    </h1> Your IC-Explorer.
371
372  <div id="legend" style="padding-right: 200px">
373    <div style="float:right;  border-style: solid; border-width: 1px; padding:20px">
374    0 uninitialized<br>
375    . premonomorphic<br>
376    1 monomorphic<br>
377    ^ recompute handler<br>
378    P polymorphic<br>
379    N megamorphic<br>
380    G generic
381    </div>
382  </div>
383
384  <h2>Usage</h2> Run your script with <code>--trace_ic</code> and upload on this page:<br/>
385  <code>/path/to/d8 --trace_ic your_script.js > trace.txt</code>
386  <h2>Data</h2>
387  <form name="fileForm">
388    <p>
389      <input id="uploadInput" type="file" name="files" onchange="loadFile();"> trace
390      entries: <span id="count">0</span>
391    </p>
392  </form>
393  <h2>Result</h2>
394  <p>
395    Group-Key:
396    <select id="group-key" onchange="updateTable()"></select>
397  </p>
398  <p>
399    <table id="table" width="100%">
400      <tbody id="table-body">
401      </tbody>
402    </table>
403  </p>
404</body>
405
406</html>
407