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 |