Skip to content

Instantly share code, notes, and snippets.

@simonlindholm
Created June 5, 2012 23:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save simonlindholm/2878765 to your computer and use it in GitHub Desktop.
Save simonlindholm/2878765 to your computer and use it in GitHub Desktop.
Firebug profiling code (for issue 1309)
/**
* Time execution of a piece of code, with a user-provided number 'iterations'
* of samples (>= 0), or if 'iterations' is null, just one.
*/
timeExecution = function(context, code, iterations)
{
var userGiven = true;
if (iterations === null)
{
userGiven = false;
iterations = 1;
}
// In FF15 and up, performance.now() provides submillisecond precision;
// for older versions we will have to fall back to Date.now().
var precise = ("performance" in window && "now" in window.performance);
// Build up JavaScript code that evaluates and times 'code'.
var getTimingCode = function(code)
{
var nowF = (precise ? "performance.now()" : "Date.now()");
var ret = "{ ";
var timingOverhead = "0";
if (precise)
{
// Warm up timer/JavaScript engine. (This helps a tiny bit, I
// think. Can't hurt, at least.)
ret += [nowF, nowF].join("; ") + "; ";
ret += "document.getElementById('dummy'); ";
// performance.now() takes some time to run (~0.02ms on my machine);
// thus, save some consecutive timings so we can account for that.
// The actual overhead fluctuates, so use the most reasonable value.
ret += "let __fbt0, __fbt1, __fbt2, __fbt3; ";
ret += "__fbt0 = " + nowF + "; try {} finally { if (__fbt1 = " + nowF + ") {} } ";
ret += "__fbt2 = " + nowF + "; try {} finally { if (__fbt3 = " + nowF + ") {} } ";
timingOverhead = "Math.min(__fbt3 - __fbt2, __fbt1 - __fbt0)";
}
ret += "let __fbT0, __fbT1; __fbT0 = " + nowF + "; ";
// Add a default return value, to avoid printing a random float if
// the evaluated code lacks statements.
ret += "void 0; ";
// Actually evaluate the code.
ret += "try {\n" + code + "\n} finally {\n";
// Save the time taken in window.__fbTiming. To retain the last
// evaluated value for display, wrap the timing calculation/
// assignment in an expression.
ret += "if (__fbT1 = " + nowF + ", window.__fbTiming = (__fbT1 - __fbT0) - " + timingOverhead + ") {} ";
ret += "} }";
return ret;
};
var win = (context.baseWindow ? context.baseWindow : context.window);
var timeCode = getTimingCode(code);
var times = [], resArgs;
for (var i = 0; i < iterations; ++i)
{
var save = function() { resArgs = arguments; };
Firebug.CommandLine.evaluate(timeCode, context, context.thisValue,
win, save, save);
// Get the timing out from the global.
var timing = NaN;
try
{
timing = +win.wrappedJSObject.__fbTiming;
delete win.wrappedJSObject.__fbTiming;
}
catch (e) {}
times.push(timing);
// In case of e.g. syntax errors, we have no data to display. Just
// print the last result/error.
if (isNaN(timing))
{
Firebug.Console.log.apply(Firebug.Console, resArgs);
return;
}
}
// Print the result of the last iteration.
Firebug.Console.log.apply(Firebug.Console, resArgs);
if (precise && ((times.length >= 5 && times[0] < 0.2) ||
(times.length >= 10 && times[0] < 1.0)))
{
// The first ~3 results are slightly too high, on my machine. Throw
// them away.
times.splice(0, 3);
}
if (times.length >= 10)
{
// We have enough data to be able to throw out outliers.
var edge = Math.floor(times.length * 0.2);
times.sort(function(a, b) { return a - b; });
times = times.slice(edge, -edge);
}
// Calculate a simple average. If it is negative (from incorrect timing
// overhead correction - most commonly from timing something empty),
// show it as 0 instead.
var average = 0;
for (var i = 0; i < times.length; ++i)
average += times[i];
average /= times.length;
if (average < 0)
average = 0;
// Truncate the result to 2 decimals, or more for more iterations.
var decimals = (precise ? 2 : 0);
for (var order = 2; order <= iterations; order *= 10)
++decimals;
var str = average.toFixed(decimals);
if (userGiven)
str = Locale.$STRF("commandline.TimeUsageAverage", [str, iterations]);
else
str = Locale.$STRF("commandline.TimeUsage", [str]);
Firebug.Console.logFormatted([str], context, "log");
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment