Commits

Brian Burg committed dc7d398

In progress.

Comments (0)

Files changed (3)

addon/aboutgc.html

 </script>
 <link rel="stylesheet" href="stylesheet.css" />
 </head>
-<h1>About GC</h1>
-<div id="gc-timeline" />
-<div id="gc-time" />
+<h1>GC Timeline</h1>
+<div id="gc-timeline"></div>
+<h1><tt>sfink</tt>'s GC performance</h1>
+<div id="gc-time"></div>
 </body>
 </html>
 const Ci = Components.interfaces;
+const Cc = Components.classes;
 
-var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]  
-                   .getService(Components.interfaces.nsIWindowMediator);  
+const wm = Cc["@mozilla.org/appshell/window-mediator;1"]  
+    .getService(Ci.nsIWindowMediator);  
+
 var mainWindow = wm.getMostRecentWindow("navigator:browser");
 var gBrowser = mainWindow.gBrowser;
 
 // data points.
 var firstGCIndex = 0;
 
+const BYTES_PER_KB = Math.pow(2, 10);
+const BYTES_PER_MB = Math.pow(2, 20);
+const BYTES_PER_GB = Math.pow(2, 30);
+
+const MS_PER_SECOND = 1000;
+const MS_PER_MINUTE = MS_PER_SECOND * 1000;
+const MS_PER_HOUR = MS_PER_MINUTE * 60;
+
 function drawGraph() {
-    function format_KB(v, axis) {
-        return (v/1024).toFixed(axis.tickDecimals) + "KB";
+    function format_bytes(v, axis) {
+	var decimals = axis.tickDecimals || 3;
+
+	if (v < BYTES_PER_KB)
+            return v.toPrecision(decimals) + "B";
+	else if (v < BYTES_PER_MB)
+	    return (v/BYTES_PER_KB).toPrecision(decimals) + "KB";
+	else if (v < BYTES_PER_GB)
+	    return (v/BYTES_PER_MB).toPrecision(decimals) + "MB";
+	else
+	    return (v/BYTES_PER_GB).toPrecision(decimals) + "GB";
     }
 
     function format_ms(v, axis) {
-        return (v/1000).toFixed(axis.tickDecimals) + "ms";
+	var decimals = axis.tickDecimals || 0;
+        return (v/1000).toFixed(decimals) + "ms";
     }
     
-    function format_time(v, axis) {
-        return "+" + (v/1000).toFixed(3) + "ms";
+    function format_elapsed(v, axis) {
+	/* TODO: should be supplied with MS not uS */
+	var rem = v/1000;
+	var str = [];
+	
+	var decimals = ( (axis && axis.tickDecimals) ? axis.tickDecimals : 0 ) || 3;
+
+	if (rem > MS_PER_HOUR) {
+	    str.push("" + (rem - (rem % MS_PER_HOUR))/MS_PER_HOUR + "h");
+	    rem = rem % MS_PER_HOUR;
+	}
+	if (rem > MS_PER_MINUTE) {
+ 	    str.push("" + (rem - (rem % MS_PER_MINUTE))/MS_PER_MINUTE + "m");
+	    rem = rem % MS_PER_MINUTE;
+	}
+	if (rem > MS_PER_SECOND) {
+	    str.push((rem - (rem % MS_PER_SECOND))/MS_PER_SECOND + "s");
+	    rem = rem % MS_PER_SECOND;
+	}
+	if (str.length == 0) {
+	    str.push(rem.toPrecision(decimals) + "ms");
+	}
+
+	/* TODO: if less than a second total, use ms. if less than a
+	 * minute, use fractional seconds */
+
+        return str.join(" ");
     }
 
     // Construct a function that makes sure the ticks are in multiples of
         var i = item.dataIndex;
         return {
             'index': item.dataIndex + firstGCIndex,
-            'x': format_time(series[0].data[i][0], plot.getXAxes()[0]),
+            'x': format_elapsed(series[0].data[i][0], plot.getXAxes()[0]),
             'duration': format_ms(series[0].data[i][1], plot.getYAxes()[0]),
-            'freed': format_KB(series[1].data[i][1], plot.getYAxes()[1]),
+            'freed': format_bytes(series[1].data[i][1], plot.getYAxes()[1]),
             'dataIndex': item.dataIndex,
             'item': item
         };
 	return 0;
     }
 
-    var options = { yaxes: [ { 'min': 0,
-                               tickFormatter: format_ms,
-                               color: "olive",
-                             },
-                             { 'min': 0,
-                               position: 'right',
-                               tickFormatter: format_KB,
-                               ticks: tick_maker(100 * 1024, 10),
-                               color: "blue",
-                             },
-                           ],
-                    legend: { 'position': 'ne',
-                              'backgroundOpacity': 0.85,
-                              'backgroundColor': "yellow",
-                            },
-                    grid: {
-                        clickable: true,
-                    },
-                  };
+    function prepareTimelinePlot(dataArr) {
 
-    var graphdata = [ { data: [ [ d[0], d[1] ] for each (d in gcs) ],
-                        label: "GC Duration",
-                        clickable: true,
-                        color: "olive",
-                      },
-                      { data: [ [ d[0], d[2] ] for each (d in gcs) ],
-                        label: "Memory Freed (KB)",
-                        bars: { show: true, barWidth: 500000 },
-                        clickable: true,
-                        yaxis: 2,
-                        color: "blue",
-                      }
-                    ];
+	var heapSizeData = [];
+	var gcDurationMarks = [];
 
-    var plot = $.plot($("#gc-time"), graphdata, options);
+	for each (rec in dataArr) {
+	    /* generate heap size over time */
+	    heapSizeData.push([rec[0], rec[2]]);
+	    heapSizeData.push([rec[1], rec[3]]);
+
+	    /* generate gc time markings */
+	    gcDurationMarks.push({ xaxis: { from: rec[0], to: rec[0] }, color: '#dde' });
+	    gcDurationMarks.push({ xaxis: { from: rec[0], to: rec[1] }, color: '#eef' });
+	    gcDurationMarks.push({ xaxis: { from: rec[1], to: rec[1] }, color: '#dde' });
+	}
+
+	var options = { yaxes: [ { tickFormatter: format_bytes,
+				   color: 'purple',
+				 },
+			       ],
+			xaxes: [ { tickFormatter: format_elapsed,
+				 },
+			       ],
+			grid: {
+			    markings: gcDurationMarks
+			},
+		      };
+
+	var graphdata = [ { data: heapSizeData,
+			    label: "Heap Size",
+			    color: "blue",
+			  },
+			];
+
+	var postPlot = function(plot) {
+	    for each (rec in dataArr) {
+		var pt = plot.pointOffset({ x: (rec[0]+rec[1])/2, y: plot.getAxes().yaxis.max});
+		$('<div>' + format_elapsed(rec[1]-rec[0]) + '</div>')
+		    .css({ 'position': 'absolute',
+			   'top': '0px',
+			   '-moz-transform': 'rotate(-90deg) translateY(-1.8em) translateX(-15px)',
+			   'font-family': 'Verdana',
+			   'text-transform': 'capitalize',
+			   'font-size': '10px',
+			   'left': pt.left + 'px',
+			 })
+		    .appendTo(plot.getPlaceholder());
+	    }
+	}
+
+	return [graphdata, options, postPlot];
+    }
+
+    function preparePerfPlot(dataArr) {
+
+	var options = { yaxes: [ { 'min': 0,
+				   tickFormatter: format_ms,
+				   color: "olive",
+				 },
+				 { 'min': 0,
+				   position: 'right',
+				   tickFormatter: format_bytes,
+				   tickDecimals: 3,
+				   ticks: tick_maker(100 * 1024, 10),
+				   color: "blue",
+				 },
+                               ],
+			legend: { 'position': 'ne',
+				  'backgroundOpacity': 0.85,
+				  'backgroundColor': "yellow",
+				},
+			grid: {
+                            clickable: true,
+			},
+                      };
+	
+	var graphdata = [ { data: [ [ d[0], d[1] ] for each (d in dataArr) ],
+                            label: "GC Duration",
+                            clickable: true,
+                            color: "olive",
+			  },
+			  { data: [ [ d[0], d[2] ] for each (d in dataArr) ],
+                            label: "Memory Freed",
+                            bars: { show: true, barWidth: 500000 },
+                            clickable: true,
+                            yaxis: 2,
+                            color: "blue",
+			  }
+			];
+
+	return [graphdata, options];
+    }
+
+    /* actually plot/draw now */
+
+    [data, opts, postplot] = prepareTimelinePlot(gc1);
+    var timelinePlot = $.plot($("#gc-timeline"), data, opts);
+    postplot(timelinePlot);
+
+    [data, opts] = preparePerfPlot(gcs);
+    var perfPlot = $.plot($("#gc-time"), data, opts);
+
     var active = null;
     $("#gc-time").bind("plotclick", function (event, pos, item) {
         if (active) {
-            if (!item || active != item.dataIndex) {
-                plot.unhighlight(0, active);
-                plot.unhighlight(1, active);
+	    if (!item || active != item.dataIndex) {
+                perfPlot.unhighlight(0, active);
+                perfPlot.unhighlight(1, active);
                 $("#tooltip").remove();
-            }
+	    }
         }
         if (item) {
-            if (active != item.dataIndex) {
-                plot.highlight(0, item.dataIndex);
-                plot.highlight(1, item.dataIndex);
-                var d = getDatum(plot, item);
+	    if (active != item.dataIndex) {
+                perfPlot.highlight(0, item.dataIndex);
+                perfPlot.highlight(1, item.dataIndex);
+                var d = getDatum(perfPlot, item);
                 var content = "GC #" + d.index + " took " + d.duration + " and freed " + d.freed;
                 showTooltip(item.pageX + 10, item.pageY + 10, content);
-            }
-            active = item.dataIndex;
+	    }
+	    active = item.dataIndex;
         }
     });
+
 }
 /* legend:
  [ gcStart, gcEnd, heapSizeStart, heapSizeEnd ]+ */
 gc1 = [
-[2977962, 3113938, 937984, 9379840],
-[4820817, 5019834, 2600960, 26009600],
-[6476051, 6692174, 589824, 5898240],
-[6664707, 6910604, 528384, 5283840],
-[8964433, 9269324, 245760, 2457600],
-[11587905, 11907527, 995328, 9953280],
-[14095545, 14406248, 303104, 3031040],
-[16800688, 17184535, 868352, 8683520],
-[19355601, 19705268, 598016, 5980160],
-[20999396, 21398819, 385024, 3850240],
-[23725601, 24118909, 139264, 1392640],
-[26611804, 27036792, 221184, 2211840],
-[27454726, 27842409, 40960, 409600],
-[28626869, 29094382, 1220608, 12206080],
-[28942986, 29313983, 61440, 614400],
-[32038112, 32444354, 974848, 9748480],
-[33073048, 33518042, 1253376, 12533760],
-[34813620, 35253024, 65536, 655360],
-[36943821, 37331198, 1241088, 12410880],
-[39000899, 39407531, 974848, 9748480],
-[41619798, 42006548, 1216512, 12165120],
-[44164673, 44574661, 1241088, 12410880],
-[46147457, 46538225, 958464, 9584640],
-[46532652, 46946296, 974848, 9748480],
-[47101215, 47504071, 1241088, 12410880],
-[50103114, 50494506, 1421312, 14213120],
-[50727220, 51111553, 1241088, 12410880]
+[2977962, 3113938, 9379840, 8441856],
+[4820817, 5019834, 26009600, 23408640],
+[6476051, 6692174, 5898240, 5308416],
+[6664707, 6910604, 5283840, 4755456],
+[8964433, 9269324, 2457600, 2211840],
+[11587905, 11907527, 9953280, 8957952],
+[14095545, 14406248, 3031040, 2727936],
+[16800688, 17184535, 8683520, 7815168],
+[19355601, 19705268, 5980160, 5382144],
+[20999396, 21398819, 3850240, 3465216],
+[23725601, 24118909, 1392640, 1253376],
+[26611804, 27036792, 2211840, 1990656],
+[27454726, 27842409, 409600, 368640],
+[28626869, 29094382, 12206080, 10985472],
+[28942986, 29313983, 614400, 552960],
+[32038112, 32444354, 9748480, 8773632],
+[33073048, 33518042, 12533760, 11280384],
+[34813620, 35253024, 655360, 589824],
+[36943821, 37331198, 12410880, 11169792],
+[39000899, 39407531, 9748480, 8773632],
+[41619798, 42006548, 12165120, 10948608],
+[44164673, 44574661, 12410880, 11169792],
+[46147457, 46538225, 9584640, 8626176],
+[46532652, 46946296, 9748480, 8773632],
+[47101215, 47504071, 12410880, 11169792],
+[50103114, 50494506, 14213120, 12791808],
+[50727220, 51111553, 12410880, 11169792]
 
 ];