df0eaff48d
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}
407 lines
12 KiB
HTML
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, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """)
|
|
.replace(/'/g, "'");
|
|
}
|
|
|
|
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>
|