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'>&hellip; </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"); });