Index: tools/ic-explorer.html |
diff --git a/tools/ICE.html b/tools/ic-explorer.html |
similarity index 60% |
rename from tools/ICE.html |
rename to tools/ic-explorer.html |
index a060a4e3eb98403d14808a24cf274b4e16238b71..43b486a50cdd33a407cdc70af3e83ab0025b14a3 100644 |
--- a/tools/ICE.html |
+++ b/tools/ic-explorer.html |
@@ -22,6 +22,10 @@ |
.key { |
padding-left: 1em; |
} |
+ .drilldown-group-title { |
+ font-weight: bold; |
+ padding: 0.5em 0 0.2em 0; |
+ } |
</style> |
<script> |
"use strict" |
@@ -30,7 +34,9 @@ var entries = []; |
class Entry { |
constructor(id, line) { |
this.id = id; |
+ this.line = line; |
var parts = line.split(" "); |
+ if (parts.length < 6) return |
this.isValid = false; |
if (parts[0][0] !== "[") return; |
if (parts[1] === "patching") return; |
@@ -44,32 +50,27 @@ class Entry { |
if (this.type.length == 0) return; |
if (this.type.indexOf('BinaryOpIC(') === 0) { |
this.type = "BinaryOpIC"; |
- this.isNative = parts[8] == "native" |
- var offset = this.isNative ? 1 : 0; |
var split = parts[0].split('('); |
this.state = "(" + split[1] + " => " + parts[2]; |
- this.position = parts[6]; |
- this.file = parts[8 + offset]; |
+ var offset = this.parsePositionAndFile(parts, 6); |
+ if (offset == -1) return |
+ if (this.file === undefined) return |
this.file = this.file.slice(0,-1); |
- |
} else { |
- this.position = parts[2]; |
- this.isNative = parts[4] == "native" |
- var offset = this.isNative ? 1 : 0; |
- this.file = parts[4 + offset]; |
- this.state = parts[5 + offset]; |
+ var offset = this.parsePositionAndFile(parts, 2); |
+ if (offset == -1) return |
+ this.state = parts[++offset]; |
if (this.type !== "CompareIC") { |
// if there is no address we have a smi key |
- var address = parts[6 + offset]; |
+ var address = parts[++offset]; |
if (address !== undefined && address.indexOf("0x") === 0) { |
- this.key = parts.slice(7 + offset).join(" "); |
+ this.key = parts.slice(++offset).join(" "); |
} else { |
this.key = address; |
} |
} |
} |
this.filePosition = this.file + " " + this.position; |
- this.isValid = true; |
if (this.key) { |
var isStringKey = false |
if (this.key.indexOf("<String[") === 0) { |
@@ -87,10 +88,27 @@ class Entry { |
this.key = this.key + "\""; |
} |
} |
+ this.isValid = true; |
+ } |
+ |
+ parsePositionAndFile(parts, start) { |
+ // find the position of 'at' in the parts array. |
+ var offset = start; |
+ for (var i = start+1; i<parts.length; i++) { |
+ offset++; |
+ if (parts[i] == 'at') break; |
+ } |
+ if (parts[offset] !== 'at') return -1; |
+ this.position = parts.slice(start, offset).join(' '); |
+ offset += 1; |
+ this.isNative = parts[offset] == "native" |
+ offset += this.isNative ? 1 : 0; |
+ this.file = parts[offset]; |
+ return offset; |
} |
} |
-function updateSize() { |
+function loadFile() { |
var files = document.getElementById("uploadInput").files; |
var file = files[0]; |
@@ -126,7 +144,32 @@ function updateSize() { |
var properties = ['type', 'category', 'file', 'filePosition', 'state' , 'key', 'isNative'] |
-function groupBy(entries, property, subGroup) { |
+class Group { |
+ constructor(property, key, entry) { |
+ this.property = property; |
+ this.key = key; |
+ this.count = 1; |
+ this.entries = [entry]; |
+ this.percentage = undefined; |
+ this.groups = undefined; |
+ } |
+ |
+ add(entry) { |
+ this.count ++; |
+ this.entries.push(entry) |
+ } |
+ |
+ createSubGroups() { |
+ this.groups = {}; |
+ for (var i=0; i<properties.length; i++) { |
+ var subProperty = properties[i]; |
+ if (this.property == subProperty) continue; |
+ this.groups[subProperty] = groupBy(this.entries, subProperty); |
+ } |
+ } |
+} |
+ |
+function groupBy(entries, property) { |
var accumulator = {}; |
accumulator.__proto__ = null; |
var length = entries.length; |
@@ -134,33 +177,23 @@ function groupBy(entries, property, subGroup) { |
var entry = entries[i]; |
var key = entry[property]; |
if (accumulator[key] == undefined) { |
- accumulator[key] = { key: key, count: 1, entries: [ entry ]}; |
+ accumulator[key] = new Group(property, key, entry) |
} else { |
- var record = accumulator[key]; |
- if (record.entries == undefined) console.log([record, entry]); |
- record.count ++; |
- record.entries.push(entry) |
+ var group = accumulator[key]; |
+ if (group.entries == undefined) console.log([group, entry]); |
+ group.add(entry) |
} |
} |
var result = [] |
for (var key in accumulator) { |
- var record = accumulator[key]; |
- record.percentage = Math.round(record.count / length * 100 * 100) / 100; |
- if (subGroup) subGroupBy(record, property); |
- result.push(record); |
+ var group = accumulator[key]; |
+ group.percentage = Math.round(group.count / length * 100 * 100) / 100; |
+ result.push(group); |
} |
result.sort((a,b) => { return b.count - a.count }); |
return result; |
} |
-function subGroupBy(record, originalProperty) { |
- record.groups = {}; |
- for (var i=0; i<properties.length; i++) { |
- var property = properties[i]; |
- if (property == originalProperty) continue; |
- record.groups[property] = groupBy(record.entries, property, false); |
- } |
-} |
@@ -170,7 +203,8 @@ function updateTable() { |
console.log(key); |
var tableBody = document.getElementById("table-body"); |
removeAllChildren(tableBody); |
- display(groupBy(entries, key, true), tableBody, true); |
+ var groups = groupBy(entries, key, true); |
+ display(groups, tableBody); |
} |
function selecedOption(node) { |
@@ -183,10 +217,7 @@ function removeAllChildren(node) { |
} |
} |
-function display(entries, parent, showDetails) { |
- if (showDetails) { |
- console.log(entries) |
- } |
+function display(entries, parent) { |
var fragment = document.createDocumentFragment(); |
function td(tr, content, className) { |
@@ -194,60 +225,67 @@ function display(entries, parent, showDetails) { |
td.innerHTML = content; |
td.className = className |
tr.appendChild(td); |
- return tr |
+ return td |
} |
- |
- function drillDown(entry, tr) { |
- tr.id = "details-" + i; |
- tr.className = "entry-details"; |
- tr.style.display = "none"; |
- |
- tr.appendChild(document.createElement("td")); |
- |
- var td = document.createElement("td"); |
- td.colSpan = 3; |
- for (var key in entry.groups) { |
- td.appendChild(drillDownGroup(entry, key)); |
- } |
- tr.appendChild(td); |
- } |
- |
- function drillDownGroup(entry, key) { |
- var group = entry.groups[key]; |
- var div = document.createElement("div") |
- div.innerHTML = key; |
- var table = document.createElement("table"); |
- display(group.slice(0, 20), table, false) |
- div.appendChild(table); |
- return div; |
- } |
- |
- for (var i = 0; i<entries.length; i++) { |
+ var max = Math.min(1000, entries.length) |
+ for (var i = 0; i<max; i++) { |
var entry = entries[i]; |
var tr = document.createElement("tr"); |
- tr.id = "row-" + i; |
- tr.dataset.id = i; |
- if (showDetails) { |
- td(tr, '<span onclick="toggleDetails(this)">details</a>', 'details'); |
- } |
+ tr.entry = entry; |
+ td(tr, '<span onclick="toggleDetails(this)">details</a>', 'details'); |
td(tr, entry.percentage +"%", 'percentage'); |
td(tr, entry.count, 'count'); |
td(tr, entry.key, 'key'); |
fragment.appendChild(tr); |
- |
- if (showDetails) { |
- tr = document.createElement("tr"); |
- drillDown(entry, tr); |
- fragment.appendChild(tr); |
- } |
+ } |
+ var omitted = entries.length - max; |
+ if (omitted > 0) { |
+ var tr = document.createElement("tr"); |
+ var td = td(tr, 'Omitted ' + omitted + " entries."); |
+ td.colSpan = 4; |
+ fragment.appendChild(tr); |
} |
parent.appendChild(fragment); |
} |
+function displayDrilldown(entry, previousSibling) { |
+ var tr = document.createElement('tr'); |
+ tr.className = "entry-details"; |
+ tr.style.display = "none"; |
+ // indent by one td. |
+ tr.appendChild(document.createElement("td")); |
+ var td = document.createElement("td"); |
+ td.colSpan = 3; |
+ for (var key in entry.groups) { |
+ td.appendChild(displayDrilldownGroup(entry, key)); |
+ } |
+ tr.appendChild(td); |
+ // Append the new TR after previousSibling. |
+ previousSibling.parentNode.insertBefore(tr, previousSibling.nextSibling) |
+} |
+ |
+function displayDrilldownGroup(entry, key) { |
+ var max = 20; |
+ var group = entry.groups[key]; |
+ var div = document.createElement("div") |
+ div.className = 'drilldown-group-title' |
+ div.innerHTML = key + ' [top ' + max + ']'; |
+ var table = document.createElement("table"); |
+ display(group.slice(0, max), table, false) |
+ div.appendChild(table); |
+ return div; |
+} |
+ |
function toggleDetails(node) { |
var tr = node.parentNode.parentNode; |
- var id = 'details-'+tr.dataset.id; |
- var details = document.getElementById(id); |
+ var entry = tr.entry; |
+ |
+ // Create subgroup in-place if the don't exist yet. |
+ if (entry.groups === undefined) { |
+ entry.createSubGroups(); |
+ displayDrilldown(entry, tr); |
+ } |
+ var details = tr.nextSibling; |
var display = details.style.display; |
if (display != "none") { |
display = "none"; |
@@ -281,7 +319,7 @@ function initGroupKeySelect() { |
<h2>Data</h2> |
<form name="fileForm"> |
<p> |
- <input id="uploadInput" type="file" name="files" onchange="updateSize();" > |
+ <input id="uploadInput" type="file" name="files" onchange="loadFile();" > |
trace entries: <span id="count">0</span> |
</p> |
</form> |