|
7 | 7 | <meta name="viewport" content="width=device-width">
|
8 | 8 | <title>Pyroscope</title>
|
9 | 9 | <link rel="stylesheet" href="build/styles.<%= webpack.hash %>.css">
|
| 10 | + <%= extra_metadata %> |
10 | 11 | <% if (mode == "development") { %>
|
11 | 12 | <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🔥</text><rect x='25' width='75' height='35' fill='white'/><text x='25' y='35' font-size='35' font-family='-apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif' font-weight='bold'>DEV</text></svg>">
|
12 | 13 | <% } else { %>
|
|
15 | 16 | </head>
|
16 | 17 | <body>
|
17 | 18 | <div id="root"></div>
|
18 |
| - <script> |
19 |
| - // TODO: dedup this |
20 |
| - |
21 |
| - var details, searchbtn, matchedtxt, svg; |
22 |
| - function init(evt) { |
23 |
| - if(document.getElementById("details")) { |
24 |
| - details = document.getElementById("details").firstChild; |
25 |
| - searchbtn = document.getElementById("search"); |
26 |
| - matchedtxt = document.getElementById("matched"); |
27 |
| - svg = document.getElementById("main-svg"); |
28 |
| - searching = 0; |
29 |
| - } |
30 |
| - } |
31 |
| - |
32 |
| - // mouse-over for info |
33 |
| - function s(node) { // show |
34 |
| - info = g_to_text(node); |
35 |
| - details.nodeValue = "Function: " + info; |
36 |
| - } |
37 |
| - function c() { // clear |
38 |
| - details.nodeValue = ' '; |
39 |
| - } |
40 |
| - |
41 |
| - // ctrl-F for search |
42 |
| - window.addEventListener("keydown",function (e) { |
43 |
| - if (e.keyCode === 114 || (e.ctrlKey && e.keyCode === 70)) { |
44 |
| - e.preventDefault(); |
45 |
| - search_prompt(); |
46 |
| - } |
47 |
| - }) |
48 |
| - |
49 |
| - // functions |
50 |
| - function find_child(parent, name, attr) { |
51 |
| - var children = parent.childNodes; |
52 |
| - for (var i=0; i<children.length;i++) { |
53 |
| - if (children[i].tagName == name) |
54 |
| - return (attr != undefined) ? children[i].attributes[attr].value : children[i]; |
55 |
| - } |
56 |
| - return; |
57 |
| - } |
58 |
| - function orig_save(e, attr, val) { |
59 |
| - if (e.attributes["_orig_"+attr] != undefined) return; |
60 |
| - if (e.attributes[attr] == undefined) return; |
61 |
| - if (val == undefined) val = e.attributes[attr].value; |
62 |
| - e.setAttribute("_orig_"+attr, val); |
63 |
| - } |
64 |
| - function orig_load(e, attr) { |
65 |
| - if (e.attributes["_orig_"+attr] == undefined) return; |
66 |
| - e.attributes[attr].value = e.attributes["_orig_"+attr].value; |
67 |
| - e.removeAttribute("_orig_"+attr); |
68 |
| - } |
69 |
| - function g_to_text(e) { |
70 |
| - var text = find_child(e, "title").firstChild.nodeValue; |
71 |
| - return (text) |
72 |
| - } |
73 |
| - function g_to_func(e) { |
74 |
| - var func = g_to_text(e); |
75 |
| - // if there's any manipulation we want to do to the function |
76 |
| - // name before it's searched, do it here before returning. |
77 |
| - return (func); |
78 |
| - } |
79 |
| - function update_text(e) { |
80 |
| - var r = find_child(e, "rect"); |
81 |
| - var t = find_child(e, "text"); |
82 |
| - var w = parseFloat(r.attributes["width"].value) -3; |
83 |
| - var txt = find_child(e, "title").textContent.replace(/\([^(]*\)$/,""); |
84 |
| - t.attributes["x"].value = parseFloat(r.attributes["x"].value) +3; |
85 |
| - |
86 |
| - // Smaller than this size won't fit anything |
87 |
| - if (w < 2*12*0.59) { |
88 |
| - t.textContent = ""; |
89 |
| - return; |
90 |
| - } |
91 |
| - |
92 |
| - t.textContent = txt; |
93 |
| - // Fit in full text width |
94 |
| - if (/^ *$/.test(txt) || t.getSubStringLength(0, txt.length) < w) |
95 |
| - return; |
96 |
| - |
97 |
| - for (var x=txt.length-2; x>0; x--) { |
98 |
| - if (t.getSubStringLength(0, x+2) <= w) { |
99 |
| - t.textContent = txt.substring(0,x) + ".."; |
100 |
| - return; |
101 |
| - } |
102 |
| - } |
103 |
| - t.textContent = ""; |
104 |
| - } |
105 |
| - |
106 |
| - // zoom |
107 |
| - function zoom_reset(e) { |
108 |
| - if (e.attributes != undefined) { |
109 |
| - orig_load(e, "x"); |
110 |
| - orig_load(e, "width"); |
111 |
| - } |
112 |
| - if (e.childNodes == undefined) return; |
113 |
| - for(var i=0, c=e.childNodes; i<c.length; i++) { |
114 |
| - zoom_reset(c[i]); |
115 |
| - } |
116 |
| - } |
117 |
| - function zoom_child(e, x, ratio) { |
118 |
| - if (e.attributes != undefined) { |
119 |
| - if (e.attributes["x"] != undefined) { |
120 |
| - orig_save(e, "x"); |
121 |
| - e.attributes["x"].value = (parseFloat(e.attributes["x"].value) - x - 10) * ratio + 10; |
122 |
| - if(e.tagName == "text") e.attributes["x"].value = find_child(e.parentNode, "rect", "x") + 3; |
123 |
| - } |
124 |
| - if (e.attributes["width"] != undefined) { |
125 |
| - orig_save(e, "width"); |
126 |
| - e.attributes["width"].value = parseFloat(e.attributes["width"].value) * ratio; |
127 |
| - } |
128 |
| - } |
129 |
| - |
130 |
| - if (e.childNodes == undefined) return; |
131 |
| - for(var i=0, c=e.childNodes; i<c.length; i++) { |
132 |
| - zoom_child(c[i], x-10, ratio); |
133 |
| - } |
134 |
| - } |
135 |
| - function zoom_parent(e) { |
136 |
| - if (e.attributes) { |
137 |
| - if (e.attributes["x"] != undefined) { |
138 |
| - orig_save(e, "x"); |
139 |
| - e.attributes["x"].value = 10; |
140 |
| - } |
141 |
| - if (e.attributes["width"] != undefined) { |
142 |
| - orig_save(e, "width"); |
143 |
| - e.attributes["width"].value = parseInt(svg.width.baseVal.value) - (10*2); |
144 |
| - } |
145 |
| - } |
146 |
| - if (e.childNodes == undefined) return; |
147 |
| - for(var i=0, c=e.childNodes; i<c.length; i++) { |
148 |
| - zoom_parent(c[i]); |
149 |
| - } |
150 |
| - } |
151 |
| - function zoom(node) { |
152 |
| - var attr = find_child(node, "rect").attributes; |
153 |
| - var width = parseFloat(attr["width"].value); |
154 |
| - var xmin = parseFloat(attr["x"].value); |
155 |
| - var xmax = parseFloat(xmin + width); |
156 |
| - var ymin = parseFloat(attr["y"].value); |
157 |
| - var ratio = (svg.width.baseVal.value - 2*10) / width; |
158 |
| - |
159 |
| - // XXX: Workaround for JavaScript float issues (fix me) |
160 |
| - var fudge = 0.0001; |
161 |
| - |
162 |
| - var unzoombtn = document.getElementById("unzoom"); |
163 |
| - unzoombtn.style["opacity"] = "1.0"; |
164 |
| - |
165 |
| - var el = document.getElementsByTagName("g"); |
166 |
| - for(var i=0;i<el.length;i++){ |
167 |
| - var e = el[i]; |
168 |
| - var a = find_child(e, "rect").attributes; |
169 |
| - var ex = parseFloat(a["x"].value); |
170 |
| - var ew = parseFloat(a["width"].value); |
171 |
| - // Is it an ancestor |
172 |
| - if (0 == 0) { |
173 |
| - var upstack = parseFloat(a["y"].value) > ymin; |
174 |
| - } else { |
175 |
| - var upstack = parseFloat(a["y"].value) < ymin; |
176 |
| - } |
177 |
| - if (upstack) { |
178 |
| - // Direct ancestor |
179 |
| - if (ex <= xmin && (ex+ew+fudge) >= xmax) { |
180 |
| - e.style["opacity"] = "0.5"; |
181 |
| - zoom_parent(e); |
182 |
| - e.onclick = function(e){unzoom(); zoom(this);}; |
183 |
| - update_text(e); |
184 |
| - } |
185 |
| - // not in current path |
186 |
| - else |
187 |
| - e.style["display"] = "none"; |
188 |
| - } |
189 |
| - // Children maybe |
190 |
| - else { |
191 |
| - // no common path |
192 |
| - if (ex < xmin || ex + fudge >= xmax) { |
193 |
| - e.style["display"] = "none"; |
194 |
| - } |
195 |
| - else { |
196 |
| - zoom_child(e, xmin, ratio); |
197 |
| - e.onclick = function(e){zoom(this);}; |
198 |
| - update_text(e); |
199 |
| - } |
200 |
| - } |
201 |
| - } |
202 |
| - } |
203 |
| - function unzoom() { |
204 |
| - var unzoombtn = document.getElementById("unzoom"); |
205 |
| - if(!unzoombtn){ |
206 |
| - return |
207 |
| - } |
208 |
| - unzoombtn.style["opacity"] = "0.0"; |
209 |
| - |
210 |
| - var el = document.getElementsByTagName("g"); |
211 |
| - for(i=0;i<el.length;i++) { |
212 |
| - el[i].style["display"] = "block"; |
213 |
| - el[i].style["opacity"] = "1"; |
214 |
| - zoom_reset(el[i]); |
215 |
| - update_text(el[i]); |
216 |
| - } |
217 |
| - } |
218 |
| - |
219 |
| - // search |
220 |
| - function reset_search() { |
221 |
| - var el = document.getElementsByTagName("rect"); |
222 |
| - for (var i=0; i < el.length; i++) { |
223 |
| - orig_load(el[i], "fill") |
224 |
| - } |
225 |
| - } |
226 |
| - function search_prompt() { |
227 |
| - if (!searching) { |
228 |
| - var term = prompt("Enter a search term (regexp " + |
229 |
| - "allowed, eg: ^ext4_)", ""); |
230 |
| - if (term != null) { |
231 |
| - search(term) |
232 |
| - } |
233 |
| - } else { |
234 |
| - reset_search(); |
235 |
| - searching = 0; |
236 |
| - searchbtn.style["opacity"] = "0.1"; |
237 |
| - searchbtn.firstChild.nodeValue = "Search" |
238 |
| - matchedtxt.style["opacity"] = "0.0"; |
239 |
| - matchedtxt.firstChild.nodeValue = "" |
240 |
| - } |
241 |
| - } |
242 |
| - function search(term) { |
243 |
| - var re = new RegExp(term); |
244 |
| - var el = document.getElementsByTagName("g"); |
245 |
| - var matches = new Object(); |
246 |
| - var maxwidth = 0; |
247 |
| - for (var i = 0; i < el.length; i++) { |
248 |
| - var e = el[i]; |
249 |
| - if (e.attributes["class"].value != "func_g") |
250 |
| - continue; |
251 |
| - var func = g_to_func(e); |
252 |
| - var rect = find_child(e, "rect"); |
253 |
| - if (rect == null) { |
254 |
| - // the rect might be wrapped in an anchor |
255 |
| - // if nameattr href is being used |
256 |
| - if (rect = find_child(e, "a")) { |
257 |
| - rect = find_child(r, "rect"); |
258 |
| - } |
259 |
| - } |
260 |
| - if (func == null || rect == null) |
261 |
| - continue; |
262 |
| - |
263 |
| - // Save max width. Only works as we have a root frame |
264 |
| - var w = parseFloat(rect.attributes["width"].value); |
265 |
| - if (w > maxwidth) |
266 |
| - maxwidth = w; |
267 |
| - |
268 |
| - if (func.match(re)) { |
269 |
| - // highlight |
270 |
| - var x = parseFloat(rect.attributes["x"].value); |
271 |
| - orig_save(rect, "fill"); |
272 |
| - rect.attributes["fill"].value = |
273 |
| - "rgb(230,0,230)"; |
274 |
| - |
275 |
| - // remember matches |
276 |
| - if (matches[x] == undefined) { |
277 |
| - matches[x] = w; |
278 |
| - } else { |
279 |
| - if (w > matches[x]) { |
280 |
| - // overwrite with parent |
281 |
| - matches[x] = w; |
282 |
| - } |
283 |
| - } |
284 |
| - searching = 1; |
285 |
| - } |
286 |
| - } |
287 |
| - if (!searching) |
288 |
| - return; |
289 |
| - |
290 |
| - searchbtn.style["opacity"] = "1.0"; |
291 |
| - searchbtn.firstChild.nodeValue = "Reset Search" |
292 |
| - |
293 |
| - // calculate percent matched, excluding vertical overlap |
294 |
| - var count = 0; |
295 |
| - var lastx = -1; |
296 |
| - var lastw = 0; |
297 |
| - var keys = Array(); |
298 |
| - for (k in matches) { |
299 |
| - if (matches.hasOwnProperty(k)) |
300 |
| - keys.push(k); |
301 |
| - } |
302 |
| - // sort the matched frames by their x location |
303 |
| - // ascending, then width descending |
304 |
| - keys.sort(function(a, b){ |
305 |
| - return a - b; |
306 |
| - }); |
307 |
| - // Step through frames saving only the biggest bottom-up frames |
308 |
| - // thanks to the sort order. This relies on the tree property |
309 |
| - // where children are always smaller than their parents. |
310 |
| - var fudge = 0.0001; // JavaScript floating point |
311 |
| - for (var k in keys) { |
312 |
| - var x = parseFloat(keys[k]); |
313 |
| - var w = matches[keys[k]]; |
314 |
| - if (x >= lastx + lastw - fudge) { |
315 |
| - count += w; |
316 |
| - lastx = x; |
317 |
| - lastw = w; |
318 |
| - } |
319 |
| - } |
320 |
| - // display matched percent |
321 |
| - matchedtxt.style["opacity"] = "1.0"; |
322 |
| - pct = 100 * count / maxwidth; |
323 |
| - if (pct == 100) |
324 |
| - pct = "100" |
325 |
| - else |
326 |
| - pct = pct.toFixed(1) |
327 |
| - matchedtxt.firstChild.nodeValue = "Matched: " + pct + "%"; |
328 |
| - } |
329 |
| - function searchover(e) { |
330 |
| - searchbtn.style["opacity"] = "1.0"; |
331 |
| - } |
332 |
| - function searchout(e) { |
333 |
| - if (searching) { |
334 |
| - searchbtn.style["opacity"] = "1.0"; |
335 |
| - } else { |
336 |
| - searchbtn.style["opacity"] = "0.1"; |
337 |
| - } |
338 |
| - } |
339 |
| - |
340 |
| - </script> |
341 | 19 | <script src="build/app.<%= webpack.hash %>.js" type="text/javascript"></script>
|
342 | 20 | </body>
|
343 | 21 | </html>
|
0 commit comments