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