lib/flamegraph/flamegraph.html in flamegraph-0.0.5 vs lib/flamegraph/flamegraph.html in flamegraph-0.0.6
- old
+ new
@@ -5,26 +5,75 @@
<meta charset=utf-8 />
<title>Flame Graph of Page</title>
<style>
- .info {height: 40px;}
+ .info {min-height: 50px; margin: 10px; }
.legend div {
display: block;
float: left;
width: 150px;
margin: 0 8px 8px;
padding: 4px;
height: 50px;
}
+ .code {
+ font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace;
+ }
+ #frameinfo table .sample-info {
+ width: 200px;
+ color: #333;
+ font-size: 12px;
+ }
+ #frameinfo table {
+ border-collapse: collapse;
+ }
+ #frameinfo table tr {
+ border-bottom: 1px solid #eee;
+ margin-top: 5px;
+ }
+ #frameinfo td {
+ padding: 5px;
+ }
+ #frameinfo-wrapper {
+ position: fixed;
+ z-index: 1;
+ opacity: 0.7;
+ background-color: black;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ display: none;
+ }
+ #frameinfo {
+ position: fixed;
+ padding: 10px;
+ z-index: 2;
+ opacity: 1.0;
+ top: 0;
+ margin-top: 50px;
+ margin-left: 40px;
+ width: 80%;
+ height: 80%;
+ background-color: white;
+ border: 2px solid #666;
+ display: none;
+ overflow: auto;
+ }
</style>
</head>
<body>
<div class="graph"></div>
- <div class="info"></div>
+ <div class="info code"></div>
<div class="legend"></div>
-
+ <div id="frameinfo-wrapper"></div>
+ <div id="frameinfo">
+ <h3>Frame Info</h3>
+ <table>
+ </table>
+ </div>
<script>
var data = /**DATA**/;
var maxX = 0;
var maxY = 0;
@@ -82,11 +131,16 @@
}
var guessMethod = function(frame) {
var split = frame.split('`');
if(split.length == 2) {
- return split[1].split("'")[0];
+ var fullMethod = split[1].split("'")[0];
+ split = fullMethod.split("#");
+ if(split.length == 2) {
+ return split[1];
+ }
+ return split[0];
}
return '?';
}
var guessFile = function(frame) {
@@ -99,11 +153,11 @@
}
$.each(data, function(){
maxX = Math.max(maxX, this.x + this.width);
maxY = Math.max(maxY, this.y);
- this.shortName = /* guessGem(this.frame) + " " + guessFile(this.frame) + " " */ guessMethod(this.frame);
+ this.shortName = guessMethod(this.frame);
});
var width = $(window).width();
var height = $(window).height() / 1.2;
@@ -192,10 +246,91 @@
$('.info').text("");
d3.selectAll(i.nodes)
.attr('opacity',1);
};
+var backtrace = function(frame){
+ for(var i=0; i<data.length; i++){
+ if(frame === data[i]){ break; }
+ }
+
+ frames = [frame];
+ var depth = frame.y;
+
+ while(i > 0){
+ if(depth == -1) break;
+
+ if(data[i].y === depth-1) {
+ frames.push(data[i]);
+ depth--;
+ }
+
+ i--;
+ }
+
+ return frames;
+}
+
+$('#frameinfo-wrapper').click(function(d){
+ $(this).hide();
+ $('#frameinfo').hide();
+});
+
+var click = function(d){
+ var trace = backtrace(d);
+
+ var link = function(path, dest){
+ return path.replace(/[^\/]+:\d+/, function(x){ return "<a target='_blank' href='"+ dest +"'>" + x + "</a>"})
+ };
+
+ var linkify = function(path){
+ var split = path.split("/")[0].split("-");
+ if(["activerecord","actionpack","railties","activesupport", "rails"].indexOf(split[0]) > -1) {
+ var github = "https://github.com/rails/rails/blob/";
+ var file = path.split(":")[0].split("/");
+ if(split[0] === "rails") {
+ file.shift();
+ } else {
+ file[0] = split[0];
+ }
+
+ github += (split[1].length < 6 ? "v" : "") + split[1] + "/";
+ github += file.join("/");
+ github += "#L" + parseInt(path.split(":")[1]);
+
+ return link(path, github);
+ }
+ return path;
+ }
+
+ var simplify = function(frame){
+ var split = frame.split('/gems/');
+ if(split.length > 1){
+ var path = linkify(split.pop());
+ return "<span class='full-location'>" + split.join('/gems/') + "/</span>" + path;
+ } else {
+ return frame;
+ }
+ }
+
+ var table = trace.map(function(f){
+ var i = info[f.frame];
+ return "<tr><td class='code'>" + simplify(f.frame) + "</td><td class='sample-info'>" +
+ samplePercent(i.samples.length, f.topFrame ? f.topFrame.exclusiveCount : 0) +
+ "</td></tr>";
+ }).join("\n");
+
+ var table = $('#frameinfo table').html(table);
+ table.find(".full-location").hide().after("<span class='expand'>… </span>");
+ table.find(".expand").css({cursor: "pointer"}).click(function(){
+ $(this).hide().parent().find(".full-location").show();
+ });
+
+ $('#frameinfo-wrapper').show();
+ $('#frameinfo').show();
+};
+
// http://stackoverflow.com/a/7419630
var rainbow = function(numOfSteps, step) {
// This function generates vibrant, "evenly spaced" colours (i.e. no clustering). This is ideal for creating easily distiguishable vibrant markers in Google Maps and other apps.
// Adam Cole, 2011-Sept-14
// HSV to RBG adapted from: http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
@@ -289,11 +424,11 @@
var word = d.shortName; // words[0];
var width = xScale(d.width+100);
var height = yScale(1);
var length = 0;
d3.select(this).style("font-size", size + "px").text(word);
- while(((this.getBBox().width >= width) || (this.getBBox().height >= height)) && (size > 12))
+ while((size > 12.1) && ((this.getBBox().width >= width) || (this.getBBox().height >= height)))
{
size -= 0.1;
d3.select(this).style("font-size", size + "px");
}
@@ -321,18 +456,22 @@
i.samples.push(d.x + j);
}
return i.color;
})
.on("mouseover", mouseover)
- .on("mouseout", mouseout);
+ .on("mouseout", mouseout)
+ .on("click", click)
+ .attr("cursor", "pointer");
d3.select(this)
.append("text")
.attr("x",function(d) { return xScale(d.x - 0.98); })
.attr("y",function(d) { return yScale(maxY - d.y);})
.on("mouseover", mouseover)
.on("mouseout", mouseout)
+ .on("click", click)
.each(fontSize)
+ .attr("cursor", "pointer")
.attr("display", "none");
});