<html> <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; } </style> <script> "use strict" var entries = []; class Entry { constructor(id, line) { this.id = id; var parts = line.split(" "); this.isValid = false; if (parts[0][0] !== "[") return; if (parts[1] === "patching") return; this.type = parts[0].substr(1); this.category = "Other"; 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"; 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]; 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]; if (this.type !== "CompareIC") { // if there is no address we have a smi key var address = parts[6 + offset]; if (address !== undefined && address.indexOf("0x") === 0) { this.key = parts.slice(7 + 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) { 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 + "\""; } } } } function updateSize() { 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(); } var properties = ['type', 'category', 'file', 'filePosition', 'state' , 'key', 'isNative'] function groupBy(entries, property, subGroup) { 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] = { key: key, count: 1, entries: [ entry ]}; } else { var record = accumulator[key]; if (record.entries == undefined) console.log([record, entry]); record.count ++; record.entries.push(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); } 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); } } 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); display(groupBy(entries, key, true), tableBody, true); } function selecedOption(node) { return node.options[node.selectedIndex] } function removeAllChildren(node) { while (node.firstChild) { node.removeChild(node.firstChild); } } function display(entries, parent, showDetails) { if (showDetails) { console.log(entries) } var fragment = document.createDocumentFragment(); function td(tr, content, className) { var td = document.createElement("td"); td.innerHTML = content; td.className = className tr.appendChild(td); return tr } 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 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'); } 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); } } parent.appendChild(fragment); } function toggleDetails(node) { var tr = node.parentNode.parentNode; var id = 'details-'+tr.dataset.id; var details = document.getElementById(id); 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); } } </script> </head> <body> <h1> <span style="color: #00FF00">I</span> <span style="color: #FF00FF">C</span> <span style="color: #00FFFF">E</span> </h1> Your IC-Explorer. <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="updateSize();" > 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>