Skip to content

Instantly share code, notes, and snippets.

@antocuni
Created September 7, 2024 12:09
Show Gist options
  • Select an option

  • Save antocuni/aac6bc866c9e46f2a423b9f1e58ca796 to your computer and use it in GitHub Desktop.

Select an option

Save antocuni/aac6bc866c9e46f2a423b9f1e58ca796 to your computer and use it in GitHub Desktop.
scalene flamegraph
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" width="1800" height="242" onload="init(evt)" viewBox="0 0 1800 242" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Flame graph stack visualization. See https://github.com/brendangregg/FlameGraph for latest version, and http://www.brendangregg.com/flamegraphs.html for examples. -->
<defs >
<linearGradient id="background" y1="0" y2="1" x1="0" x2="0" >
<stop stop-color="#eeeeee" offset="5%" />
<stop stop-color="#eeeeb0" offset="95%" />
</linearGradient>
</defs>
<style type="text/css">
.func_g:hover { stroke:black; stroke-width:0.5; cursor:pointer; }
</style>
<script type="text/ecmascript">
<![CDATA[
var details, svg;
function init(evt) {
details = document.getElementById("details").firstChild;
svg = document.getElementsByTagName("svg")[0];
searching = 0;
}
// mouse-over for info
function s(info) { details.nodeValue = "Function: " + info; }
function c() { details.nodeValue = ' '; }
// 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 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;
var searchbtn = document.getElementById("search");
searchbtn.style["opacity"] = "0.1";
searchbtn.firstChild.nodeValue = "Search"
}
}
function search(term) {
var re = new RegExp(term);
var el = document.getElementsByTagName("g");
for (var i=0; i < el.length; i++){
var e = el[i];
if (e.attributes["class"].value == "func_g") {
// Scrape the function name from the onmouseover
// callback text. This is a little dirty.
var func = e.attributes["onmouseover"].value;
if (func != null) {
func = func.substr(3);
func = func.replace(/ .*/, "");
var r = find_child(e, "rect");
}
if (func != null && r != null &&
func.match(re)) {
orig_save(r, "fill");
r.attributes["fill"].value =
"rgb(230,0,230)";
searching = 1;
}
}
}
if (searching) {
var searchbtn = document.getElementById("search");
searchbtn.style["opacity"] = "1.0";
searchbtn.firstChild.nodeValue = "Reset Search"
}
}
function searchover(e) {
var searchbtn = document.getElementById("search");
searchbtn.style["opacity"] = "1.0";
}
function searchout(e) {
var searchbtn = document.getElementById("search");
if (searching) {
searchbtn.style["opacity"] = "1.0";
} else {
searchbtn.style["opacity"] = "0.1";
}
}
]]>
</script>
<rect x="0.0" y="0" width="1800.0" height="242.0" fill="url(#background)" />
<text text-anchor="middle" x="900.00" y="24" font-size="17" font-family="Verdana" fill="rgb(0,0,0)" >Flame Graph</text>
<text text-anchor="" x="10.00" y="225" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" id="details" > </text>
<text text-anchor="" x="10.00" y="24" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" id="unzoom" onclick="unzoom()" style="opacity:0.0;cursor:pointer" >Reset Zoom</text>
<text text-anchor="" x="1690.00" y="24" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" id="search" onmouseover="searchover()" onmouseout="searchout()" onclick="search_prompt()" style="opacity:0.1;cursor:pointer" >Search</text>
<g class="func_g" onmouseover="s('Packet.append_to:/tmp/richards.py (1 samples, 0.21%)')" onmouseout="c()" onclick="zoom(this)">
<title>Packet.append_to:/tmp/richards.py (1 samples, 0.21%)</title><rect x="1118.3" y="49" width="3.7" height="15.0" fill="rgb(234,69,26)" rx="2" ry="2" />
<text text-anchor="" x="1121.30" y="59.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('Task.qpkt:/tmp/richards.py (36 samples, 7.55%)')" onmouseout="c()" onclick="zoom(this)">
<title>Task.qpkt:/tmp/richards.py (36 samples, 7.55%)</title><rect x="1122.0" y="65" width="134.4" height="15.0" fill="rgb(210,213,31)" rx="2" ry="2" />
<text text-anchor="" x="1125.03" y="75.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >Task.qpkt:/tmp/r..</text>
</g>
<g class="func_g" onmouseover="s('DeviceTask.fn:/tmp/richards.py (58 samples, 12.16%)')" onmouseout="c()" onclick="zoom(this)">
<title>DeviceTask.fn:/tmp/richards.py (58 samples, 12.16%)</title><rect x="786.2" y="81" width="216.4" height="15.0" fill="rgb(235,164,48)" rx="2" ry="2" />
<text text-anchor="" x="789.18" y="91.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >DeviceTask.fn:/tmp/richards.py</text>
</g>
<g class="func_g" onmouseover="s('HandlerTaskRec.deviceInAdd:/tmp/richards.py (8 samples, 1.68%)')" onmouseout="c()" onclick="zoom(this)">
<title>HandlerTaskRec.deviceInAdd:/tmp/richards.py (8 samples, 1.68%)</title><rect x="1073.5" y="65" width="29.9" height="15.0" fill="rgb(249,130,17)" rx="2" ry="2" />
<text text-anchor="" x="1076.52" y="75.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >Ha..</text>
</g>
<g class="func_g" onmouseover="s('Task.qpkt:/tmp/richards.py (5 samples, 1.05%)')" onmouseout="c()" onclick="zoom(this)">
<title>Task.qpkt:/tmp/richards.py (5 samples, 1.05%)</title><rect x="1674.3" y="65" width="18.7" height="15.0" fill="rgb(220,138,28)" rx="2" ry="2" />
<text text-anchor="" x="1677.32" y="75.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('Task.addPacket:/tmp/richards.py (18 samples, 3.77%)')" onmouseout="c()" onclick="zoom(this)">
<title>Task.addPacket:/tmp/richards.py (18 samples, 3.77%)</title><rect x="1181.7" y="49" width="67.2" height="15.0" fill="rgb(243,189,28)" rx="2" ry="2" />
<text text-anchor="" x="1184.74" y="59.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >Task.ad..</text>
</g>
<g class="func_g" onmouseover="s('HandlerTaskRec.workInAdd:/tmp/richards.py (5 samples, 1.05%)')" onmouseout="c()" onclick="zoom(this)">
<title>HandlerTaskRec.workInAdd:/tmp/richards.py (5 samples, 1.05%)</title><rect x="1103.4" y="65" width="18.6" height="15.0" fill="rgb(213,216,52)" rx="2" ry="2" />
<text text-anchor="" x="1106.38" y="75.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('TaskState.packetPending:/tmp/richards.py (14 samples, 2.94%)')" onmouseout="c()" onclick="zoom(this)">
<title>TaskState.packetPending:/tmp/richards.py (14 samples, 2.94%)</title><rect x="1457.9" y="81" width="52.2" height="15.0" fill="rgb(212,129,12)" rx="2" ry="2" />
<text text-anchor="" x="1460.88" y="91.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >TaskS..</text>
</g>
<g class="func_g" onmouseover="s('TaskState.running:/tmp/richards.py (27 samples, 5.66%)')" onmouseout="c()" onclick="zoom(this)">
<title>TaskState.running:/tmp/richards.py (27 samples, 5.66%)</title><rect x="1510.1" y="81" width="100.8" height="15.0" fill="rgb(254,179,53)" rx="2" ry="2" />
<text text-anchor="" x="1513.13" y="91.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >TaskState.ru..</text>
</g>
<g class="func_g" onmouseover="s('Task.findtcb:/tmp/richards.py (4 samples, 0.84%)')" onmouseout="c()" onclick="zoom(this)">
<title>Task.findtcb:/tmp/richards.py (4 samples, 0.84%)</title><rect x="972.8" y="49" width="14.9" height="15.0" fill="rgb(208,78,24)" rx="2" ry="2" />
<text text-anchor="" x="975.77" y="59.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('Task.qpkt:/tmp/richards.py (18 samples, 3.77%)')" onmouseout="c()" onclick="zoom(this)">
<title>Task.qpkt:/tmp/richards.py (18 samples, 3.77%)</title><rect x="920.5" y="65" width="67.2" height="15.0" fill="rgb(210,31,48)" rx="2" ry="2" />
<text text-anchor="" x="923.52" y="75.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >Task.qp..</text>
</g>
<g class="func_g" onmouseover="s('Task.hold:/tmp/richards.py (4 samples, 0.84%)')" onmouseout="c()" onclick="zoom(this)">
<title>Task.hold:/tmp/richards.py (4 samples, 0.84%)</title><rect x="905.6" y="65" width="14.9" height="15.0" fill="rgb(242,42,54)" rx="2" ry="2" />
<text text-anchor="" x="908.60" y="75.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('all (477 samples, 100%)')" onmouseout="c()" onclick="zoom(this)">
<title>all (477 samples, 100%)</title><rect x="10.0" y="193" width="1780.0" height="15.0" fill="rgb(246,163,1)" rx="2" ry="2" />
<text text-anchor="" x="13.00" y="203.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('main:/tmp/richards.py (477 samples, 100.00%)')" onmouseout="c()" onclick="zoom(this)">
<title>main:/tmp/richards.py (477 samples, 100.00%)</title><rect x="10.0" y="161" width="1780.0" height="15.0" fill="rgb(242,129,21)" rx="2" ry="2" />
<text text-anchor="" x="13.00" y="171.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >main:/tmp/richards.py</text>
</g>
<g class="func_g" onmouseover="s('Richards.run:/tmp/richards.py (477 samples, 100.00%)')" onmouseout="c()" onclick="zoom(this)">
<title>Richards.run:/tmp/richards.py (477 samples, 100.00%)</title><rect x="10.0" y="129" width="1780.0" height="15.0" fill="rgb(206,41,42)" rx="2" ry="2" />
<text text-anchor="" x="13.00" y="139.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >Richards.run:/tmp/richards.py</text>
</g>
<g class="func_g" onmouseover="s('schedule:/tmp/richards.py (477 samples, 100.00%)')" onmouseout="c()" onclick="zoom(this)">
<title>schedule:/tmp/richards.py (477 samples, 100.00%)</title><rect x="10.0" y="113" width="1780.0" height="15.0" fill="rgb(240,22,23)" rx="2" ry="2" />
<text text-anchor="" x="13.00" y="123.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >schedule:/tmp/richards.py</text>
</g>
<g class="func_g" onmouseover="s('Task.runTask:/tmp/richards.py (318 samples, 66.67%)')" onmouseout="c()" onclick="zoom(this)">
<title>Task.runTask:/tmp/richards.py (318 samples, 66.67%)</title><rect x="510.0" y="97" width="1186.7" height="15.0" fill="rgb(209,94,52)" rx="2" ry="2" />
<text text-anchor="" x="513.04" y="107.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >Task.runTask:/tmp/richards.py</text>
</g>
<g class="func_g" onmouseover="s('Task.findtcb:/tmp/richards.py (2 samples, 0.42%)')" onmouseout="c()" onclick="zoom(this)">
<title>Task.findtcb:/tmp/richards.py (2 samples, 0.42%)</title><rect x="1685.5" y="49" width="7.5" height="15.0" fill="rgb(219,162,14)" rx="2" ry="2" />
<text text-anchor="" x="1688.51" y="59.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('(module):/tmp/richards.py (477 samples, 100.00%)')" onmouseout="c()" onclick="zoom(this)">
<title>(module):/tmp/richards.py (477 samples, 100.00%)</title><rect x="10.0" y="177" width="1780.0" height="15.0" fill="rgb(253,172,15)" rx="2" ry="2" />
<text text-anchor="" x="13.00" y="187.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >(module):/tmp/richards.py</text>
</g>
<g class="func_g" onmouseover="s('Task.addPacket:/tmp/richards.py (1 samples, 0.21%)')" onmouseout="c()" onclick="zoom(this)">
<title>Task.addPacket:/tmp/richards.py (1 samples, 0.21%)</title><rect x="1681.8" y="49" width="3.7" height="15.0" fill="rgb(244,2,50)" rx="2" ry="2" />
<text text-anchor="" x="1684.78" y="59.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('TaskState.isWaitingWithPacket:/tmp/richards.py (15 samples, 3.14%)')" onmouseout="c()" onclick="zoom(this)">
<title>TaskState.isWaitingWithPacket:/tmp/richards.py (15 samples, 3.14%)</title><rect x="1401.9" y="81" width="56.0" height="15.0" fill="rgb(243,188,21)" rx="2" ry="2" />
<text text-anchor="" x="1404.91" y="91.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >TaskS..</text>
</g>
<g class="func_g" onmouseover="s('Packet.append_to:/tmp/richards.py (2 samples, 0.42%)')" onmouseout="c()" onclick="zoom(this)">
<title>Packet.append_to:/tmp/richards.py (2 samples, 0.42%)</title><rect x="1095.9" y="49" width="7.5" height="15.0" fill="rgb(254,49,27)" rx="2" ry="2" />
<text text-anchor="" x="1098.91" y="59.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('IdleTask.fn:/tmp/richards.py (31 samples, 6.50%)')" onmouseout="c()" onclick="zoom(this)">
<title>IdleTask.fn:/tmp/richards.py (31 samples, 6.50%)</title><rect x="1286.2" y="81" width="115.7" height="15.0" fill="rgb(221,16,19)" rx="2" ry="2" />
<text text-anchor="" x="1289.23" y="91.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >IdleTask.fn:/t..</text>
</g>
<g class="func_g" onmouseover="s('Task.findtcb:/tmp/richards.py (3 samples, 0.63%)')" onmouseout="c()" onclick="zoom(this)">
<title>Task.findtcb:/tmp/richards.py (3 samples, 0.63%)</title><rect x="1390.7" y="49" width="11.2" height="15.0" fill="rgb(243,36,0)" rx="2" ry="2" />
<text text-anchor="" x="1393.71" y="59.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('HandlerTask.fn:/tmp/richards.py (76 samples, 15.93%)')" onmouseout="c()" onclick="zoom(this)">
<title>HandlerTask.fn:/tmp/richards.py (76 samples, 15.93%)</title><rect x="1002.6" y="81" width="283.6" height="15.0" fill="rgb(236,187,30)" rx="2" ry="2" />
<text text-anchor="" x="1005.62" y="91.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >HandlerTask.fn:/tmp/richards.py</text>
</g>
<g class="func_g" onmouseover="s('entry_point:/tmp/richards.py (477 samples, 100.00%)')" onmouseout="c()" onclick="zoom(this)">
<title>entry_point:/tmp/richards.py (477 samples, 100.00%)</title><rect x="10.0" y="145" width="1780.0" height="15.0" fill="rgb(217,224,32)" rx="2" ry="2" />
<text text-anchor="" x="13.00" y="155.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >entry_point:/tmp/richards.py</text>
</g>
<g class="func_g" onmouseover="s('Task.waitTask:/tmp/richards.py (4 samples, 0.84%)')" onmouseout="c()" onclick="zoom(this)">
<title>Task.waitTask:/tmp/richards.py (4 samples, 0.84%)</title><rect x="987.7" y="65" width="14.9" height="15.0" fill="rgb(221,100,42)" rx="2" ry="2" />
<text text-anchor="" x="990.69" y="75.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('Task.findtcb:/tmp/richards.py (2 samples, 0.42%)')" onmouseout="c()" onclick="zoom(this)">
<title>Task.findtcb:/tmp/richards.py (2 samples, 0.42%)</title><rect x="1248.9" y="49" width="7.5" height="15.0" fill="rgb(214,80,23)" rx="2" ry="2" />
<text text-anchor="" x="1251.91" y="59.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('Task.waitTask:/tmp/richards.py (1 samples, 0.21%)')" onmouseout="c()" onclick="zoom(this)">
<title>Task.waitTask:/tmp/richards.py (1 samples, 0.21%)</title><rect x="1693.0" y="65" width="3.7" height="15.0" fill="rgb(229,27,45)" rx="2" ry="2" />
<text text-anchor="" x="1695.98" y="75.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('Task.release:/tmp/richards.py (25 samples, 5.24%)')" onmouseout="c()" onclick="zoom(this)">
<title>Task.release:/tmp/richards.py (25 samples, 5.24%)</title><rect x="1308.6" y="65" width="93.3" height="15.0" fill="rgb(251,20,12)" rx="2" ry="2" />
<text text-anchor="" x="1311.62" y="75.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >Task.releas..</text>
</g>
<g class="func_g" onmouseover="s('WorkTask.fn:/tmp/richards.py (23 samples, 4.82%)')" onmouseout="c()" onclick="zoom(this)">
<title>WorkTask.fn:/tmp/richards.py (23 samples, 4.82%)</title><rect x="1610.9" y="81" width="85.8" height="15.0" fill="rgb(223,13,41)" rx="2" ry="2" />
<text text-anchor="" x="1613.88" y="91.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >WorkTask.f..</text>
</g>
<g class="func_g" onmouseover="s('Task.addPacket:/tmp/richards.py (9 samples, 1.89%)')" onmouseout="c()" onclick="zoom(this)">
<title>Task.addPacket:/tmp/richards.py (9 samples, 1.89%)</title><rect x="939.2" y="49" width="33.6" height="15.0" fill="rgb(216,41,36)" rx="2" ry="2" />
<text text-anchor="" x="942.18" y="59.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >Ta..</text>
</g>
<g class="func_g" onmouseover="s('Task.waitTask:/tmp/richards.py (8 samples, 1.68%)')" onmouseout="c()" onclick="zoom(this)">
<title>Task.waitTask:/tmp/richards.py (8 samples, 1.68%)</title><rect x="1256.4" y="65" width="29.8" height="15.0" fill="rgb(228,2,17)" rx="2" ry="2" />
<text text-anchor="" x="1259.37" y="75.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >Ta..</text>
</g>
<g class="func_g" onmouseover="s('TaskState.isTaskHoldingOrWaiting:/tmp/richards.py (25 samples, 5.24%)')" onmouseout="c()" onclick="zoom(this)">
<title>TaskState.isTaskHoldingOrWaiting:/tmp/richards.py (25 samples, 5.24%)</title><rect x="1696.7" y="97" width="93.3" height="15.0" fill="rgb(214,86,14)" rx="2" ry="2" />
<text text-anchor="" x="1699.71" y="107.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >TaskState.i..</text>
</g>
<g class="func_g" onmouseover="s('Packet.append_to:/tmp/richards.py (2 samples, 0.42%)')" onmouseout="c()" onclick="zoom(this)">
<title>Packet.append_to:/tmp/richards.py (2 samples, 0.42%)</title><rect x="1241.4" y="33" width="7.5" height="15.0" fill="rgb(236,100,34)" rx="2" ry="2" />
<text text-anchor="" x="1244.45" y="43.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
</svg>
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" width="1800" height="242" onload="init(evt)" viewBox="0 0 1800 242" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Flame graph stack visualization. See https://github.com/brendangregg/FlameGraph for latest version, and http://www.brendangregg.com/flamegraphs.html for examples. -->
<defs >
<linearGradient id="background" y1="0" y2="1" x1="0" x2="0" >
<stop stop-color="#eeeeee" offset="5%" />
<stop stop-color="#eeeeb0" offset="95%" />
</linearGradient>
</defs>
<style type="text/css">
.func_g:hover { stroke:black; stroke-width:0.5; cursor:pointer; }
</style>
<script type="text/ecmascript">
<![CDATA[
var details, svg;
function init(evt) {
details = document.getElementById("details").firstChild;
svg = document.getElementsByTagName("svg")[0];
searching = 0;
}
// mouse-over for info
function s(info) { details.nodeValue = "Function: " + info; }
function c() { details.nodeValue = ' '; }
// 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 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;
var searchbtn = document.getElementById("search");
searchbtn.style["opacity"] = "0.1";
searchbtn.firstChild.nodeValue = "Search"
}
}
function search(term) {
var re = new RegExp(term);
var el = document.getElementsByTagName("g");
for (var i=0; i < el.length; i++){
var e = el[i];
if (e.attributes["class"].value == "func_g") {
// Scrape the function name from the onmouseover
// callback text. This is a little dirty.
var func = e.attributes["onmouseover"].value;
if (func != null) {
func = func.substr(3);
func = func.replace(/ .*/, "");
var r = find_child(e, "rect");
}
if (func != null && r != null &&
func.match(re)) {
orig_save(r, "fill");
r.attributes["fill"].value =
"rgb(230,0,230)";
searching = 1;
}
}
}
if (searching) {
var searchbtn = document.getElementById("search");
searchbtn.style["opacity"] = "1.0";
searchbtn.firstChild.nodeValue = "Reset Search"
}
}
function searchover(e) {
var searchbtn = document.getElementById("search");
searchbtn.style["opacity"] = "1.0";
}
function searchout(e) {
var searchbtn = document.getElementById("search");
if (searching) {
searchbtn.style["opacity"] = "1.0";
} else {
searchbtn.style["opacity"] = "0.1";
}
}
]]>
</script>
<rect x="0.0" y="0" width="1800.0" height="242.0" fill="url(#background)" />
<text text-anchor="middle" x="900.00" y="24" font-size="17" font-family="Verdana" fill="rgb(0,0,0)" >Flame Graph</text>
<text text-anchor="" x="10.00" y="225" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" id="details" > </text>
<text text-anchor="" x="10.00" y="24" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" id="unzoom" onclick="unzoom()" style="opacity:0.0;cursor:pointer" >Reset Zoom</text>
<text text-anchor="" x="1690.00" y="24" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" id="search" onmouseover="searchover()" onmouseout="searchout()" onclick="search_prompt()" style="opacity:0.1;cursor:pointer" >Search</text>
<g class="func_g" onmouseover="s('(module):/tmp/richards.py (469 samples, 100.00%)')" onmouseout="c()" onclick="zoom(this)">
<title>(module):/tmp/richards.py (469 samples, 100.00%)</title><rect x="10.0" y="177" width="1780.0" height="15.0" fill="rgb(252,117,1)" rx="2" ry="2" />
<text text-anchor="" x="13.00" y="187.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >(module):/tmp/richards.py</text>
</g>
<g class="func_g" onmouseover="s('append_to:/tmp/richards.py (3 samples, 0.64%)')" onmouseout="c()" onclick="zoom(this)">
<title>append_to:/tmp/richards.py (3 samples, 0.64%)</title><rect x="1114.4" y="49" width="11.4" height="15.0" fill="rgb(222,186,47)" rx="2" ry="2" />
<text text-anchor="" x="1117.43" y="59.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('waitTask:/tmp/richards.py (10 samples, 2.13%)')" onmouseout="c()" onclick="zoom(this)">
<title>waitTask:/tmp/richards.py (10 samples, 2.13%)</title><rect x="1531.9" y="65" width="38.0" height="15.0" fill="rgb(238,135,36)" rx="2" ry="2" />
<text text-anchor="" x="1534.92" y="75.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >wai..</text>
</g>
<g class="func_g" onmouseover="s('schedule:/tmp/richards.py (469 samples, 100.00%)')" onmouseout="c()" onclick="zoom(this)">
<title>schedule:/tmp/richards.py (469 samples, 100.00%)</title><rect x="10.0" y="113" width="1780.0" height="15.0" fill="rgb(211,17,2)" rx="2" ry="2" />
<text text-anchor="" x="13.00" y="123.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >schedule:/tmp/richards.py</text>
</g>
<g class="func_g" onmouseover="s('findtcb:/tmp/richards.py (9 samples, 1.92%)')" onmouseout="c()" onclick="zoom(this)">
<title>findtcb:/tmp/richards.py (9 samples, 1.92%)</title><rect x="1391.5" y="49" width="34.2" height="15.0" fill="rgb(249,77,32)" rx="2" ry="2" />
<text text-anchor="" x="1394.49" y="59.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >fi..</text>
</g>
<g class="func_g" onmouseover="s('packetPending:/tmp/richards.py (13 samples, 2.77%)')" onmouseout="c()" onclick="zoom(this)">
<title>packetPending:/tmp/richards.py (13 samples, 2.77%)</title><rect x="1630.6" y="81" width="49.3" height="15.0" fill="rgb(234,61,20)" rx="2" ry="2" />
<text text-anchor="" x="1633.60" y="91.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >pack..</text>
</g>
<g class="func_g" onmouseover="s('release:/tmp/richards.py (28 samples, 5.97%)')" onmouseout="c()" onclick="zoom(this)">
<title>release:/tmp/richards.py (28 samples, 5.97%)</title><rect x="1425.7" y="65" width="106.2" height="15.0" fill="rgb(208,168,43)" rx="2" ry="2" />
<text text-anchor="" x="1428.65" y="75.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >release:/tmp/..</text>
</g>
<g class="func_g" onmouseover="s('isTaskHoldingOrWaiting:/tmp/richards.py (33 samples, 7.04%)')" onmouseout="c()" onclick="zoom(this)">
<title>isTaskHoldingOrWaiting:/tmp/richards.py (33 samples, 7.04%)</title><rect x="488.2" y="97" width="125.3" height="15.0" fill="rgb(211,196,39)" rx="2" ry="2" />
<text text-anchor="" x="491.21" y="107.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >isTaskHoldingOr..</text>
</g>
<g class="func_g" onmouseover="s('main:/tmp/richards.py (469 samples, 100.00%)')" onmouseout="c()" onclick="zoom(this)">
<title>main:/tmp/richards.py (469 samples, 100.00%)</title><rect x="10.0" y="161" width="1780.0" height="15.0" fill="rgb(232,81,6)" rx="2" ry="2" />
<text text-anchor="" x="13.00" y="171.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >main:/tmp/richards.py</text>
</g>
<g class="func_g" onmouseover="s('run:/tmp/richards.py (469 samples, 100.00%)')" onmouseout="c()" onclick="zoom(this)">
<title>run:/tmp/richards.py (469 samples, 100.00%)</title><rect x="10.0" y="129" width="1780.0" height="15.0" fill="rgb(228,85,48)" rx="2" ry="2" />
<text text-anchor="" x="13.00" y="139.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >run:/tmp/richards.py</text>
</g>
<g class="func_g" onmouseover="s('workInAdd:/tmp/richards.py (3 samples, 0.64%)')" onmouseout="c()" onclick="zoom(this)">
<title>workInAdd:/tmp/richards.py (3 samples, 0.64%)</title><rect x="1569.9" y="65" width="11.4" height="15.0" fill="rgb(238,28,21)" rx="2" ry="2" />
<text text-anchor="" x="1572.87" y="75.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('deviceInAdd:/tmp/richards.py (11 samples, 2.35%)')" onmouseout="c()" onclick="zoom(this)">
<title>deviceInAdd:/tmp/richards.py (11 samples, 2.35%)</title><rect x="1084.1" y="65" width="41.7" height="15.0" fill="rgb(214,85,21)" rx="2" ry="2" />
<text text-anchor="" x="1087.07" y="75.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >dev..</text>
</g>
<g class="func_g" onmouseover="s('hold:/tmp/richards.py (6 samples, 1.28%)')" onmouseout="c()" onclick="zoom(this)">
<title>hold:/tmp/richards.py (6 samples, 1.28%)</title><rect x="1125.8" y="65" width="22.8" height="15.0" fill="rgb(223,172,48)" rx="2" ry="2" />
<text text-anchor="" x="1128.82" y="75.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >h..</text>
</g>
<g class="func_g" onmouseover="s('runTask:/tmp/richards.py (310 samples, 66.10%)')" onmouseout="c()" onclick="zoom(this)">
<title>runTask:/tmp/richards.py (310 samples, 66.10%)</title><rect x="613.5" y="97" width="1176.5" height="15.0" fill="rgb(237,135,24)" rx="2" ry="2" />
<text text-anchor="" x="616.45" y="107.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >runTask:/tmp/richards.py</text>
</g>
<g class="func_g" onmouseover="s('findtcb:/tmp/richards.py (1 samples, 0.21%)')" onmouseout="c()" onclick="zoom(this)">
<title>findtcb:/tmp/richards.py (1 samples, 0.21%)</title><rect x="1528.1" y="49" width="3.8" height="15.0" fill="rgb(221,174,11)" rx="2" ry="2" />
<text text-anchor="" x="1531.12" y="59.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('qpkt:/tmp/richards.py (73 samples, 15.57%)')" onmouseout="c()" onclick="zoom(this)">
<title>qpkt:/tmp/richards.py (73 samples, 15.57%)</title><rect x="1148.6" y="65" width="277.1" height="15.0" fill="rgb(213,9,6)" rx="2" ry="2" />
<text text-anchor="" x="1151.59" y="75.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >qpkt:/tmp/richards.py</text>
</g>
<g class="func_g" onmouseover="s('running:/tmp/richards.py (29 samples, 6.18%)')" onmouseout="c()" onclick="zoom(this)">
<title>running:/tmp/richards.py (29 samples, 6.18%)</title><rect x="1679.9" y="81" width="110.1" height="15.0" fill="rgb(211,207,46)" rx="2" ry="2" />
<text text-anchor="" x="1682.94" y="91.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >running:/tmp/..</text>
</g>
<g class="func_g" onmouseover="s('all (469 samples, 100%)')" onmouseout="c()" onclick="zoom(this)">
<title>all (469 samples, 100%)</title><rect x="10.0" y="193" width="1780.0" height="15.0" fill="rgb(249,103,48)" rx="2" ry="2" />
<text text-anchor="" x="13.00" y="203.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('fn:/tmp/richards.py (196 samples, 41.79%)')" onmouseout="c()" onclick="zoom(this)">
<title>fn:/tmp/richards.py (196 samples, 41.79%)</title><rect x="837.4" y="81" width="743.9" height="15.0" fill="rgb(251,36,51)" rx="2" ry="2" />
<text text-anchor="" x="840.38" y="91.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >fn:/tmp/richards.py</text>
</g>
<g class="func_g" onmouseover="s('isWaitingWithPacket:/tmp/richards.py (13 samples, 2.77%)')" onmouseout="c()" onclick="zoom(this)">
<title>isWaitingWithPacket:/tmp/richards.py (13 samples, 2.77%)</title><rect x="1581.3" y="81" width="49.3" height="15.0" fill="rgb(239,128,48)" rx="2" ry="2" />
<text text-anchor="" x="1584.26" y="91.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >isWa..</text>
</g>
<g class="func_g" onmouseover="s('addPacket:/tmp/richards.py (45 samples, 9.59%)')" onmouseout="c()" onclick="zoom(this)">
<title>addPacket:/tmp/richards.py (45 samples, 9.59%)</title><rect x="1220.7" y="49" width="170.8" height="15.0" fill="rgb(246,221,25)" rx="2" ry="2" />
<text text-anchor="" x="1223.70" y="59.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >addPacket:/tmp/richard..</text>
</g>
<g class="func_g" onmouseover="s('append_to:/tmp/richards.py (5 samples, 1.07%)')" onmouseout="c()" onclick="zoom(this)">
<title>append_to:/tmp/richards.py (5 samples, 1.07%)</title><rect x="1372.5" y="33" width="19.0" height="15.0" fill="rgb(227,152,5)" rx="2" ry="2" />
<text text-anchor="" x="1375.52" y="43.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" ></text>
</g>
<g class="func_g" onmouseover="s('entry_point:/tmp/richards.py (469 samples, 100.00%)')" onmouseout="c()" onclick="zoom(this)">
<title>entry_point:/tmp/richards.py (469 samples, 100.00%)</title><rect x="10.0" y="145" width="1780.0" height="15.0" fill="rgb(252,136,7)" rx="2" ry="2" />
<text text-anchor="" x="13.00" y="155.5" font-size="12" font-family="Verdana" fill="rgb(0,0,0)" >entry_point:/tmp/richards.py</text>
</g>
</svg>
"""
To create a flamegraph:
$ python -m scalene --json --no-browser --stacks --cpu-sampling-rate 0.001 richards.py
$ python foldstack.py profile.json | /tmp/FlameGraph/flamegraph.pl > flamegraph.html
"""
import sys
import json
def main():
fname = sys.argv[1]
with open(fname) as f:
data = json.load(f)
for frames, stats in data['stacks']:
count, py_time, c_time, cpu_samples = stats
lines = [f'{fn}:{filename}' for filename, fn, lineno in frames]
folded = ';'.join(lines)
print(f'{folded} {count}')
if __name__ == '__main__':
main()
"""
based on a Java version:
Based on original version written in BCPL by Dr Martin Richards
in 1981 at Cambridge University Computer Laboratory, England
and a C++ version derived from a Smalltalk version written by
L Peter Deutsch.
Java version: Copyright (C) 1995 Sun Microsystems, Inc.
Translation from C++, Mario Wolczko
Outer loop added by Alex Jacoby
"""
import time
# Task IDs
I_IDLE = 1
I_WORK = 2
I_HANDLERA = 3
I_HANDLERB = 4
I_DEVA = 5
I_DEVB = 6
# Packet types
K_DEV = 1000
K_WORK = 1001
# Packet
BUFSIZE = 4
BUFSIZE_RANGE = range(BUFSIZE)
class Packet(object):
def __init__(self, l, i, k):
self.link = l
self.ident = i
self.kind = k
self.datum = 0
self.data = [0] * BUFSIZE
def append_to(self, lst):
self.link = None
if lst is None:
return self
else:
p = lst
next = p.link
while next is not None:
p = next
next = p.link
p.link = self
return lst
# Task Records
class TaskRec(object):
pass
class DeviceTaskRec(TaskRec):
def __init__(self):
self.pending = None
class IdleTaskRec(TaskRec):
def __init__(self):
self.control = 1
self.count = 10000
class HandlerTaskRec(TaskRec):
def __init__(self):
self.work_in = None
self.device_in = None
def workInAdd(self, p):
self.work_in = p.append_to(self.work_in)
return self.work_in
def deviceInAdd(self, p):
self.device_in = p.append_to(self.device_in)
return self.device_in
class WorkerTaskRec(TaskRec):
def __init__(self):
self.destination = I_HANDLERA
self.count = 0
# Task
class TaskState(object):
def __init__(self):
self.packet_pending = True
self.task_waiting = False
self.task_holding = False
def packetPending(self):
self.packet_pending = True
self.task_waiting = False
self.task_holding = False
return self
def waiting(self):
self.packet_pending = False
self.task_waiting = True
self.task_holding = False
return self
def running(self):
self.packet_pending = False
self.task_waiting = False
self.task_holding = False
return self
def waitingWithPacket(self):
self.packet_pending = True
self.task_waiting = True
self.task_holding = False
return self
def isPacketPending(self):
return self.packet_pending
def isTaskWaiting(self):
return self.task_waiting
def isTaskHolding(self):
return self.task_holding
def isTaskHoldingOrWaiting(self):
return self.task_holding or (not self.packet_pending and self.task_waiting)
def isWaitingWithPacket(self):
return self.packet_pending and self.task_waiting and not self.task_holding
tracing = False
layout = 0
def trace(a):
global layout
layout -= 1
if layout <= 0:
print()
layout = 50
print(a, end='')
TASKTABSIZE = 10
class TaskWorkArea(object):
def __init__(self):
self.taskTab = [None] * TASKTABSIZE
self.taskList = None
self.holdCount = 0
self.qpktCount = 0
taskWorkArea = TaskWorkArea()
class Task(TaskState):
def __init__(self, i, p, w, initialState, r):
self.link = taskWorkArea.taskList
self.ident = i
self.priority = p
self.input = w
self.packet_pending = initialState.isPacketPending()
self.task_waiting = initialState.isTaskWaiting()
self.task_holding = initialState.isTaskHolding()
self.handle = r
taskWorkArea.taskList = self
taskWorkArea.taskTab[i] = self
def fn(self, pkt, r):
raise NotImplementedError
def addPacket(self, p, old):
if self.input is None:
self.input = p
self.packet_pending = True
if self.priority > old.priority:
return self
else:
p.append_to(self.input)
return old
def runTask(self):
if self.isWaitingWithPacket():
msg = self.input
self.input = msg.link
if self.input is None:
self.running()
else:
self.packetPending()
else:
msg = None
return self.fn(msg, self.handle)
def waitTask(self):
self.task_waiting = True
return self
def hold(self):
taskWorkArea.holdCount += 1
self.task_holding = True
return self.link
def release(self, i):
t = self.findtcb(i)
t.task_holding = False
if t.priority > self.priority:
return t
else:
return self
def qpkt(self, pkt):
t = self.findtcb(pkt.ident)
taskWorkArea.qpktCount += 1
pkt.link = None
pkt.ident = self.ident
return t.addPacket(pkt, self)
def findtcb(self, id):
t = taskWorkArea.taskTab[id]
if t is None:
raise Exception("Bad task id %d" % id)
return t
# DeviceTask
class DeviceTask(Task):
def __init__(self, i, p, w, s, r):
Task.__init__(self, i, p, w, s, r)
def fn(self, pkt, r):
d = r
assert isinstance(d, DeviceTaskRec)
if pkt is None:
pkt = d.pending
if pkt is None:
return self.waitTask()
else:
d.pending = None
return self.qpkt(pkt)
else:
d.pending = pkt
if tracing:
trace(pkt.datum)
return self.hold()
class HandlerTask(Task):
def __init__(self, i, p, w, s, r):
Task.__init__(self, i, p, w, s, r)
def fn(self, pkt, r):
h = r
assert isinstance(h, HandlerTaskRec)
if pkt is not None:
if pkt.kind == K_WORK:
h.workInAdd(pkt)
else:
h.deviceInAdd(pkt)
work = h.work_in
if work is None:
return self.waitTask()
count = work.datum
if count >= BUFSIZE:
h.work_in = work.link
return self.qpkt(work)
dev = h.device_in
if dev is None:
return self.waitTask()
h.device_in = dev.link
dev.datum = work.data[count]
work.datum = count + 1
return self.qpkt(dev)
# IdleTask
class IdleTask(Task):
def __init__(self, i, p, w, s, r):
Task.__init__(self, i, 0, None, s, r)
def fn(self, pkt, r):
i = r
assert isinstance(i, IdleTaskRec)
i.count -= 1
if i.count == 0:
return self.hold()
elif i.control & 1 == 0:
i.control //= 2
return self.release(I_DEVA)
else:
i.control = i.control // 2 ^ 0xd008
return self.release(I_DEVB)
# WorkTask
A = ord('A')
class WorkTask(Task):
def __init__(self, i, p, w, s, r):
Task.__init__(self, i, p, w, s, r)
def fn(self, pkt, r):
w = r
assert isinstance(w, WorkerTaskRec)
if pkt is None:
return self.waitTask()
if w.destination == I_HANDLERA:
dest = I_HANDLERB
else:
dest = I_HANDLERA
w.destination = dest
pkt.ident = dest
pkt.datum = 0
for i in BUFSIZE_RANGE: # range(BUFSIZE)
w.count += 1
if w.count > 26:
w.count = 1
pkt.data[i] = A + w.count - 1
return self.qpkt(pkt)
def schedule():
t = taskWorkArea.taskList
while t is not None:
if tracing:
print("tcb =", t.ident)
if t.isTaskHoldingOrWaiting():
t = t.link
else:
if tracing:
trace(chr(ord("0") + t.ident))
t = t.runTask()
class Richards(object):
def run(self, iterations):
for i in range(iterations):
taskWorkArea.holdCount = 0
taskWorkArea.qpktCount = 0
IdleTask(I_IDLE, 1, 10000, TaskState().running(), IdleTaskRec())
wkq = Packet(None, 0, K_WORK)
wkq = Packet(wkq, 0, K_WORK)
WorkTask(I_WORK, 1000, wkq, TaskState(
).waitingWithPacket(), WorkerTaskRec())
wkq = Packet(None, I_DEVA, K_DEV)
wkq = Packet(wkq, I_DEVA, K_DEV)
wkq = Packet(wkq, I_DEVA, K_DEV)
HandlerTask(I_HANDLERA, 2000, wkq, TaskState(
).waitingWithPacket(), HandlerTaskRec())
wkq = Packet(None, I_DEVB, K_DEV)
wkq = Packet(wkq, I_DEVB, K_DEV)
wkq = Packet(wkq, I_DEVB, K_DEV)
HandlerTask(I_HANDLERB, 3000, wkq, TaskState(
).waitingWithPacket(), HandlerTaskRec())
wkq = None
DeviceTask(I_DEVA, 4000, wkq,
TaskState().waiting(), DeviceTaskRec())
DeviceTask(I_DEVB, 5000, wkq,
TaskState().waiting(), DeviceTaskRec())
schedule()
if taskWorkArea.holdCount == 9297 and taskWorkArea.qpktCount == 23246:
pass
else:
return False
return True
def entry_point(iterations):
r = Richards()
startTime = time.time()
result = r.run(iterations)
endTime = time.time()
return result, startTime, endTime
def main(iterations=10):
print("Richards benchmark (Python) starting...")
result, startTime, endTime = entry_point(iterations)
if not result:
print("Incorrect results!")
return -1
total_s = endTime - startTime
print("Total time for %d iterations: %.2f secs" %(iterations,total_s))
print("Average time per iteration: %.2f ms" %(total_s*1000/iterations))
if __name__ == '__main__':
import sys
if len(sys.argv) >= 2:
main(iterations = int(sys.argv[1]))
else:
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment