315 lines
110 KiB
XML
315 lines
110 KiB
XML
![]() |
<svg width="1200" height="1078" onload="init(evt)" viewBox="0 0 1200 1078" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="background" y2="1" x2="0"><stop stop-color="#eee" offset="5%"/><stop stop-color="#eeeeb0" offset="95%"/></linearGradient></defs><style>.func_g:hover{stroke:#000;stroke-width:.5;cursor:pointer}</style><script type="text/ecmascript"><![CDATA[
|
||
|
var details, searchbtn, matchedtxt, svg;
|
||
|
function init(evt) {
|
||
|
details = document.getElementById("details").firstChild;
|
||
|
searchbtn = document.getElementById("search");
|
||
|
matchedtxt = document.getElementById("matched");
|
||
|
svg = document.getElementsByTagName("svg")[0];
|
||
|
searching = 0;
|
||
|
}
|
||
|
|
||
|
// mouse-over for info
|
||
|
function s(node) { // show
|
||
|
info = g_to_text(node);
|
||
|
details.nodeValue = "Function: " + info;
|
||
|
}
|
||
|
function c() { // clear
|
||
|
details.nodeValue = ' ';
|
||
|
}
|
||
|
|
||
|
// ctrl-F for search
|
||
|
window.addEventListener("keydown",function (e) {
|
||
|
if (e.keyCode === 114 || (e.ctrlKey && e.keyCode === 70)) {
|
||
|
e.preventDefault();
|
||
|
search_prompt();
|
||
|
}
|
||
|
})
|
||
|
|
||
|
// functions
|
||
|
function find_child(parent, name, attr) {
|
||
|
var children = parent.childNodes;
|
||
|
for (var i=0; i<children.length;i++) {
|
||
|
if (children[i].tagName == name)
|
||
|
return (attr != undefined) ? children[i].attributes[attr].value : children[i];
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
function orig_save(e, attr, val) {
|
||
|
if (e.attributes["_orig_"+attr] != undefined) return;
|
||
|
if (e.attributes[attr] == undefined) return;
|
||
|
if (val == undefined) val = e.attributes[attr].value;
|
||
|
e.setAttribute("_orig_"+attr, val);
|
||
|
}
|
||
|
function orig_load(e, attr) {
|
||
|
if (e.attributes["_orig_"+attr] == undefined) return;
|
||
|
e.attributes[attr].value = e.attributes["_orig_"+attr].value;
|
||
|
e.removeAttribute("_orig_"+attr);
|
||
|
}
|
||
|
function g_to_text(e) {
|
||
|
var text = find_child(e, "title").firstChild.nodeValue;
|
||
|
return (text)
|
||
|
}
|
||
|
function g_to_func(e) {
|
||
|
var func = g_to_text(e);
|
||
|
// if there's any manipulation we want to do to the function
|
||
|
// name before it's searched, do it here before returning.
|
||
|
return (func);
|
||
|
}
|
||
|
function update_text(e) {
|
||
|
var r = find_child(e, "rect");
|
||
|
var t = find_child(e, "text");
|
||
|
var w = parseFloat(r.attributes["width"].value) -3;
|
||
|
var txt = find_child(e, "title").textContent.replace(/\([^(]*\)$/,"");
|
||
|
t.attributes["x"].value = parseFloat(r.attributes["x"].value) +3;
|
||
|
|
||
|
// Smaller than this size won't fit anything
|
||
|
if (w < 2*12*0.59) {
|
||
|
t.textContent = "";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
t.textContent = txt;
|
||
|
// Fit in full text width
|
||
|
if (/^ *$/.test(txt) || t.getSubStringLength(0, txt.length) < w)
|
||
|
return;
|
||
|
|
||
|
for (var x=txt.length-2; x>0; x--) {
|
||
|
if (t.getSubStringLength(0, x+2) <= w) {
|
||
|
t.textContent = txt.substring(0,x) + "..";
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
t.textContent = "";
|
||
|
}
|
||
|
|
||
|
// zoom
|
||
|
function zoom_reset(e) {
|
||
|
if (e.attributes != undefined) {
|
||
|
orig_load(e, "x");
|
||
|
orig_load(e, "width");
|
||
|
}
|
||
|
if (e.childNodes == undefined) return;
|
||
|
for(var i=0, c=e.childNodes; i<c.length; i++) {
|
||
|
zoom_reset(c[i]);
|
||
|
}
|
||
|
}
|
||
|
function zoom_child(e, x, ratio) {
|
||
|
if (e.attributes != undefined) {
|
||
|
if (e.attributes["x"] != undefined) {
|
||
|
orig_save(e, "x");
|
||
|
e.attributes["x"].value = (parseFloat(e.attributes["x"].value) - x - 10) * ratio + 10;
|
||
|
if(e.tagName == "text") e.attributes["x"].value = find_child(e.parentNode, "rect", "x") + 3;
|
||
|
}
|
||
|
if (e.attributes["width"] != undefined) {
|
||
|
orig_save(e, "width");
|
||
|
e.attributes["width"].value = parseFloat(e.attributes["width"].value) * ratio;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (e.childNodes == undefined) return;
|
||
|
for(var i=0, c=e.childNodes; i<c.length; i++) {
|
||
|
zoom_child(c[i], x-10, ratio);
|
||
|
}
|
||
|
}
|
||
|
function zoom_parent(e) {
|
||
|
if (e.attributes) {
|
||
|
if (e.attributes["x"] != undefined) {
|
||
|
orig_save(e, "x");
|
||
|
e.attributes["x"].value = 10;
|
||
|
}
|
||
|
if (e.attributes["width"] != undefined) {
|
||
|
orig_save(e, "width");
|
||
|
e.attributes["width"].value = parseInt(svg.width.baseVal.value) - (10*2);
|
||
|
}
|
||
|
}
|
||
|
if (e.childNodes == undefined) return;
|
||
|
for(var i=0, c=e.childNodes; i<c.length; i++) {
|
||
|
zoom_parent(c[i]);
|
||
|
}
|
||
|
}
|
||
|
function zoom(node) {
|
||
|
var attr = find_child(node, "rect").attributes;
|
||
|
var width = parseFloat(attr["width"].value);
|
||
|
var xmin = parseFloat(attr["x"].value);
|
||
|
var xmax = parseFloat(xmin + width);
|
||
|
var ymin = parseFloat(attr["y"].value);
|
||
|
var ratio = (svg.width.baseVal.value - 2*10) / width;
|
||
|
|
||
|
// XXX: Workaround for JavaScript float issues (fix me)
|
||
|
var fudge = 0.0001;
|
||
|
|
||
|
var unzoombtn = document.getElementById("unzoom");
|
||
|
unzoombtn.style["opacity"] = "1.0";
|
||
|
|
||
|
var el = document.getElementsByTagName("g");
|
||
|
for(var i=0;i<el.length;i++){
|
||
|
var e = el[i];
|
||
|
var a = find_child(e, "rect").attributes;
|
||
|
var ex = parseFloat(a["x"].value);
|
||
|
var ew = parseFloat(a["width"].value);
|
||
|
// Is it an ancestor
|
||
|
if (0 == 0) {
|
||
|
var upstack = parseFloat(a["y"].value) > ymin;
|
||
|
} else {
|
||
|
var upstack = parseFloat(a["y"].value) < ymin;
|
||
|
}
|
||
|
if (upstack) {
|
||
|
// Direct ancestor
|
||
|
if (ex <= xmin && (ex+ew+fudge) >= xmax) {
|
||
|
e.style["opacity"] = "0.5";
|
||
|
zoom_parent(e);
|
||
|
e.onclick = function(e){unzoom(); zoom(this);};
|
||
|
update_text(e);
|
||
|
}
|
||
|
// not in current path
|
||
|
else
|
||
|
e.style["display"] = "none";
|
||
|
}
|
||
|
// Children maybe
|
||
|
else {
|
||
|
// no common path
|
||
|
if (ex < xmin || ex + fudge >= xmax) {
|
||
|
e.style["display"] = "none";
|
||
|
}
|
||
|
else {
|
||
|
zoom_child(e, xmin, ratio);
|
||
|
e.onclick = function(e){zoom(this);};
|
||
|
update_text(e);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
function unzoom() {
|
||
|
var unzoombtn = document.getElementById("unzoom");
|
||
|
unzoombtn.style["opacity"] = "0.0";
|
||
|
|
||
|
var el = document.getElementsByTagName("g");
|
||
|
for(i=0;i<el.length;i++) {
|
||
|
el[i].style["display"] = "block";
|
||
|
el[i].style["opacity"] = "1";
|
||
|
zoom_reset(el[i]);
|
||
|
update_text(el[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// search
|
||
|
function reset_search() {
|
||
|
var el = document.getElementsByTagName("rect");
|
||
|
for (var i=0; i < el.length; i++) {
|
||
|
orig_load(el[i], "fill")
|
||
|
}
|
||
|
}
|
||
|
function search_prompt() {
|
||
|
if (!searching) {
|
||
|
var term = prompt("Enter a search term (regexp " +
|
||
|
"allowed, eg: ^ext4_)", "");
|
||
|
if (term != null) {
|
||
|
search(term)
|
||
|
}
|
||
|
} else {
|
||
|
reset_search();
|
||
|
searching = 0;
|
||
|
searchbtn.style["opacity"] = "0.1";
|
||
|
searchbtn.firstChild.nodeValue = "Search"
|
||
|
matchedtxt.style["opacity"] = "0.0";
|
||
|
matchedtxt.firstChild.nodeValue = ""
|
||
|
}
|
||
|
}
|
||
|
function search(term) {
|
||
|
var re = new RegExp(term);
|
||
|
var el = document.getElementsByTagName("g");
|
||
|
var matches = new Object();
|
||
|
var maxwidth = 0;
|
||
|
for (var i = 0; i < el.length; i++) {
|
||
|
var e = el[i];
|
||
|
if (e.attributes["class"].value != "func_g")
|
||
|
continue;
|
||
|
var func = g_to_func(e);
|
||
|
var rect = find_child(e, "rect");
|
||
|
if (rect == null) {
|
||
|
// the rect might be wrapped in an anchor
|
||
|
// if nameattr href is being used
|
||
|
if (rect = find_child(e, "a")) {
|
||
|
rect = find_child(r, "rect");
|
||
|
}
|
||
|
}
|
||
|
if (func == null || rect == null)
|
||
|
continue;
|
||
|
|
||
|
// Save max width. Only works as we have a root frame
|
||
|
var w = parseFloat(rect.attributes["width"].value);
|
||
|
if (w > maxwidth)
|
||
|
maxwidth = w;
|
||
|
|
||
|
if (func.match(re)) {
|
||
|
// highlight
|
||
|
var x = parseFloat(rect.attributes["x"].value);
|
||
|
orig_save(rect, "fill");
|
||
|
rect.attributes["fill"].value =
|
||
|
"rgb(230,0,230)";
|
||
|
|
||
|
// remember matches
|
||
|
if (matches[x] == undefined) {
|
||
|
matches[x] = w;
|
||
|
} else {
|
||
|
if (w > matches[x]) {
|
||
|
// overwrite with parent
|
||
|
matches[x] = w;
|
||
|
}
|
||
|
}
|
||
|
searching = 1;
|
||
|
}
|
||
|
}
|
||
|
if (!searching)
|
||
|
return;
|
||
|
|
||
|
searchbtn.style["opacity"] = "1.0";
|
||
|
searchbtn.firstChild.nodeValue = "Reset Search"
|
||
|
|
||
|
// calculate percent matched, excluding vertical overlap
|
||
|
var count = 0;
|
||
|
var lastx = -1;
|
||
|
var lastw = 0;
|
||
|
var keys = Array();
|
||
|
for (k in matches) {
|
||
|
if (matches.hasOwnProperty(k))
|
||
|
keys.push(k);
|
||
|
}
|
||
|
// sort the matched frames by their x location
|
||
|
// ascending, then width descending
|
||
|
keys.sort(function(a, b){
|
||
|
return a - b;
|
||
|
});
|
||
|
// Step through frames saving only the biggest bottom-up frames
|
||
|
// thanks to the sort order. This relies on the tree property
|
||
|
// where children are always smaller than their parents.
|
||
|
var fudge = 0.0001; // JavaScript floating point
|
||
|
for (var k in keys) {
|
||
|
var x = parseFloat(keys[k]);
|
||
|
var w = matches[keys[k]];
|
||
|
if (x >= lastx + lastw - fudge) {
|
||
|
count += w;
|
||
|
lastx = x;
|
||
|
lastw = w;
|
||
|
}
|
||
|
}
|
||
|
// display matched percent
|
||
|
matchedtxt.style["opacity"] = "1.0";
|
||
|
pct = 100 * count / maxwidth;
|
||
|
if (pct == 100)
|
||
|
pct = "100"
|
||
|
else
|
||
|
pct = pct.toFixed(1)
|
||
|
matchedtxt.firstChild.nodeValue = "Matched: " + pct + "%";
|
||
|
}
|
||
|
function searchover(e) {
|
||
|
searchbtn.style["opacity"] = "1.0";
|
||
|
}
|
||
|
function searchout(e) {
|
||
|
if (searching) {
|
||
|
searchbtn.style["opacity"] = "1.0";
|
||
|
} else {
|
||
|
searchbtn.style["opacity"] = "0.1";
|
||
|
}
|
||
|
}
|
||
|
]]></script><path fill="url(#background)" d="M0 0H1200V1078H0z"/><text text-anchor="middle" x="600" y="24" font-size="17" font-family="Verdana">Flame Graph</text><text x="10" y="1061" font-size="12" font-family="Verdana" id="details"></text><text x="10" y="24" font-size="12" font-family="Verdana" id="unzoom" onclick="unzoom()" opacity="0.0" cursor="pointer">Reset Zoom</text><text x="1090" y="24" font-size="12" font-family="Verdana" id="search" onmouseover="searchover()" onmouseout="searchout()" onclick="search_prompt()" opacity="0.1" cursor="pointer">Search</text><text x="1090" y="1061" font-size="12" font-family="Verdana" id="matched"></text><g class="func_g" onmouseover="s(this)" onmouseout="c()" onclick="zoom(this)"><title>/datas/progs/odoo/odoo/models.py:browse:4237 (11 samples, 8.33%)</title><rect x="760.9" y="85" width="98.3" height="15" fill="#D93707" rx="2" ry="2"/><text x="763.91" y="95.5" font-size="12" font-family="Verdana">/datas/prog..</text></g><g class="func_g" onmouseover="s(this)" onmouseout="c()" onclick="zoom(this)"><title>/datas/progs/odoo/odoo/fields.py:__get__:948 (1 samples, 0.76%)</title><rect x="1181.1" y="357" width="8.9" height="15" fill="#CD8D24" rx="2" ry="2"/></g><g class="func_g" onmouseover="s(this)" onmouseout="c()" onclick="zoom(this)"><title>/datas/progs/odoo/odoo/api.py:__new__:735 (3 samples, 2.27%)</title><rect x="188.8" y="197" width="26.8" height="15" fill="#D9B31D" rx="2" ry="2"/><text x="191.79" y="207.5" font-size="12" font-family="Verdana">/..</text></g><g class="func_g" onmouseover="s(this)" onmouseout="c()" onclick="zoom(this)"><title>/datas/progs/odoo/odoo/fields.py:__get__:948 (38 samples, 28.79%)</title><rect x="617.9" y="181" width="339.7" height="15" fill="#DF2D2E" rx="2" ry="2"/><text x="620.88" y="191.5" font-size="12" font-family="Verdana">/datas/progs/odoo/odoo/fields.py:__get__:948</text></g><g class="func_g" onmouseover="s(this)" onmouseout="c()" onclick="zoom(this)"><title>/datas/progs/odoo/odoo/api.py:__new__:736 (5 samples, 3.79%)</title><rect x="1064.8" y="213" width="44.7" height="15" fill="#D64A2F" rx="2" ry="2"/><text x="1067.85" y="223.5" font-size="12" font-family="Verdana">/dat..</text></g><g class="func_g" onmouseover="s(this)" onmouseout="c()" onclick="zoom(this)"><title><string>:__new__:14 (1 samples, 0.76%)</title><rect x="144.1" y="213" width="8.9" height="15" fill="#DD3515" rx="2" ry="2"/></g><g class="func_g" onmouseover="s(this)" onmouseout="c()" onclick="zoom(this)"><title>/datas/progs/odoo/odoo/models.py:_normalize_ids:5206 (1 samples, 0.76%)</title><rect x="752" y="69" width="8.9" height="15" fill="#F38E29" rx="2" ry="2"/></g><g class="func_g" onmouseover="s(this)" onmouseout="c()" onclick="zoom(this)"><title><frozen importlib._bootstrap>:_call_with_frames_removed:219 (1 samples, 0.76%)</title><rect x="10" y="389" width="8.9" height="15" fill="#EF6504" rx="2" ry="2"/></g><g class="func_g" onmouseover="s(this)" onmouseout="c()" onclick="zoom(this)"><title>/datas/progs/odoo/odoo/models.py:sudo:4310 (3 samples, 2.27%)</title><rect x="510.6" y="197" width="26.8" height="15" fill="#DBDB2A" rx="2" ry="2"/><text x="513.61" y="207.5" font-size="12" font-family="Verdana">/..</text></g><g class="func_g" onmouseover="s(this)" onmouseout="c()" onclick="zoom(this)"><title><frozen importlib._bootstrap>:_call_with_frames_removed:219 (1 samples, 0.76%)</title><rect x="10" y="181" width="8.9" height="15" fill="#D4982C" rx="2" ry="2"/></g><g class="func_g" onmouseover="s(this)" onmouseout="c()" onclick="zoom(this)"><title>/datas/progs/odoo/odoo/api.py:__new__:736 (1 samples, 0.76%)</title><rect x="528.5" y="165" width="8.9" height="15" fill="#F97923" rx="2" ry="2"/></g><g class="func_g" onmouseover="s(this)" onmouseout="c()" onclick="zoom(this)"><title><frozen importlib._bootstrap_external>:exec_module:678 (1 samples, 0.76%)</title><rect x="10" y="197" width="8.9" height="15" fill="#D64B33" rx="2" ry="2"/></g><g class="func_g" onmouseover="s(this)" onmouseout="c()" onclick="zoom(this)"><title>/datas/progs/odoo/odoo/fields.py:convert_to_c
|