2010-09-19

Comfy browser performance testing

I have been poking around with some performance tests and profiling lately, first with Steve Souders' Browserscope, which gets the job done, at some convenience cost of setting up a publicly hosted web page and tying it to a Google account (that you might have to first create), and, for loading performance, different ways of organizing script tags, images, iframes, style sheets and so on, Cuzillion, by same author.

Today, I found and toyed around a bit with jsperf.com by Mathias Bynens, which does much of the boring setup job for you, when it comes to micro-benchmarking some snippet of javascript versus another, assuming the thing you want to test is synchronous, and doesn't involve complex preconditions. (I wonder what makes Array copying using a saved Array.prototype.slice significantly slower than the other more evenly performance-matched variants?) As should always be stated when mentioning benchmarks and optimization, this kind of micro-benchmarking is less relevant than finding your code's hot spots and picking better algorithms where relevant. That said, it's still academic fun to play with this kind of thing.

For this kind of small test, jsperf.com does all the Browserscope setup work for you, and lets others improve (fork) your test after the fact, adding versions you didn't think of yourself that do the same thing. I have a vague plan of trying to make it run some performance tests for a little code snippet I wrought up recently that does a deep copy of a nested (JSON:able) structure from a parent window where there may be crud on Object.prototype (the code should run in an iframe free of such), to benchmark vs a mere JSON.parse(JSON.stringify(taintedObject), which would also clean away the crud:

var _slice = [].slice, _toString = Object.prototype.toString;
function array(arrayish) {
  return _slice.call(arrayish, 0);
}

function isArray(obj) {
  return '[object Array]' === _toString.call(obj);
}

// Take a nested structure from a hostile window (presumably full of crap in its
// Object.prototype, et cetera) and return a cleaned-up version with this window
// object's (pure) Array and Object constructors.
function deepClone(obj) {
  if ('object' !== typeof obj) return obj;
  if (null === obj) return null;
  if (isArray(obj)) return array(obj).map(deepClone);
  var clean = {};
  for (var key in obj)
    if (obj.hasOwnProperty(key))
      clean[key] = deepClone(obj[key]);
  return clean;
}

What surprised me about the above code, when testing it on the kinds of payloads it would typically handle (data somewhat heavy on largeish strings), was that it actually was a bit faster than using the browser native JSON codecs, whereas, for larger inputs, native code always won out. Sometimes you just have to test stuff, to find out what wins.

2010-09-13

JSONView with copy & paste support

Last weekend I picked up Ben Hollis' JSONView extension to tinker it to keep JSON viewed through it copy-and-paste:able, both as a whole and in part. It was rather fun work and within some few hours I had a patch that did the trick, and a few other ones to boot:



I sent Ben a patch, but not having heard anything back, I figured I might as well share the results here too, as it's all MIT licensed goodness (as is my patched version, of course). You can either download an installable xpi build, or fork my repository from github.

My edits are all on a branch named after my github user -- a practice I can recommend, when mirroring some svn upstream repository (with git-svn, for instance); it simplifies the process of tracking vendor updates to a mere git svn rebase on master (for you -- git-svn, sadly, is not able to push its metadata about the non-git upstream to github) and lets other people reuse your pristine vendor branch for their own purposes.

Enjoy your easier-to-handle JSON! I guess next step would be to integrate these improvements into the Chrome fork Jamie Wilkinson is maintaining. Any takers?

2010-08-23

Friendlier github commits pages

I figured I should announce the news of a much improved github commits page I have been tinkering with for a while, that lets you unfold full details about commits (individually, or in batch) without leaving the page. A screenshot of what the Greasemonkey master branch commits might look like with a few unfolded:

screenshot of github commits page with the user script active

Usage is intuitive; just click anywhere in a commit that isn't already a link, and the commit will load in place (unless already loaded) and unfold its whole changeset, or refold itself again, when clicked a second time. Similarly, individual files changed can be folded and unfolded much the same way, though only by clicking their headers (I often want to copy and paste stuff from diffs, so no click magic there). To unfold or refold every commit on the page, either hit "f", or click the "(un)fold all commits" link at the top or bottom right of the page.

This user script (install link, userscript.org page with docs and complete change log) is incidentally compatible with extensions like AutoPagerize too, in case you prefer scrolling for content to finding and clicking "Older" (h) and "Newer" (l). And if you just want to try it out without installing anything, try this bookmarklet on any github commits page.

And it's all done by a hundred lines of jQuery, about a dozen lines of css and another dozen lines of Greasemonkey / Chrome portability code that breaks out of their respective sandbox environments to run what the script needs to run in the context of the web page itself.

That latter piece is useful too, by the way, modeled on a trick Anthony Lieuallen came up with for the Greasemonkey wiki at some point. This is what it looks like, including full docs:


The above-referred jQuery is already loaded by github's page template, so I don't need to bother grabbing or shipping one of my own. If you are hacking a more hostile site, and run Greasemonkey you might want to add a // @require http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js line to your script header instead (I haven't tested, but if you try to run jQuery in the mozilla javascript sandbox anything beyond really basic stuff fails due to the common pitfalls that jQuery, sanely, does not much attempt to evade).

All above code is freely poachable (read: MIT license) at github, with as much or little attribution as you like. I would of course be especially happy to see the github people adopt this for their default page templates, as it's really useful stuff. Share and enjoy!