OLD | NEW |
(Empty) | |
| 1 <html> |
| 2 <head> |
| 3 <style> |
| 4 .entry-details { |
| 5 } |
| 6 .entry-details TD { |
| 7 } |
| 8 .details { |
| 9 width: 2em; |
| 10 border: 1px black dotted; |
| 11 } |
| 12 .count { |
| 13 text-align: right; |
| 14 width: 5em; |
| 15 font-family: monospace; |
| 16 } |
| 17 .percentage { |
| 18 text-align: right; |
| 19 width: 5em; |
| 20 font-family: monospace; |
| 21 } |
| 22 .key { |
| 23 padding-left: 1em; |
| 24 } |
| 25 </style> |
| 26 <script> |
| 27 "use strict" |
| 28 var entries = []; |
| 29 |
| 30 class Entry { |
| 31 constructor(id, line) { |
| 32 this.id = id; |
| 33 var parts = line.split(" "); |
| 34 this.isValid = false; |
| 35 if (parts[0][0] !== "[") return; |
| 36 if (parts[1] === "patching") return; |
| 37 this.type = parts[0].substr(1); |
| 38 this.category = "Other"; |
| 39 if (this.type.indexOf("Store") !== -1) { |
| 40 this.category = "Store"; |
| 41 } else if (this.type.indexOf("Load") !== -1) { |
| 42 this.category = "Load"; |
| 43 } |
| 44 if (this.type.length == 0) return; |
| 45 if (this.type.indexOf('BinaryOpIC(') === 0) { |
| 46 this.type = "BinaryOpIC"; |
| 47 this.isNative = parts[8] == "native" |
| 48 var offset = this.isNative ? 1 : 0; |
| 49 var split = parts[0].split('('); |
| 50 this.state = "(" + split[1] + " => " + parts[2]; |
| 51 this.position = parts[6]; |
| 52 this.file = parts[8 + offset]; |
| 53 this.file = this.file.slice(0,-1); |
| 54 |
| 55 } else { |
| 56 this.position = parts[2]; |
| 57 this.isNative = parts[4] == "native" |
| 58 var offset = this.isNative ? 1 : 0; |
| 59 this.file = parts[4 + offset]; |
| 60 this.state = parts[5 + offset]; |
| 61 if (this.type !== "CompareIC") { |
| 62 // if there is no address we have a smi key |
| 63 var address = parts[6 + offset]; |
| 64 if (address !== undefined && address.indexOf("0x") === 0) { |
| 65 this.key = parts.slice(7 + offset).join(" "); |
| 66 } else { |
| 67 this.key = address; |
| 68 } |
| 69 } |
| 70 } |
| 71 this.filePosition = this.file + " " + this.position; |
| 72 this.isValid = true; |
| 73 if (this.key) { |
| 74 var isStringKey = false |
| 75 if (this.key.indexOf("<String[") === 0) { |
| 76 isStringKey = true; |
| 77 this.key = "\"" + this.key.slice(this.key.indexOf(']')+3); |
| 78 } else if (this.key.indexOf("<") === 0) { |
| 79 this.key = this.key.slice(1); |
| 80 } |
| 81 if (this.key.endsWith(">]")) { |
| 82 this.key = this.key.slice(0, -2); |
| 83 } else if (this.key.endsWith("]")) { |
| 84 this.key = this.key.slice(0, -1); |
| 85 } |
| 86 if (isStringKey) { |
| 87 this.key = this.key + "\""; |
| 88 } |
| 89 } |
| 90 } |
| 91 } |
| 92 |
| 93 function updateSize() { |
| 94 var files = document.getElementById("uploadInput").files; |
| 95 |
| 96 var file = files[0]; |
| 97 var reader = new FileReader(); |
| 98 |
| 99 reader.onload = function(evt) { |
| 100 entries = []; |
| 101 var end = this.result.length; |
| 102 var current = 0; |
| 103 var next = 0; |
| 104 var line; |
| 105 var i = 0; |
| 106 var entry; |
| 107 while (current < end) { |
| 108 next = this.result.indexOf("\n", current); |
| 109 if (next === -1) break; |
| 110 i++; |
| 111 |
| 112 line = this.result.substring(current, next); |
| 113 current = next+1; |
| 114 entry = new Entry(i, line); |
| 115 if (entry.isValid) entries.push(entry); |
| 116 } |
| 117 |
| 118 document.getElementById("count").innerHTML = i; |
| 119 updateTable(); |
| 120 } |
| 121 reader.readAsText(file); |
| 122 initGroupKeySelect(); |
| 123 } |
| 124 |
| 125 |
| 126 |
| 127 var properties = ['type', 'category', 'file', 'filePosition', 'state' , 'key', '
isNative'] |
| 128 |
| 129 function groupBy(entries, property, subGroup) { |
| 130 var accumulator = {}; |
| 131 accumulator.__proto__ = null; |
| 132 var length = entries.length; |
| 133 for (var i = 0; i < length; i++) { |
| 134 var entry = entries[i]; |
| 135 var key = entry[property]; |
| 136 if (accumulator[key] == undefined) { |
| 137 accumulator[key] = { key: key, count: 1, entries: [ entry ]}; |
| 138 } else { |
| 139 var record = accumulator[key]; |
| 140 if (record.entries == undefined) console.log([record, entry]); |
| 141 record.count ++; |
| 142 record.entries.push(entry) |
| 143 } |
| 144 } |
| 145 var result = [] |
| 146 for (var key in accumulator) { |
| 147 var record = accumulator[key]; |
| 148 record.percentage = Math.round(record.count / length * 100 * 100) / 100; |
| 149 if (subGroup) subGroupBy(record, property); |
| 150 result.push(record); |
| 151 } |
| 152 result.sort((a,b) => { return b.count - a.count }); |
| 153 return result; |
| 154 } |
| 155 |
| 156 function subGroupBy(record, originalProperty) { |
| 157 record.groups = {}; |
| 158 for (var i=0; i<properties.length; i++) { |
| 159 var property = properties[i]; |
| 160 if (property == originalProperty) continue; |
| 161 record.groups[property] = groupBy(record.entries, property, false); |
| 162 } |
| 163 } |
| 164 |
| 165 |
| 166 |
| 167 function updateTable() { |
| 168 var select = document.getElementById("group-key"); |
| 169 var key = select.options[select.selectedIndex].text; |
| 170 console.log(key); |
| 171 var tableBody = document.getElementById("table-body"); |
| 172 removeAllChildren(tableBody); |
| 173 display(groupBy(entries, key, true), tableBody, true); |
| 174 } |
| 175 |
| 176 function selecedOption(node) { |
| 177 return node.options[node.selectedIndex] |
| 178 } |
| 179 |
| 180 function removeAllChildren(node) { |
| 181 while (node.firstChild) { |
| 182 node.removeChild(node.firstChild); |
| 183 } |
| 184 } |
| 185 |
| 186 function display(entries, parent, showDetails) { |
| 187 if (showDetails) { |
| 188 console.log(entries) |
| 189 } |
| 190 var fragment = document.createDocumentFragment(); |
| 191 |
| 192 function td(tr, content, className) { |
| 193 var td = document.createElement("td"); |
| 194 td.innerHTML = content; |
| 195 td.className = className |
| 196 tr.appendChild(td); |
| 197 return tr |
| 198 } |
| 199 |
| 200 function drillDown(entry, tr) { |
| 201 tr.id = "details-" + i; |
| 202 tr.className = "entry-details"; |
| 203 tr.style.display = "none"; |
| 204 |
| 205 tr.appendChild(document.createElement("td")); |
| 206 |
| 207 var td = document.createElement("td"); |
| 208 td.colSpan = 3; |
| 209 for (var key in entry.groups) { |
| 210 td.appendChild(drillDownGroup(entry, key)); |
| 211 } |
| 212 tr.appendChild(td); |
| 213 } |
| 214 |
| 215 function drillDownGroup(entry, key) { |
| 216 var group = entry.groups[key]; |
| 217 var div = document.createElement("div") |
| 218 div.innerHTML = key; |
| 219 var table = document.createElement("table"); |
| 220 display(group.slice(0, 20), table, false) |
| 221 div.appendChild(table); |
| 222 return div; |
| 223 } |
| 224 |
| 225 for (var i = 0; i<entries.length; i++) { |
| 226 var entry = entries[i]; |
| 227 var tr = document.createElement("tr"); |
| 228 tr.id = "row-" + i; |
| 229 tr.dataset.id = i; |
| 230 if (showDetails) { |
| 231 td(tr, '<span onclick="toggleDetails(this)">details</a>', 'details'); |
| 232 } |
| 233 td(tr, entry.percentage +"%", 'percentage'); |
| 234 td(tr, entry.count, 'count'); |
| 235 td(tr, entry.key, 'key'); |
| 236 fragment.appendChild(tr); |
| 237 |
| 238 if (showDetails) { |
| 239 tr = document.createElement("tr"); |
| 240 drillDown(entry, tr); |
| 241 fragment.appendChild(tr); |
| 242 } |
| 243 } |
| 244 parent.appendChild(fragment); |
| 245 } |
| 246 |
| 247 function toggleDetails(node) { |
| 248 var tr = node.parentNode.parentNode; |
| 249 var id = 'details-'+tr.dataset.id; |
| 250 var details = document.getElementById(id); |
| 251 var display = details.style.display; |
| 252 if (display != "none") { |
| 253 display = "none"; |
| 254 }else { |
| 255 display = "table-row" |
| 256 }; |
| 257 details.style.display = display; |
| 258 } |
| 259 |
| 260 function initGroupKeySelect() { |
| 261 var select = document.getElementById("group-key"); |
| 262 for (var i in properties) { |
| 263 var option = document.createElement("option"); |
| 264 option.text = properties[i]; |
| 265 select.add(option); |
| 266 } |
| 267 } |
| 268 |
| 269 </script> |
| 270 </head> |
| 271 <body> |
| 272 <h1> |
| 273 <span style="color: #00FF00">I</span> |
| 274 <span style="color: #FF00FF">C</span> |
| 275 <span style="color: #00FFFF">E</span> |
| 276 </h1> |
| 277 Your IC-Explorer. |
| 278 <h2>Usage</h2> |
| 279 Run your script with <code>--trace_ic</code> and upload on this page:<br/> |
| 280 <code>/path/to/d8 --trace_ic your_script.js > trace.txt</code> |
| 281 <h2>Data</h2> |
| 282 <form name="fileForm"> |
| 283 <p> |
| 284 <input id="uploadInput" type="file" name="files" onchange="updateSize();
" > |
| 285 trace entries: <span id="count">0</span> |
| 286 </p> |
| 287 </form> |
| 288 <h2>Result</h2> |
| 289 <p> |
| 290 Group-Key: |
| 291 <select id="group-key" onchange="updateTable()"></select> |
| 292 </p> |
| 293 <p> |
| 294 <table id="table" width="100%"> |
| 295 <tbody id="table-body"> |
| 296 </tbody> |
| 297 </table> |
| 298 </p> |
| 299 </body> |
| 300 </html> |
OLD | NEW |