1<?xml version="1.0" standalone="no"?> 2<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 3<svg version="1.1" width="1200" height="214" onload="init(evt)" viewBox="0 0 1200 214" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 4<!-- Flame graph stack visualization. See https://github.com/brendangregg/FlameGraph for latest version, and http://www.brendangregg.com/flamegraphs.html for examples. --> 5<!-- NOTES: --> 6<defs> 7 <linearGradient id="background" y1="0" y2="1" x1="0" x2="0" > 8 <stop stop-color="#eeeeee" offset="5%" /> 9 <stop stop-color="#eeeeb0" offset="95%" /> 10 </linearGradient> 11</defs> 12<style type="text/css"> 13 text { font-family:Verdana; font-size:12px; fill:rgb(0,0,0); } 14 #search, #ignorecase { opacity:0.1; cursor:pointer; } 15 #search:hover, #search.show, #ignorecase:hover, #ignorecase.show { opacity:1; } 16 #subtitle { text-anchor:middle; font-color:rgb(160,160,160); } 17 #title { text-anchor:middle; font-size:17px} 18 #unzoom { cursor:pointer; } 19 #frames > *:hover { stroke:black; stroke-width:0.5; cursor:pointer; } 20 .hide { display:none; } 21 .parent { opacity:0.5; } 22</style> 23<script type="text/ecmascript"> 24<![CDATA[ 25 "use strict"; 26 var details, searchbtn, unzoombtn, matchedtxt, svg, searching, currentSearchTerm, ignorecase, ignorecaseBtn; 27 function init(evt) { 28 details = document.getElementById("details").firstChild; 29 searchbtn = document.getElementById("search"); 30 ignorecaseBtn = document.getElementById("ignorecase"); 31 unzoombtn = document.getElementById("unzoom"); 32 matchedtxt = document.getElementById("matched"); 33 svg = document.getElementsByTagName("svg")[0]; 34 searching = 0; 35 currentSearchTerm = null; 36 37 // use GET parameters to restore a flamegraphs state. 38 var params = get_params(); 39 if (params.x && params.y) 40 zoom(find_group(document.querySelector('[x="' + params.x + '"][y="' + params.y + '"]'))); 41 if (params.s) search(params.s); 42 } 43 44 // event listeners 45 window.addEventListener("click", function(e) { 46 var target = find_group(e.target); 47 if (target) { 48 if (target.nodeName == "a") { 49 if (e.ctrlKey === false) return; 50 e.preventDefault(); 51 } 52 if (target.classList.contains("parent")) unzoom(true); 53 zoom(target); 54 if (!document.querySelector('.parent')) { 55 // we have basically done a clearzoom so clear the url 56 var params = get_params(); 57 if (params.x) delete params.x; 58 if (params.y) delete params.y; 59 history.replaceState(null, null, parse_params(params)); 60 unzoombtn.classList.add("hide"); 61 return; 62 } 63 64 // set parameters for zoom state 65 var el = target.querySelector("rect"); 66 if (el && el.attributes && el.attributes.y && el.attributes._orig_x) { 67 var params = get_params() 68 params.x = el.attributes._orig_x.value; 69 params.y = el.attributes.y.value; 70 history.replaceState(null, null, parse_params(params)); 71 } 72 } 73 else if (e.target.id == "unzoom") clearzoom(); 74 else if (e.target.id == "search") search_prompt(); 75 else if (e.target.id == "ignorecase") toggle_ignorecase(); 76 }, false) 77 78 // mouse-over for info 79 // show 80 window.addEventListener("mouseover", function(e) { 81 var target = find_group(e.target); 82 if (target) details.nodeValue = "Function: " + g_to_text(target); 83 }, false) 84 85 // clear 86 window.addEventListener("mouseout", function(e) { 87 var target = find_group(e.target); 88 if (target) details.nodeValue = ' '; 89 }, false) 90 91 // ctrl-F for search 92 // ctrl-I to toggle case-sensitive search 93 window.addEventListener("keydown",function (e) { 94 if (e.keyCode === 114 || (e.ctrlKey && e.keyCode === 70)) { 95 e.preventDefault(); 96 search_prompt(); 97 } 98 else if (e.ctrlKey && e.keyCode === 73) { 99 e.preventDefault(); 100 toggle_ignorecase(); 101 } 102 }, false) 103 104 // functions 105 function get_params() { 106 var params = {}; 107 var paramsarr = window.location.search.substr(1).split('&'); 108 for (var i = 0; i < paramsarr.length; ++i) { 109 var tmp = paramsarr[i].split("="); 110 if (!tmp[0] || !tmp[1]) continue; 111 params[tmp[0]] = decodeURIComponent(tmp[1]); 112 } 113 return params; 114 } 115 function parse_params(params) { 116 var uri = "?"; 117 for (var key in params) { 118 uri += key + '=' + encodeURIComponent(params[key]) + '&'; 119 } 120 if (uri.slice(-1) == "&") 121 uri = uri.substring(0, uri.length - 1); 122 if (uri == '?') 123 uri = window.location.href.split('?')[0]; 124 return uri; 125 } 126 function find_child(node, selector) { 127 var children = node.querySelectorAll(selector); 128 if (children.length) return children[0]; 129 } 130 function find_group(node) { 131 var parent = node.parentElement; 132 if (!parent) return; 133 if (parent.id == "frames") return node; 134 return find_group(parent); 135 } 136 function orig_save(e, attr, val) { 137 if (e.attributes["_orig_" + attr] != undefined) return; 138 if (e.attributes[attr] == undefined) return; 139 if (val == undefined) val = e.attributes[attr].value; 140 e.setAttribute("_orig_" + attr, val); 141 } 142 function orig_load(e, attr) { 143 if (e.attributes["_orig_"+attr] == undefined) return; 144 e.attributes[attr].value = e.attributes["_orig_" + attr].value; 145 e.removeAttribute("_orig_"+attr); 146 } 147 function g_to_text(e) { 148 var text = find_child(e, "title").firstChild.nodeValue; 149 return (text) 150 } 151 function g_to_func(e) { 152 var func = g_to_text(e); 153 // if there's any manipulation we want to do to the function 154 // name before it's searched, do it here before returning. 155 return (func); 156 } 157 function update_text(e) { 158 var r = find_child(e, "rect"); 159 var t = find_child(e, "text"); 160 var w = parseFloat(r.attributes.width.value) -3; 161 var txt = find_child(e, "title").textContent.replace(/\([^(]*\)$/,""); 162 t.attributes.x.value = parseFloat(r.attributes.x.value) + 3; 163 164 // Smaller than this size won't fit anything 165 if (w < 2 * 12 * 0.59) { 166 t.textContent = ""; 167 return; 168 } 169 170 t.textContent = txt; 171 var sl = t.getSubStringLength(0, txt.length); 172 // check if only whitespace or if we can fit the entire string into width w 173 if (/^ *$/.test(txt) || sl < w) 174 return; 175 176 // this isn't perfect, but gives a good starting point 177 // and avoids calling getSubStringLength too often 178 var start = Math.floor((w/sl) * txt.length); 179 for (var x = start; x > 0; x = x-2) { 180 if (t.getSubStringLength(0, x + 2) <= w) { 181 t.textContent = txt.substring(0, x) + ".."; 182 return; 183 } 184 } 185 t.textContent = ""; 186 } 187 188 // zoom 189 function zoom_reset(e) { 190 if (e.attributes != undefined) { 191 orig_load(e, "x"); 192 orig_load(e, "width"); 193 } 194 if (e.childNodes == undefined) return; 195 for (var i = 0, c = e.childNodes; i < c.length; i++) { 196 zoom_reset(c[i]); 197 } 198 } 199 function zoom_child(e, x, ratio) { 200 if (e.attributes != undefined) { 201 if (e.attributes.x != undefined) { 202 orig_save(e, "x"); 203 e.attributes.x.value = (parseFloat(e.attributes.x.value) - x - 10) * ratio + 10; 204 if (e.tagName == "text") 205 e.attributes.x.value = find_child(e.parentNode, "rect[x]").attributes.x.value + 3; 206 } 207 if (e.attributes.width != undefined) { 208 orig_save(e, "width"); 209 e.attributes.width.value = parseFloat(e.attributes.width.value) * ratio; 210 } 211 } 212 213 if (e.childNodes == undefined) return; 214 for (var i = 0, c = e.childNodes; i < c.length; i++) { 215 zoom_child(c[i], x - 10, ratio); 216 } 217 } 218 function zoom_parent(e) { 219 if (e.attributes) { 220 if (e.attributes.x != undefined) { 221 orig_save(e, "x"); 222 e.attributes.x.value = 10; 223 } 224 if (e.attributes.width != undefined) { 225 orig_save(e, "width"); 226 e.attributes.width.value = parseInt(svg.width.baseVal.value) - (10 * 2); 227 } 228 } 229 if (e.childNodes == undefined) return; 230 for (var i = 0, c = e.childNodes; i < c.length; i++) { 231 zoom_parent(c[i]); 232 } 233 } 234 function zoom(node) { 235 var attr = find_child(node, "rect").attributes; 236 var width = parseFloat(attr.width.value); 237 var xmin = parseFloat(attr.x.value); 238 var xmax = parseFloat(xmin + width); 239 var ymin = parseFloat(attr.y.value); 240 var ratio = (svg.width.baseVal.value - 2 * 10) / width; 241 242 // XXX: Workaround for JavaScript float issues (fix me) 243 var fudge = 0.0001; 244 245 unzoombtn.classList.remove("hide"); 246 247 var el = document.getElementById("frames").children; 248 for (var i = 0; i < el.length; i++) { 249 var e = el[i]; 250 var a = find_child(e, "rect").attributes; 251 var ex = parseFloat(a.x.value); 252 var ew = parseFloat(a.width.value); 253 var upstack; 254 // Is it an ancestor 255 if (0 == 0) { 256 upstack = parseFloat(a.y.value) > ymin; 257 } else { 258 upstack = parseFloat(a.y.value) < ymin; 259 } 260 if (upstack) { 261 // Direct ancestor 262 if (ex <= xmin && (ex+ew+fudge) >= xmax) { 263 e.classList.add("parent"); 264 zoom_parent(e); 265 update_text(e); 266 } 267 // not in current path 268 else 269 e.classList.add("hide"); 270 } 271 // Children maybe 272 else { 273 // no common path 274 if (ex < xmin || ex + fudge >= xmax) { 275 e.classList.add("hide"); 276 } 277 else { 278 zoom_child(e, xmin, ratio); 279 update_text(e); 280 } 281 } 282 } 283 search(); 284 } 285 function unzoom(dont_update_text) { 286 unzoombtn.classList.add("hide"); 287 var el = document.getElementById("frames").children; 288 for(var i = 0; i < el.length; i++) { 289 el[i].classList.remove("parent"); 290 el[i].classList.remove("hide"); 291 zoom_reset(el[i]); 292 if(!dont_update_text) update_text(el[i]); 293 } 294 search(); 295 } 296 function clearzoom() { 297 unzoom(); 298 299 // remove zoom state 300 var params = get_params(); 301 if (params.x) delete params.x; 302 if (params.y) delete params.y; 303 history.replaceState(null, null, parse_params(params)); 304 } 305 306 // search 307 function toggle_ignorecase() { 308 ignorecase = !ignorecase; 309 if (ignorecase) { 310 ignorecaseBtn.classList.add("show"); 311 } else { 312 ignorecaseBtn.classList.remove("show"); 313 } 314 reset_search(); 315 search(); 316 } 317 function reset_search() { 318 var el = document.querySelectorAll("#frames rect"); 319 for (var i = 0; i < el.length; i++) { 320 orig_load(el[i], "fill") 321 } 322 var params = get_params(); 323 delete params.s; 324 history.replaceState(null, null, parse_params(params)); 325 } 326 function search_prompt() { 327 if (!searching) { 328 var term = prompt("Enter a search term (regexp " + 329 "allowed, eg: ^ext4_)" 330 + (ignorecase ? ", ignoring case" : "") 331 + "\nPress Ctrl-i to toggle case sensitivity", ""); 332 if (term != null) search(term); 333 } else { 334 reset_search(); 335 searching = 0; 336 currentSearchTerm = null; 337 searchbtn.classList.remove("show"); 338 searchbtn.firstChild.nodeValue = "Search" 339 matchedtxt.classList.add("hide"); 340 matchedtxt.firstChild.nodeValue = "" 341 } 342 } 343 function search(term) { 344 if (term) currentSearchTerm = term; 345 346 var re = new RegExp(currentSearchTerm, ignorecase ? 'i' : ''); 347 var el = document.getElementById("frames").children; 348 var matches = new Object(); 349 var maxwidth = 0; 350 for (var i = 0; i < el.length; i++) { 351 var e = el[i]; 352 var func = g_to_func(e); 353 var rect = find_child(e, "rect"); 354 if (func == null || rect == null) 355 continue; 356 357 // Save max width. Only works as we have a root frame 358 var w = parseFloat(rect.attributes.width.value); 359 if (w > maxwidth) 360 maxwidth = w; 361 362 if (func.match(re)) { 363 // highlight 364 var x = parseFloat(rect.attributes.x.value); 365 orig_save(rect, "fill"); 366 rect.attributes.fill.value = "rgb(230,0,230)"; 367 368 // remember matches 369 if (matches[x] == undefined) { 370 matches[x] = w; 371 } else { 372 if (w > matches[x]) { 373 // overwrite with parent 374 matches[x] = w; 375 } 376 } 377 searching = 1; 378 } 379 } 380 if (!searching) 381 return; 382 var params = get_params(); 383 params.s = currentSearchTerm; 384 history.replaceState(null, null, parse_params(params)); 385 386 searchbtn.classList.add("show"); 387 searchbtn.firstChild.nodeValue = "Reset Search"; 388 389 // calculate percent matched, excluding vertical overlap 390 var count = 0; 391 var lastx = -1; 392 var lastw = 0; 393 var keys = Array(); 394 for (k in matches) { 395 if (matches.hasOwnProperty(k)) 396 keys.push(k); 397 } 398 // sort the matched frames by their x location 399 // ascending, then width descending 400 keys.sort(function(a, b){ 401 return a - b; 402 }); 403 // Step through frames saving only the biggest bottom-up frames 404 // thanks to the sort order. This relies on the tree property 405 // where children are always smaller than their parents. 406 var fudge = 0.0001; // JavaScript floating point 407 for (var k in keys) { 408 var x = parseFloat(keys[k]); 409 var w = matches[keys[k]]; 410 if (x >= lastx + lastw - fudge) { 411 count += w; 412 lastx = x; 413 lastw = w; 414 } 415 } 416 // display matched percent 417 matchedtxt.classList.remove("hide"); 418 var pct = 100 * count / maxwidth; 419 if (pct != 100) pct = pct.toFixed(1) 420 matchedtxt.firstChild.nodeValue = "Matched: " + pct + "%"; 421 } 422]]> 423</script> 424<rect x="0.0" y="0" width="1200.0" height="214.0" fill="url(#background)" /> 425<text id="title" x="600.00" y="24" >Flame Graph</text> 426<text id="details" x="10.00" y="197" > </text> 427<text id="unzoom" x="10.00" y="24" class="hide">Reset Zoom</text> 428<text id="search" x="1090.00" y="24" >Search</text> 429<text id="ignorecase" x="1174.00" y="24" >ic</text> 430<text id="matched" x="1090.00" y="197" > </text> 431<g id="frames"> 432<g > 433<title>z_impl_k_busy_wait (60 samples, 23.26%)</title><rect x="375.9" y="69" width="274.4" height="15.0" fill="rgb(239,158,37)" rx="2" ry="2" /> 434<text x="378.89" y="79.5" >z_impl_k_busy_wait</text> 435</g> 436<g > 437<title>sys_clock_cycle_get_32 (40 samples, 15.50%)</title><rect x="467.4" y="53" width="182.9" height="15.0" fill="rgb(225,96,23)" rx="2" ry="2" /> 438<text x="470.36" y="63.5" >sys_clock_cycle_get_32</text> 439</g> 440<g > 441<title>all (258 samples, 100%)</title><rect x="10.0" y="165" width="1180.0" height="15.0" fill="rgb(213,39,9)" rx="2" ry="2" /> 442<text x="13.00" y="175.5" ></text> 443</g> 444<g > 445<title>sys_clock_cycle_get_32 (20 samples, 7.75%)</title><rect x="284.4" y="53" width="91.5" height="15.0" fill="rgb(225,96,23)" rx="2" ry="2" /> 446<text x="287.42" y="63.5" >sys_clock_..</text> 447</g> 448<g > 449<title>sys_clock_cycle_get_32 (20 samples, 7.75%)</title><rect x="10.0" y="37" width="91.5" height="15.0" fill="rgb(225,96,23)" rx="2" ry="2" /> 450<text x="13.00" y="47.5" >sys_clock_..</text> 451</g> 452<g > 453<title>z_impl_k_busy_wait (78 samples, 30.23%)</title><rect x="650.3" y="69" width="356.8" height="15.0" fill="rgb(239,158,37)" rx="2" ry="2" /> 454<text x="653.31" y="79.5" >z_impl_k_busy_wait</text> 455</g> 456<g > 457<title>sys_clock_cycle_get_32 (40 samples, 15.50%)</title><rect x="101.5" y="37" width="182.9" height="15.0" fill="rgb(225,96,23)" rx="2" ry="2" /> 458<text x="104.47" y="47.5" >sys_clock_cycle_get_32</text> 459</g> 460<g > 461<title>z_impl_k_busy_wait (20 samples, 7.75%)</title><rect x="284.4" y="69" width="91.5" height="15.0" fill="rgb(239,158,37)" rx="2" ry="2" /> 462<text x="287.42" y="79.5" >z_impl_k_b..</text> 463</g> 464<g > 465<title>func_0 (80 samples, 31.01%)</title><rect x="10.0" y="85" width="365.9" height="15.0" fill="rgb(224,91,21)" rx="2" ry="2" /> 466<text x="13.00" y="95.5" >func_0</text> 467</g> 468<g > 469<title>sys_clock_cycle_get_32 (59 samples, 22.87%)</title><rect x="737.2" y="53" width="269.9" height="15.0" fill="rgb(225,96,23)" rx="2" ry="2" /> 470<text x="740.21" y="63.5" >sys_clock_cycle_get_32</text> 471</g> 472<g > 473<title>z_impl_k_busy_wait (40 samples, 15.50%)</title><rect x="101.5" y="53" width="182.9" height="15.0" fill="rgb(239,158,37)" rx="2" ry="2" /> 474<text x="104.47" y="63.5" >z_impl_k_busy_wait</text> 475</g> 476<g > 477<title>main (218 samples, 84.50%)</title><rect x="10.0" y="101" width="997.1" height="15.0" fill="rgb(243,179,42)" rx="2" ry="2" /> 478<text x="13.00" y="111.5" >main</text> 479</g> 480<g > 481<title>func_0_1 (40 samples, 15.50%)</title><rect x="101.5" y="69" width="182.9" height="15.0" fill="rgb(244,182,43)" rx="2" ry="2" /> 482<text x="104.47" y="79.5" >func_0_1</text> 483</g> 484<g > 485<title>idle (40 samples, 15.50%)</title><rect x="1007.1" y="117" width="182.9" height="15.0" fill="rgb(239,157,37)" rx="2" ry="2" /> 486<text x="1010.05" y="127.5" >idle</text> 487</g> 488<g > 489<title>func_1 (60 samples, 23.26%)</title><rect x="375.9" y="85" width="274.4" height="15.0" fill="rgb(218,62,14)" rx="2" ry="2" /> 490<text x="378.89" y="95.5" >func_1</text> 491</g> 492<g > 493<title>arch_cpu_idle (40 samples, 15.50%)</title><rect x="1007.1" y="101" width="182.9" height="15.0" fill="rgb(218,62,14)" rx="2" ry="2" /> 494<text x="1010.05" y="111.5" >arch_cpu_idle</text> 495</g> 496<g > 497<title>z_thread_entry (258 samples, 100.00%)</title><rect x="10.0" y="133" width="1180.0" height="15.0" fill="rgb(234,137,32)" rx="2" ry="2" /> 498<text x="13.00" y="143.5" >z_thread_entry</text> 499</g> 500<g > 501<title>bg_thread_main (218 samples, 84.50%)</title><rect x="10.0" y="117" width="997.1" height="15.0" fill="rgb(235,140,33)" rx="2" ry="2" /> 502<text x="13.00" y="127.5" >bg_thread_main</text> 503</g> 504<g > 505<title>func_0_0 (20 samples, 7.75%)</title><rect x="10.0" y="69" width="91.5" height="15.0" fill="rgb(251,212,50)" rx="2" ry="2" /> 506<text x="13.00" y="79.5" >func_0_0</text> 507</g> 508<g > 509<title>z_impl_k_busy_wait (20 samples, 7.75%)</title><rect x="10.0" y="53" width="91.5" height="15.0" fill="rgb(239,158,37)" rx="2" ry="2" /> 510<text x="13.00" y="63.5" >z_impl_k_b..</text> 511</g> 512<g > 513<title>func_2 (78 samples, 30.23%)</title><rect x="650.3" y="85" width="356.8" height="15.0" fill="rgb(212,32,7)" rx="2" ry="2" /> 514<text x="653.31" y="95.5" >func_2</text> 515</g> 516<g > 517<title>[unknown] (258 samples, 100.00%)</title><rect x="10.0" y="149" width="1180.0" height="15.0" fill="rgb(210,24,5)" rx="2" ry="2" /> 518<text x="13.00" y="159.5" >[unknown]</text> 519</g> 520</g> 521</svg> 522