21
Jan 10

State of Static Analysis At Mozilla

Mozilla has static analyses built into the buildsystem that can be turned on with –with-static-checking= flag. The analyses live in xpcom/analyses directory. The testcases (aka documentation) are in xpcom/tests/static-checker. Analyses are implemented in either Dehydra or Treehydra and run within a patched GCC 4.3.

The currently landed checks are:

  • final.js: Java-like “final” keyword for C++
  • flow.js: Ensure code in a function flows through a particular label
  • must-override.js: Force derived classes to override certain methods
  • override.js: Ensure methods exist in base class
  • outparams.js: Ensure outparameters and return error codes are in sync
  • stack.js: Mark classes as stack-only

A whole lot more analyses in various states of completion can be tracked in the static analysis bug.

Asynchronous discussion happens in the mailing list. #static irc channel is the place for interactive discussion.

Nearterm Plans For Plugins

GCC 4.5 has an official plugin framework enabled by default. I will try to switch to GCC 4.5 as soon as it is out. Currently 4.5 is still changing too often for me to bother fixing Treehydra (Dehydra usually works). As soon as 4.5 is out I will revise the installation instructions to use distribution GCC and JavaScript packages to avoid the current mess (draft can be found here). Sometime after that I’ll switch Mozilla static analysis to GCC 4.5 and drop 4.3 support.

Hopefully, this will make it easier for other open source projects to adapt the hydras.

Plans for Analyses

I’m a big believer into application-specific static analyses, but I would like to see some heavy duty open source analyzers built on top of GCC.

Some of the not-so-Mozilla-specific analyses should be bundled together to make them easy to try out on other projects.

Hopefully 2010 will be the year that open source static analysis catches on.

LCA2010

I posted my slides from yesterday.


19
Jan 10

Chromium vs Minefield: Cold startup performance comparison

Hunting Down Mythical “Slowness”

I recently met a developer who used Chromium instead of Firefox. Chromium’s superior startup speed was his reason for using it.This got me excited because said developer was running Linux, so it was relatively easy to measure cold startup and get a complete IO breakdown.

Turned out Firefox took roughly 23 seconds to start. After much cursing about how I’ve never seen Firefox startup this slow, I eventually gave up on figuring out what’s slowing his startup and instead we measured Chromium startup. It also turned out to also be roughly 23 seconds. The super-slow hard drive made everything slow. Turned out Chromium’s superior startup was a myth in this case.

Measuring Startup

As a result of investigating the startup myth above, my kiwi coworkers encouraged me to post a comparison of Chrome/Firefox startup. I am at linuxconf at the moment so I did the comparison on my laptop.

Laptop configuration:

  • Intel(R) Core(TM)2 Duo CPU  L9400 running at 800Mhz to amplify any performance differences.
  • HITACHI HTS722020K9SA00 harddrive for the user profile and browser binaries
  • OCZ Vertex 30GB SSD for system libraries/configuration.
  • Fedora 12, Minefield 20100119 tarball, chromium-4.0.285.0-0.1.20091230svn35370.fc12.i686
  • sudo sync && sudo sysctl -w vm.drop_caches=3 && sudo sysctl -w vm.drop_caches=0 to clear the disk cache inbetween runs

What am I testing? I am measuring the time between invoking the browser until a JavaScript snippet embedded within a basic webpage is executed (ie Vlad’s approach, with a slightly modified startup.html). The above sysctl command clears disk caches, this creates a similar situation to when one turns on the computer and it hasn’t yet loaded all of the browser libraries from disk into memory. This is a blackbox approach to measuring how long it takes from clicking on the browser icon to get an interactive browser.

Firefox commandline: firefox -profile /mnt/startup/profile/firefox  -no-remote file://`pwd`/startup.html#`python -c ‘import time; print int(time.time() * 1000);’`

Chromium commandline: chromium-browser –user-data-dir=/mnt/startup/profile/chrome  file://`pwd`/startup.html#`python -c ‘import time; print int(time.time() * 1000);’`

Both of these tests are done with an empty profile that was populated and has settled after running the browser a few times.

Results

The following numbers are milliseconds reported by the startup.html above.

Running Chromium five times: 4685, 4168, 4222, 4197, 4232

Running Minefield five times: 3155, 3273, 3352, 3311, 3322

I picked Minefield because that’s the browser that I run and the codebase that I focus on. The linux Chromium channel seems to be the closest parallel to Minefield. I did not test on Windows because it is a bit of a nightmare to measure cold startup there.

Conclusion

On my system Minefield is around 30% faster at starting up with  an empty profile than Chromium (the difference is amplified by running the CPU at 800Mhz). For comparison of Minefield against older Firefox versions, see Dietrich’s post.

I suspect that there is a relatively small difference between the two browsers because we are running into the fundamental limitations of loading large applications into memory (my rant).


04
Jan 10

Some developers manually grope around in the dark

Cool thing about static analysis is that you can ask painful-for-humans questions about your codebase AND have them answered.
Here are two that got answered by Ehren:

Where do function bodies continue after return statements (ie obviously dead/broken code)? Bug 535646.

How many functions in Mozilla could/should be marked static? Bug 536427.

Awesome!


04
Jan 10

Windows 7 Startup Exploration

I did some digging to figure out if one can setup cold-startup testing in Windows 7 without nasty hacks. My conclusion is: sorta-kinda.

The Good – Most of the Ingredients Are Present

I haven’t actively used Windows since pre-XP days. It looks like it has come a long way since then: there is now a decent interactive shell, all kinds of settings/services can be controlled from the commandline and there is even sudo-like functionality.

PowerShell takes inspiration from the korn shell and throws in .net which allows for much nicer “shell programming” than the dominant bash shell.

mountvol is a terrible equivalent to mount in linux – but it exists, so I’m happy.

NTFS junctions are frustrating equivalents to links in a unix filesystem.

The Bad

The essential ability to completely flush filesystem caches isn’t there. This isn’t quite as embarrassing as it seems as Mac OS X’s purge command does not flush the page cache (resulting in mmapped files not purged from cache), so technically OS X has the same limitation and only Linux gets it right.

The Ugly Workaround

After much brainstorming we figured out that we can clear all relevant caches on Mac OS X by putting files that we care about on a separate partition and mounting/unmounting it for every measurement.

Ridiculously, Windows is “smarter” than that and appears to cache stuff per-drive, such that mounting/unmounting a partition has no effect on the cache. The best workaround I could come up with involves putting the said partition onto a USB disk and unplugging it in-between unmount/mount testing cycle.

Windows 7 Startup Recipe

1) Set up junctions for the 2 profile directories to point to the USB partition, unzip firefox onto that partition.

2)
$old = (get-location)
$mountpoint = $env:userprofile + "\cold"
# magic name given by running mountvol
$drive = "\\?\Volume{885d5bc3-e918-11de-a4e5-002268e3077c}\"
# Based on http://poshcode.org/696 + fiddling with UAC settings to avoid prompts
sudo mountvol $mountpoint $drive
# Mountvol doesn't seem to block until drive is mounted
sleep 1
#mountvol
cd $mountpoint\firefox
echo (pwd)
# The following command shows PowerShell awesomeness
# based on Vlad's approach
./firefox.exe -no-remote "file://$(pwd)\startup.html#$([Int64](([DateTime]::utcnow - (new-object DateTime 1970,1,1)).ticks/10000))"
cd $old
# I haven't yet figured out how to wait on firefox.exe to finish
sleep 10
sudo mountvol $mountpoint /d

3) Unplug USB drive