v8/tools/ic-explorer.html
thestig df0eaff48d Fix static initializer in ic.cc
This was added in commit 40611, but the std::cout calls are gone so the
header is no longer needed.

Remove trailing spaces in html files rom the same commit and from other
html files in the same directory.

Review-Url: https://codereview.chromium.org/2797253009
Cr-Commit-Position: refs/heads/master@{#44535}
2017-04-10 17:45:35 +00:00

407 lines
12 KiB
HTML

<html>
<!--
Copyright 2016 the V8 project authors. All rights reserved. Use of this source
code is governed by a BSD-style license that can be found in the LICENSE file.
-->
<head>
<style>
.entry-details {}
.entry-details TD {}
.details {
width: 2em;
border: 1px black dotted;
}
.count {
text-align: right;
width: 5em;
font-family: monospace;
}
.percentage {
text-align: right;
width: 5em;
font-family: monospace;
}
.key {
padding-left: 1em;
}
.drilldown-group-title {
font-weight: bold;
padding: 0.5em 0 0.2em 0;
}
</style>
<script>
"use strict"
var entries = [];
var properties = ['type', 'category', 'file', 'filePosition', 'state',
'key', 'isNative', 'map', 'propertiesMode', 'numberOfOwnProperties',
'instanceType'
]
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;
this.type = parts[0].substr(1);
this.category = "unknown";
this.map = "unknown";
this.propertiesMode = "unknown";
this.numberOfOwnProperties = 0;
this.instanceType = "unknown";
if (this.type.indexOf("Store") !== -1) {
this.category = "Store";
} else if (this.type.indexOf("Load") !== -1) {
this.category = "Load";
}
if (this.type.length == 0) return;
if (this.type.indexOf('BinaryOpIC(') === 0) {
this.type = "BinaryOpIC";
var split = parts[0].split('(');
this.state = "(" + split[1] + " => " + parts[2];
var offset = this.parsePositionAndFile(parts, 6);
if (offset == -1) return
if (this.file === undefined) return
this.file = this.file.slice(0, -1);
} else {
var offset = this.parsePositionAndFile(parts, 2);
if (offset == -1) return
this.state = parts[++offset];
var mapPart = parts[offset + 1];
if (mapPart !== undefined && mapPart.startsWith("map=")) {
if (mapPart[4] == "(") {
if (mapPart.endsWith(")")) {
this.map = mapPart.substr(5, mapPart.length-6);
} else {
this.map = mapPart.substr(5);
}
offset++;
offset = this.parseMapProperties(parts, offset);
} else {
this.map = mapPart.substr(4);
offset++;
}
if (this.map == "(nil)") this.map = "unknown";
}
if (this.type !== "CompareIC") {
// if there is no address we have a smi key
var address = parts[++offset];
if (address !== undefined && address.indexOf("0x") === 0) {
this.key = parts.slice(++offset).join(" ");
} else {
this.key = address;
}
}
}
this.filePosition = this.file + " " + this.position;
if (this.key) {
var isStringKey = false
if (this.key.indexOf("<String[") === 0) {
isStringKey = true;
this.key = "\"" + this.key.slice(this.key.indexOf(']') + 3);
} else if (this.key.indexOf("<") === 0) {
this.key = this.key.slice(1);
}
if (this.key.endsWith(">]")) {
this.key = this.key.slice(0, -2);
} else if (this.key.endsWith("]")) {
this.key = this.key.slice(0, -1);
}
if (isStringKey) {
this.key = this.key + "\"";
}
}
this.isValid = true;
}
parseMapProperties(parts, offset) {
var next = parts[++offset];
if (!next.startsWith('dict')) return offset;
this.propertiesMode =
next.substr(5) == "0" ? "fast" : "slow";
this.numberOfOwnProperties = parts[++offset].substr(4);
next = parts[++offset];
this.instanceType = next.substr(5, next.length-6);
return offset;
}
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 loadFile() {
var files = document.getElementById("uploadInput").files;
var file = files[0];
var reader = new FileReader();
reader.onload = function(evt) {
entries = [];
var end = this.result.length;
var current = 0;
var next = 0;
var line;
var i = 0;
var entry;
while (current < end) {
next = this.result.indexOf("\n", current);
if (next === -1) break;
i++;
line = this.result.substring(current, next);
current = next + 1;
entry = new Entry(i, line);
if (entry.isValid) entries.push(entry);
}
document.getElementById("count").innerHTML = i;
updateTable();
}
reader.readAsText(file);
initGroupKeySelect();
}
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;
for (var i = 0; i < length; i++) {
var entry = entries[i];
var key = entry[property];
if (accumulator[key] == undefined) {
accumulator[key] = new Group(property, key, entry)
} else {
var group = accumulator[key];
if (group.entries == undefined) console.log([group, entry]);
group.add(entry)
}
}
var result = []
for (var key in accumulator) {
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 escapeHtml(unsafe) {
if (!unsafe) return "";
return unsafe.toString()
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
function updateTable() {
var select = document.getElementById("group-key");
var key = select.options[select.selectedIndex].text;
console.log(key);
var tableBody = document.getElementById("table-body");
removeAllChildren(tableBody);
var groups = groupBy(entries, key, true);
display(groups, tableBody);
}
function selecedOption(node) {
return node.options[node.selectedIndex]
}
function removeAllChildren(node) {
while (node.firstChild) {
node.removeChild(node.firstChild);
}
}
function display(entries, parent) {
var fragment = document.createDocumentFragment();
function td(tr, content, className) {
var td = document.createElement("td");
td.innerHTML = content;
td.className = className
tr.appendChild(td);
return td
}
var max = Math.min(1000, entries.length)
for (var i = 0; i < max; i++) {
var entry = entries[i];
var tr = document.createElement("tr");
tr.entry = entry;
td(tr, '<span onclick="toggleDetails(this)">details</a>', 'details');
td(tr, entry.percentage + "%", 'percentage');
td(tr, entry.count, 'count');
td(tr, escapeHtml(entry.key), 'key');
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 + ' out of ' + group.length + ']';
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 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";
} else {
display = "table-row"
};
details.style.display = display;
}
function initGroupKeySelect() {
var select = document.getElementById("group-key");
for (var i in properties) {
var option = document.createElement("option");
option.text = properties[i];
select.add(option);
}
}
function handleOnLoad() {
document.querySelector("#uploadInput").focus();
}
</script>
</head>
<body onload="handleOnLoad()">
<h1>
<span style="color: #00FF00">I</span>
<span style="color: #FF00FF">C</span>
<span style="color: #00FFFF">E</span>
</h1> Your IC-Explorer.
<div id="legend" style="padding-right: 200px">
<div style="float:right; border-style: solid; border-width: 1px; padding:20px">
0 uninitialized<br>
. premonomorphic<br>
1 monomorphic<br>
^ recompute handler<br>
P polymorphic<br>
N megamorphic<br>
G generic
</div>
</div>
<h2>Usage</h2> Run your script with <code>--trace_ic</code> and upload on this page:<br/>
<code>/path/to/d8 --trace_ic your_script.js > trace.txt</code>
<h2>Data</h2>
<form name="fileForm">
<p>
<input id="uploadInput" type="file" name="files" onchange="loadFile();"> trace
entries: <span id="count">0</span>
</p>
</form>
<h2>Result</h2>
<p>
Group-Key:
<select id="group-key" onchange="updateTable()"></select>
</p>
<p>
<table id="table" width="100%">
<tbody id="table-body">
</tbody>
</table>
</p>
</body>
</html>