Ori.livneh has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/248561

Change subject: Update flamegraph.pl to brendangregg/Flamegraph@182b24f
......................................................................

Update flamegraph.pl to brendangregg/Flamegraph@182b24f

Changes:

* 182b24fb63: Ctrl-F to search
* b26eda56a8: show matched percent
* 4c821b895f: improve code, reduce SVG size
* 71e5a78e83: Fix search to work if the nameattr href is being used
* 2ee18074bc: search
* 044f09b9d5: add --help option, URLs, and update major history
* f18bcca92d: Fix quoting in mouseover
* 996ef3c9d3: flamegraph.pl: fixed the delta percentage's sign when --negate is 
specified.

Change-Id: Ieceaa846de557ab29c534398bd92120b7211a3d2
---
M modules/xenon/files/flamegraph.pl
1 file changed, 201 insertions(+), 27 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/operations/puppet 
refs/changes/61/248561/1

diff --git a/modules/xenon/files/flamegraph.pl 
b/modules/xenon/files/flamegraph.pl
index def5ed0..bf00a04 100755
--- a/modules/xenon/files/flamegraph.pl
+++ b/modules/xenon/files/flamegraph.pl
@@ -10,6 +10,9 @@
 #
 #        grep funcA input.txt | ./flamegraph.pl [options] > graph.svg
 #
+# Then open the resulting .svg in a web browser, for interactivity: mouse-over
+# frames for info, click to zoom, and ctrl-F to search.
+#
 # Options are listed in the usage message (--help).
 #
 # The input is stack frames and sample counts formatted as single lines.  Each
@@ -66,6 +69,7 @@
 #
 # CDDL HEADER END
 #
+# 11-Oct-2014  Adrien Mahieux  Added zoom.
 # 21-Nov-2013   Shawn Sterling  Added consistent palette file option
 # 17-Mar-2013   Tim Bunce       Added options and more tunables.
 # 15-Dec-2011  Dave Pacheco    Support for frames with whitespace.
@@ -101,6 +105,33 @@
 my $titletext = "";             # centered heading
 my $titledefault = "Flame Graph";      # overwritten by --title
 my $titleinverted = "Icicle Graph";    #   "    "
+my $searchcolor = "rgb(230,0,230)";    # color for search highlighting
+my $help = 0;
+
+sub usage {
+       die <<USAGE_END;
+USAGE: $0 [options] infile > outfile.svg\n
+       --title       # change title text
+       --width       # width of image (default 1200)
+       --height      # height of each frame (default 16)
+       --minwidth    # omit smaller functions (default 0.1 pixels)
+       --fonttype    # font type (default "Verdana")
+       --fontsize    # font size (default 12)
+       --countname   # count type label (default "samples")
+       --nametype    # name type label (default "Function:")
+       --colors      # set color palette. choices are: hot (default), mem, io,
+                     # java, js, red, green, blue, yellow, purple, orange
+       --hash        # colors are keyed by function name hash
+       --cp          # use consistent palette (palette.map)
+       --reverse     # generate stack-reversed flame graph
+       --inverted    # icicle graph
+       --negate      # switch differential hues (blue<->red)
+       --help        # this message
+
+       eg,
+       $0 --title="Flame Graph: malloc()" trace.txt > graph.svg
+USAGE_END
+}
 
 GetOptions(
        'fonttype=s'  => \$fonttype,
@@ -122,27 +153,9 @@
        'reverse'     => \$stackreverse,
        'inverted'    => \$inverted,
        'negate'      => \$negate,
-) or die <<USAGE_END;
-USAGE: $0 [options] infile > outfile.svg\n
-       --title       # change title text
-       --width       # width of image (default 1200)
-       --height      # height of each frame (default 16)
-       --minwidth    # omit smaller functions (default 0.1 pixels)
-       --fonttype    # font type (default "Verdana")
-       --fontsize    # font size (default 12)
-       --countname   # count type label (default "samples")
-       --nametype    # name type label (default "Function:")
-       --colors      # set color palette. choices are: hot (default), mem, io,
-                     # java, js, red, green, blue, yellow, purple, orange
-       --hash        # colors are keyed by function name hash
-       --cp          # use consistent palette (palette.map)
-       --reverse     # generate stack-reversed flame graph
-       --inverted    # icicle graph
-       --negate      # switch differential hues (blue<->red)
-
-       eg,
-       $0 --title="Flame Graph: malloc()" trace.txt > graph.svg
-USAGE_END
+       'help'        => \$help,
+) or usage();
+$help && usage();
 
 # internals
 my $ypad1 = $fontsize * 4;      # pad top, include title
@@ -195,6 +208,7 @@
 <?xml version="1.0"$enc_attr 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="$w" height="$h" onload="init(evt)" viewBox="0 0 $w 
$h" 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. -->
 SVG
        }
 
@@ -582,13 +596,33 @@
 </style>
 <script type="text/ecmascript">
 <![CDATA[
-       var details, svg;
+       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;
        }
-       function s(info) { details.nodeValue = "$nametype " + info; }
-       function c() { details.nodeValue = ' '; }
+
+       // mouse-over for info
+       function s(node) {              // show
+               info = g_to_text(node);
+               details.nodeValue = "$nametype " + 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++) {
@@ -607,6 +641,16 @@
                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 (func != null)
+                       func = func.replace(/ .*/, "");
+               return (func);
        }
        function update_text(e) {
                var r = find_child(e, "rect");
@@ -634,6 +678,8 @@
                }
                t.textContent = "";
        }
+
+       // zoom
        function zoom_reset(e) {
                if (e.attributes != undefined) {
                        orig_load(e, "x");
@@ -742,6 +788,129 @@
                        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 =
+                                   "$searchcolor";
+
+                               // 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;
+                       if (a < b || a > b)
+                               return a - b;
+                       return matches[b] - matches[a];
+               });
+               // 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.
+               for (var k in keys) {
+                       var x = parseFloat(keys[k]);
+                       var w = matches[keys[k]];
+                       if (x >= lastx + lastw) {
+                               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>
 INC
@@ -757,6 +926,9 @@
 $im->stringTTF($black, $fonttype, $fontsize, 0.0, $xpad, $imageheight - 
($ypad2 / 2), " ", "", 'id="details"');
 $im->stringTTF($black, $fonttype, $fontsize, 0.0, $xpad, $fontsize * 2,
     "Reset Zoom", "", 'id="unzoom" onclick="unzoom()" 
style="opacity:0.0;cursor:pointer"');
+$im->stringTTF($black, $fonttype, $fontsize, 0.0, $imagewidth - $xpad - 100,
+    $fontsize * 2, "Search", "", 'id="search" onmouseover="searchover()" 
onmouseout="searchout()" onclick="search_prompt()" 
style="opacity:0.1;cursor:pointer"');
+$im->stringTTF($black, $fonttype, $fontsize, 0.0, $imagewidth - $xpad - 100, 
$imageheight - ($ypad2 / 2), " ", "", 'id="matched"');
 
 if ($palette) {
        read_palette();
@@ -794,18 +966,20 @@
                $escaped_func =~ s/&/&amp;/g;
                $escaped_func =~ s/</&lt;/g;
                $escaped_func =~ s/>/&gt;/g;
+               $escaped_func =~ s/"/&quot;/g;
                unless (defined $delta) {
                        $info = "$escaped_func ($samples_txt $countname, 
$pct%)";
                } else {
-                       my $deltapct = sprintf "%.2f", ((100 * $delta) / 
($timemax * $factor));
-                       $deltapct = $delta > 0 ? "+$deltapct" : $deltapct;
+                       my $d = $negate ? -$delta : $delta;
+                       my $deltapct = sprintf "%.2f", ((100 * $d) / ($timemax 
* $factor));
+                       $deltapct = $d > 0 ? "+$deltapct" : $deltapct;
                        $info = "$escaped_func ($samples_txt $countname, $pct%; 
$deltapct%)";
                }
        }
 
        my $nameattr = { %{ $nameattr{$func}||{} } }; # shallow clone
        $nameattr->{class}       ||= "func_g";
-       $nameattr->{onmouseover} ||= "s('".$info."')";
+       $nameattr->{onmouseover} ||= "s(this)";
        $nameattr->{onmouseout}  ||= "c()";
        $nameattr->{onclick}     ||= "zoom(this)";
        $nameattr->{title}       ||= $info;

-- 
To view, visit https://gerrit.wikimedia.org/r/248561
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ieceaa846de557ab29c534398bd92120b7211a3d2
Gerrit-PatchSet: 1
Gerrit-Project: operations/puppet
Gerrit-Branch: production
Gerrit-Owner: Ori.livneh <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to