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