Index: tools/ICE.html |
diff --git a/tools/ICE.html b/tools/ICE.html |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a060a4e3eb98403d14808a24cf274b4e16238b71 |
--- /dev/null |
+++ b/tools/ICE.html |
@@ -0,0 +1,300 @@ |
+<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> |