April 14, 2010

No. More. Downtime. Damn it.

Things have been a little shakier with our new online performance scanning service the last 2 days then we would have liked. And while we have an amazing team none come from an operations background. This makes managing and maintaining an always-on, always-in-use system a painful learning experience. Case in point: yesterday was Microsoft’s Patch Tuesday. Like the smart, security-minded folks that we are (who want to avoid the painful Exploit Wednesday), we have Windows automatic updates turned on for our scanning server. Oh wait, doesn’t automatic update mean a system reboot? Oh crap, when it reboots at 3:00am, will our scanning software come back up? Hmmm. Looks like no. Hence some unplanned downtime.

We apologize for the availability issues over the last few days, first with our hosting provider and then with our systems. In some ways having availability issues is a good thing: it means enough people know about you and are using you that they notice when you aren’t there. Of course, the much more painful downside is that you aren’t available and the first impression someone might have of you is a broken tool managed by people who doesn’t know what they are doing.

These are silly, stupid, amateur mistakes. We will do better. Specifically we are working to improve the quality of the connection between the website which accept scan requests and displays reports and the scanning server. We plan to introduce better error handling, as well as status updates to tell you what’s happening while your report is being generated. We plan to introduce an email fallback system, where if something does go wrong we notify you are allow you to enter an email address to email when the problem has been resolved and your report is ready.

Thank you to the thousand plus people who have used Zoompf’s service over he last 4 days. We hope you continue to do so. We are committed to making free, high quality tools to help developers make faster websites. Any feedback, questions, comments, or hate mail should be sent to info@zoompf.com or on twitter @zoompf.

Smashing Roaches

Since releasing our 100% online web performance scanning service 3 days ago we have checked over 1600 websites for performance defects. This is awesome beyond words! In the course of scanning those 1600 websites, we found some bugs in our own technology was well. That is not so awesome, but it is kinda funny. In this post I’ll share with you some of the issues that came up over the last few days.

Cartoon picture of a software bug

Hosting Provider Failure

When you submit a website for scanning to Zoompf, our Zoompf.com website contacts our scanning server and adds the job to the queue. When the scanning server is done with a job it uploads the results to Zoompf.com. While you wait, looking at a spinning progress bar, behind the scenes the web page is using Ajax to see if the report has been uploaded to the website. Unfortunately, our scanning server was uploading so much report data so quickly, it exceeded some settings our hosting provider for Zoompf.com had set. And so our hosting provider had the brilliant idea to just black list the IP address of our scanning box. When the scanning server tried to upload the results, our hosting provide kept terminating the connection so we had no way of uploading the reports onto the website. Worse, this was only a one way block! Job requests could get sent from Zoompf.com to the scanning server, but reports coming back could not be uploaded! This was the main cause of the outage we had yesterday afternoon. Needless to say we have a very stern conversation with our hosting provider so this shouldn’t happen again.

Far Future means FAR!

Sometimes people take performance advice a little to far. Take for example esb-alumni.de. When we assessed the site our performance scanner would crash. Turns out this website is setting a far future date using the max-age directive in the Cache-Control header. The only problem the website tells browser to cache resources for 316,224,000,000 seconds or around 10,000 years! (Here is an example). This threw an exception while trying to calculate the date the resource would expire on! While the HTTP spec doesn’t provide a maximum value for max-age, 10,000 years is a little excessive. Also, as Eric Lawrence blogged, IE and Opera can’t handle values larger than 2^31. Luckily Zoompf already had a “malformed max-age” performance check, so we made sure it would flag on max-age values larger than 2^31 seconds. We fixed this bug as of 11:00pm on Tuesday April 11.

XML Nodes of a 3rd kind

Another controlled crash was when processing this atom feed. Zoompf follows feeds and analyzes them for several performance issues. In this case, our code which minifies RSS and Atom feeds did not understand how to process XML Entity nodes. We fixed this bug as of 11:00pm on Tuesday April 11.

Run Away Crawl

At its core Zoompf uses a web crawler to find and fetch web resources to analyze for performance problems. Most people don’t know this because we artificially limit how much gets crawled for our free service. However, like any web crawler, there is a danger of the crawler getting stuck in loops and endlessly requesting pages. While we have built several safe guards into the crawler, a few scans on Sunday and Monday showed a new problem. The problem occurs on websites that are missing a resource. Zoompf tries to fetch a CSS file, say http://example.com/foo/style.css, and we get a 404 error page. However, on this error page is a relative URL to another CSS file. The relative URL is foo/style.css, which corresponds to the full URL http://example.com/foo/foo/style.css. Of course, this CSS file doesn’t exist, and returns a 404 when we request it, and that 404 response contains anoter relative URL to a CSS file that resolves to http://example.com/foo/foo/foo/style.css. You see where this is going (Here is an example of that behavior). Our scanner was crashing when the URL for a request would grow to such a ridiculous length it exceeded the column size in our scan database. We fixed this bug as of 11:00pm on Tuesday April 11.

Closing

The Internet can be a fairly dirty place that’s full of surprises, both in terms of its structure and its content. The Zoompf team will continue to fix these issues as they come up and keep you informed. Thanks for all the feedback and support and enjoy our free performance scanning service.

April 12, 2010

6 Crazy Weeks and New Online Web Performance Service

The last 6 weeks have been a very exciting time for us at Zoompf. 5 weeks ago we passed the 300 check mark for issues we test your website for using our performance scanning technology. Next we went live with a brand new web design and content management system to manage all our online content and make it easier for you to find the latest front-end performance techniques on our site and on our blog.

Less than 1 month ago, we rolled out our free 100% fully automated web performance scanner. This free service would scan whatever website you want, whenever you want, and as often as you want, and email you a web performance optimization report offering clear guidance to make you website blazingly fast. Since then over 400 submitted their email and received a free scan. Then we introduced of our web performance scanning bookmarklet which allowed anyone to check whatever site they were browsing for web performance problems regardless of what web browser or operating system they were using. This milestone made it even easier to use Zoompf’s performance scanning technology and discover how Zoompf can help web developers, designers and IT professionals build faster sites!

Shortcomings Abound

Of course to get a free performance assessment you still had to type in an email address. This was a barrier for some people. Creating the report and delivering it also wasn’t pretty. It could take up to several minutes before you would receive you report. And when you did receive the performance report is was a ZIP file containing some HTML and supporting images. Very cumbersome indeed! All of these factors made it difficult for web developers, designers, and front-end engineers to seamlessly integrate Zoompf’s performance analysis into their everyday workflow or tool chain.

Well our goal is to provide free tools, software, and services to help make the web a faster place. And that won’t happen unless it is completely painless to use Zoompf during your daily grind. So we all emptied our wallets, rolled some loose coins, and sold our bodies on the 14th hole of Augusta National’s golf course to purchase a crazy fast computer to replace our aging scanning box. Now Zoompf performance scans take seconds instead of minutes. Next, we slaved through the nights, hacking code to remove the entire email dependency from our scanning system and wrote an online reporting system.

Like Awesome in a can!

That’s right, today we are happy to announce our free performance scanning service is now entirely online! No email address, nothing to install, just sweet web-based performance checking honey. Punch in any URL you want scanned into the system, mash on “go” and in seconds you will be seeing a Zoompf performance report right inside your browser! Doc even made it work on iPhones or IE6 ;-) It looks something like this:

Screen shot of online Zoompf scanning service reports

(O’Reilly’s woodcut animal‘s eyes are so wide because he’s surprised by the wide range of web performance problems on oreilly.com!)

Now for the cool news. Not sure if you noticed but we actually flipped the switch turned activated the online service very late Friday night/very early Saturday morning (approximately 1:45am EST on April 10th). We are very pleased to say that in the last 55 hours or so, people from around the global have used Zoompf to test the performance of over 800 websites!

Want to try it out? Simply go to zoompf.com/free, type in a URL, and bask in awesomeness of free, comprehensive web performance optimization reports! Help us try and get over 1000 scans in the first 72 hours!

Recap

  • We just launch 100% free, 100% online web performance scanning service
  • We check your app for over 300 different performance and website issues
  • o strings! No email required. Unlimited use. No silly technical prejudices. Any browser. Any OS. Period.

On behalf of the entire Zoompf team, myself, Doc, JR, Tracy, and Brian, we thank you for the bottom of our hearts for your interest, feedback and support. It’s going to be an amazing year as we continue to make Zoompf the source to help your find and fix web performance optimization problems.

Enjoy,

Billy Hoffamn. Zoompf Founder

April 5, 2010

Automated Scanning Service Glitch

Unfortunately we had a glitch in our automated backend systems during the last 18-24 hours,. It affected both out free automated scanning service and our system that processes incoming inquiries about PageBurner, our professional performance consulting service. We solved the issue (an HTTP connection that was timing out before a network drive failover timeout) and we believe we have contacted everyone who was affected. If you used our free automated scanning service or submitted a request for more information about our professional between April 4th at 12:00pm EST and April 5th at 12:00pm EST, please re-submit the information or send an email to info@zoompf.com.

We are sorry for any inconvenience.

April 2, 2010

DevNation Conference Tomorrow. Oh, and Zombies

Logo for DevNation Conference

I’ll be presenting tomorrow Saturday April 3rd at the DevNation conference in Atlanta. DevNation is a travel conference that puts on intimate, one day conferences about web and software development in cities around the US . My presentation is entitled “Making the Web Fast!” and serves as an introduction to frontend performance with a twist. Instead of just explaining optimizations such as caching, domain sharding, or image crunching we are going to do some live performance autopsies of real sites. We’ll see what they are doing right and what they are doing wrong and how much they could save by implementing some front-end optimization techniques.

I’m excited about this talk. I’ve given presentations all over the world: from the steel and glass skyscrapers of Hong Kong and Tokyo, to the rain drizzled streets of London and Munich, to the faux glitz of Las Vegas, to the sunny California campuses of Silicon Valley, and even to the blandly painted government walls of an FBI field office. However there is something fun and special about presenting in my home town of Atlanta. Perhaps it is because I know where all the great restaurants and bars are to go socialize with all the attendees! Actually it is because there is a vibrant technology and entrepreneurial culture in Atlanta and I enjoy contributing to that whenever possible.

DevNation is only $50 for a whole day of technology, talks, food, and drinks. If you are in the area you should definitely attend. As an added bonus, anyone who comes up to me at DevNation and says the magical phrase Zombie Apocalypse will get free PageBurner performance assessment. Unlike a free performance assessment through our website, our PageBurner performance assessment will analyze you entire website and contains full details and remediation advice for all the issues we find.

Hope to see you there.

March 30, 2010

The Big Performance Improvement in IE9 No One is Talking About

Microsoft released a preview of Internet Explorer 9 last week. Much attention has been paid to its increased standards support as well as performance improvements such as GPU accelerated page rendering and a faster JavaScript engine. However a small blog post that has received virtually no commentary discusses a change with IE9 that may well be the biggest web performance improvement we will see with the new browser.

Internet Explorer Logo

In a post on the IE blog last week, Marc Silbey shares the structure of IE9’s new User-Agent string. In it he writes:

An important change for site developers to know is that IE9 will send the short UA string by default. This change improves overall performance, interoperability and compatibility. IE9 will no longer send additions to the UA string made by other software installed on the machine such as .NET and many others.

Specifically, IE9’s the User-Agent string will look like this: Mozilla/5.0 (compatible, MSIE 9.0; Windows NT 6.1; Trident/5.0. Contrast that my IE8 User-Agent which is: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; WOW64; Trident/4.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.5.21022; .NET CLR 3.5.30729; MDDC; InfoPath.2; .NET CLR 1.1.4322; .NET CLR 3.0.30729). (I have no idea why there is a “Media Center PC 5.0″ identifier in my User-Agent string. I have a Dell laptop using Vista Home). The obvious benefit of the IE9’s User Agent string is that it is shorter. In fact, it’s over 70% smaller (63 bytes opposed to 216 bytes). Why the difference?

The difference is all the superfluous junk on the end of the User-Agent string. From IE4 until IE8 other programs installed on your machine could append an identifier string about themselves to the User Agent string IE would send. Junk such as different .NET runtimes and version numbers, toolbars and browser add-ons, media center strings, tablet string, Office plug-ins, and more would all appear in the User-Agent. Yes, moving to a shorter User Agent string will reduce the amount of bytes IE9 must send with each requests will improve performance. We’ve known about the benefits of reducing an HTTP request to try and make it fit in a single packet. In fact Yahoo has a performance rule around excessively sized cookies.

Of course, there is no way we would write an entire blog post about how the User-Agent string for IE9 is only 63 bytes and try to claim with a straight face that the reduced request size is the most impactful web performance improvement that IE9 brings to the table. You will see that the real benefit of IE9’s shorter User-Agent string, and perhaps the biggest web performance optimization in all of IE9, has to do with HTTP compression and caching.

Caching Compressed Responses

HTTP compression is one of the most impactful performance improvements you can deploy for a web application resulting in bandwidth savings of 50-80% for text resources. However compression makes things more complicated for shared caches like caching proxies. Consider what happens if a browser that supports compression requests a URL and the caching proxy receives a compressed version of the response. Then the caching proxy receives a request for the same URL from a different user. Can it send the compressed version? To solve this, HTTP/1.1 added the Vary header. The Vary header allows web servers to essentially say “To generate this response, we used the URL and the value of the following HTTP request headers.” Caching proxies could then store a copy of a response and know that “This copy is for this URL when requested with this HTTP request header value.” You can think of a caching proxy as having an internal table of what resources are cached and under what conditions to serve the resource. If the incoming request URL matches the URL for a cached resource, and if the value of each incoming HTTP header that was specified by the Vary response header match the values of the HTTP headers used in the original request for the cached resource, then the cache can service the new request locally by returning the cached resource.

This method allows the caching proxy to properly handle both compressed and uncompressed versions of a resource. This means that caching proxies could store two different copies of a distinct URL (one compressed, one uncompressed) based on the Accept-Encoding header. Unfortunately there are some bugs in certain older web browsers where these browsers would send an Accept-Encoding header telling the web server they supported HTTP compression when they really didn’t. The biggest culprit was IE6 before SP1. This browser had a bug would it would internally cache the compressed version of a CSS or JavaScript response and would try (and fail) to directly process the compress bytes. There are also certain versions of Netscape 4.x that did not properly handle HTTP compression despite using Accept-Encoding to instruct the server that it did.

What was the solution? Web servers would first look for the presence of an Accept-Encoding header to determine if the browser making the request thinks it can accepted compressed resources. If so the web server would next examine the User-Agent header to determine if see the requesting browser is known to have HTTP compression bugs. Only if the browser says it can accept compressed responses and it is not one of the browsers that has compression bugs will the web server serve a compressed version of the resource. (In retrospect, modifying a perfectly working web server to work around a buggy web browser seems silly. However in the age before automatic updating software this was a reasonable approach).

Unfortunately, this seemingly small change has enormous ramifications.

Different Strokes For Different Folks

Since the web server is varying the response based on both the Accept-Encoding header and the User-Agent header, it needs to indicate this to any downstream caching proxies by using a Vary: Accept-Encoding, User-Agent header. Since the web server could potentially serve a different response based on the User-Agent string, the caching proxy cannot serve the same cached response to web browser’s with different user agent strings. So instead of matching the URL and the value of the Accept-Encoding header on incoming request, now the caching proxy must match the URL, the value of the Accept-Encoding header, and the value of the User-Agent header to be able to return a cached response. To understand the impact of change, consider the following scenario.

Tom and Nick work at the same company and their web traffic passes through a shared caching proxy. Tom is using Apple’s Safari web browser and Nick is using Mozilla’s Firefox web browser. Both of these browsers support HTTP compression and neither have any known compression bugs. Tom visits http://example.com/index.html. The web server returns a compressed response with Cache-Control and Expires headers to enable caching of the resource, and a Vary: Accept-Encoding, User-Agent header to let downstream caches know what values were used to determine the response. The caching proxy stores a copy of the response using the URL http://example.com/index.html and the Accept-Encoding request header value of gzip as the key.

Nick then visits http://examples.com/index.html. The caching proxy sees the request and attempts to service it. The caching proxy does have a cached copy for the URL Nick is requesting and Nick’s request also has the same Accept-Encoding header value as the cached copy. However Nick’s request was made with Safari’s User-Agent string and the cached copy was stored for a request with Firefox’s User-Agent string (due to the Vary: User-Agent value from the originating web server). So even though both web browsers support compression, neither have any caching or compression bugs, and the caching proxy already has a cached response that is perfectly usable by any modern web browser, the caching proxy cannot serve Nick the cached response. Instead Nick’s request is passed on to the web server and that response is also cached. The shared cache now contains two separately cached yet identical responses.

The problem gets worse. Tim, who works at the same company as Tom and Nick, uses Google’s Chrome web browser to request http://example.com/index.html the caching proxy again is not able to locally service the cache. This is because Chrome has a different User-Agent string from Firefox or Safari. Thus the shared cache ends up with 3 separately cached yet identical responses. Caching Proxies went from have to story 2 copies of each distinct URL (one compressed, one uncompressed) based on the Accept-Encoding header, to storing 2 * X copies of a distinct URL, where X is the number of distinct User-Agents.

500 Different Ways To Say The Same Thing

It’s clear from this example that the addition of Vary: User-Agent to a response can significantly reduce the performance of shared caching. How much is dependent on how many distinct User agent strings. Obviously different web browsers will have different user agent strings and there is nothing we can do about that. But what about different User-Agent strings for the same version of the same browser? Sadly, there can be multiple different User-Agent strings for the same version of the same browser. Often this occurs when the operating system is included in the User-Agent string. This means the same version of the same browser can often have half a dozen different user agent strings. While this exasperates the Vary: User-Agent shared caching problem, it is still manageable.

Unfortunately Internet Explorer proceeds to destroy any chance of managing the problem. This is because IE does not have a half dozen or so different User-Agent strings. It has hundreds! Here is a list of over 480 different IE8 User-Agent strings. All of those browsers are Internet Explorer 8 but each has a different User-Agent string due to of all those external programs, toolbars, and browser add-ons that append on junk.

In short, due to the hundreds of different User-Agent variations for the same fundamental versions of Internet Explorer, and the (shrinking) majority market share of IE, currently the use of a Vary: User-Agent HTTP header effectively nullifies shared caching.

Starting To Fix The Problem

IE9’s adoption of a shorter User-Agent string without any inclusion of 3rd party identification banners will significant help matters. This change brings IE9’s User-Agent string in line with other web browser User-Agent strings which only have a few variable components. These variables are:

  • Computer Architecture of the computer
  • Version number of the web browser
  • Operating System of the computer
  • Language of Operating System

Computer Architecture is largely stabilizing on a few distinct values for each browser vendor such as i686 or x64. A changing version number of the web browser, include minor build numbers or patch numbers, is only included by a few web browsers (most notably Google Chrome). This can make for a large number of different User-Agent strings for the same major browser version. However automatic updates having largely marginalized this problem: the majority of user’s receive and use an updated version of a browser with 3 weeks of its release. The operating system of the computer also has only a few distinct values, except in the Linux world with different distributions tend to insert their name into the User-Agent string (Ubuntu and Debian being the worst offenders). Finally is the OS language. Ideally this should not be included in the User-Agent string at all, but in the Accept-Language header. The impact of including the language in the User-Agent string is largely a non issue as users behind a shared caching proxy (either instead an ISP or a corporation) tend to speak the same language.

The end result is IE9, and other major browsers, tend to only have 5 or 10 distinct User-Agent strings for each major version.

Why Even Use Vary: User-Agent?

This is perhaps the best question. There are no modern browsers that have HTTP compression issues. The biggest problem browser, IE6, had its HTTP compression issues solved nearly 8 years ago with the release of IE6 SP1 in spring of 2002. All major web browsers that send an Accept-Encoding header do legitimately support compression. There is simply no reason to ever include a Vary: User-Agent header when dealing with a cachable resource. However its easy to see why we have this problem. There are 10 years worth of web servers out there that are configured to inspect User-Agent strings. Just look at Apache’s documentation and you can see why. Below is the sample configuration for Apache’s compression module. It uses regular expressions on the User-Agent to detect bad browsers and then includes a Vary: User-Agent header in the recommended configuration for their compression module. This nullifies any caching of compressible and cachable resources.

<Location / >
  # Insert filter
  SetOutputFilter DEFLATE
  # Netscape 4.x has some problems...
  BrowserMatch ^Mozilla/4 gzip-only-text/html
  # Netscape 4.06-4.08 have some more problems
  BrowserMatch ^Mozilla/4\.0[678] no-gzip
  # MSIE masquerades as Netscape, but it is fine
  # BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
  # Make sure proxies don't deliver the wrong content
  Header append Vary User-Agent env=!dont-vary
</Location>

There is one situation where it is appropriate to have a Vary: User-Agent response header. Consider a dynamic HTML page where the web server might return different content to a mobile browser than it would for a desktop browser when serving the same URL. For those pages you would want to include a Vary: User-Agent header. However these dynamic pages are, by definition, not cachable and thus don’t harm shared caches like Caching Proxies. The rule is any resource that is cachable should not have a Vary: User-Agent header.

The Biggest Performance Improvement for IE9?

With widespread adoption of IE9, we move from a world where the major browsers (IE, Firefox, Chrome, Safari, Opera) are represented by several thousand distinct User-Agent strings to a world of roughly 50-100 distinct User-Agent Strings. That is a 10 or 30 times improvement or over an order of magnitude in improvement. We expect that shared caches like caching proxies should get roughly a 10-20 times improvement in hit rate for resources from web servers returning a Vary: User-Agent header.

This is why we say that Microsoft’s decision to remove 3rd party program identifiers from IE9’s User-Agent string could be the most impactful web performance optimization present in IE9. Other performance improvements in IE9 like the improved JavaScript engine or GPU rendering certainly are impressive. However, even 100%, 200%, or even 1000% improvements to those system will result in microseconds of improvement. A clean User-Agent string which drastically increases the hit ratio of shared caches will have increase performance measured in milliseconds or even seconds, while decreasing bandwidth costs and server load for the origin web server.

Want to see what performance problems your website has? Cachable Resource with Vary:User-Agent is just one of the 300+ web performance issues Zoompf can detect when scanning your web applications. Get your instant free web performance assessment at Zoompf.com today or try our free performance scanning bookmarklet.

March 24, 2010

Performance Tip for HTTP Downloads

HTTPWatch has an interesting article today on their blog entitled “Four Tips for Setting up HTTP File Downloads.” They offer some great advice to make sure your downloadable files work across all browsers and are saved using the appropriate name. However they didn’t include a very important feature that all websites offering large file downloads should have: support for resumable downloads! As we will see this is an essential performance feature that improves user experience while reducing bandwidth costs.

Partial Downloads and the Range Header

HTTP/1.1 added many exciting features over HTTP/1.0. And while people are familiar with the more popular HTTP/1.1 performance enhancements such as default persistent connections or chunked encoding most are unaware of another performance enhancement: partial responses. HTTP/1.1 allows a client to request a certain piece of a resource. The client can use the Range header to tell the web server to serve only a subset of bytes from the total resource.

This seemingly odd and esoteric feature is actually quite powerful because it allows for browsers to resume HTTP downloads! Consider this scenario:

Diagram showing how a browser can use the Range header to resume an interrupted download

Here we see the browser is trying to download a large PDF file named “report.pdf” which is approximately 9 megabytes. The client issues an HTTP GET request and starts downloading the response. The web server used the Accept-Range header to indicated to the client that it allows for GET requests with the Range header to download pieces of this resource. After the client has downloaded a 2 megabytes, the browser experiences a problem. This could have been a caused by a number of issues. For example the computer might have momentary lost its network connection (common on wireless networks) or another program on the computer might have locked up and caused the browser’s connection to time out. Whatever the cause, the client had to close the HTTP connection it had with the web server. However, instead of having to redownload the entire PDF file, the client can use a range request to skip what it has already downloaded and only fetch the remaining data. The client does so by using a Range header to tell the web server to serve the contents of the PDF starting at the offset 2048000.

A few key points about resumable downloads and range requests:

  • Range requests allow the user to pause and resume the download inside their browser’s downloads window.
  • Resumable downloads can only work for static resources. They cannot be used with dynamically generated responses that change with each request or where you do not know the size of the resource ahead of time.
  • To indicate to the client that you allow range requests, you must send both a Content-Length response header and a Accept-Ranges response header.
  • IIS and Apache include the appropriate headers to support range requests by default when serving static files from the file system. These web servers will also automatically handle incoming Range header and serve the appropriate bytes.
  • If you are using PHP, ASP.NET, Ruby, or some other application logic to process the client’s request and deliver the downloaded file (as in /download.php?ID=123), you will need to manually add logic into your application code to handle range requests. This is not an easy task. Consider getting rid of your download handling application logic entirely and serve the file directly from the file system. This allows you to leverage the web server’s built in support for range requests.

Conclusions

Supporting resumable downloads is an easy way for you to save bandwidth while providing your users with a better browsing experience. You can view the HTTP headers for your downloadable resources to determine if you support resumable downloads using this service and making sure the “Show all server header fields” option is enabled. You can also use a browser plug-in like Live Headers to view the HTTP header coming from the server. Zoompf checks for this issue by looking for HTTP responses that have a Content-Disposition: attachment; header (indicating a downloadable file) but don’t have an Accept-Range header.

Want to see what performance problems your website has? Non-Resumable HTTP Download is just one of the 300+ web performance issues Zoompf detects when scanning your web application for performance issues. Get your instant free web performance assessment at Zoompf.com today!

March 23, 2010

Optimizing Gradients

Gradient backgrounds are a common visual element on modern websites. And while you can use browser specific CSS extensions to directly create gradient backgrounds with pure CSS the much more common method is to use an image. Traditionally, when a web designer wants to create a gradient to a webpage, they use a program like Photoshop or The Gimp to create a small image containing the gradient they want. They then use CSS to set this image as the background for a specific element and then use repeat-x or repeat-y to spread the gradient image along the entire length of the element. This provides us with the chance for a new performance optimization technique!

Consider the image above that a Sven, a long time Zoompf user, sent in. This image is 38 pixels wide and 91 pixels tall. As you can see there is a gradient that goes from dark gray at the top of the image to white at the bottom. This image is used on the website to provide a background gradient for section titles. The website’s CSS uses the repeat-x directive to fill the section title along the X-axis with the gradient. Which raises the question “Why is the image 39 pixels wide?” After all, the change in colors is along the Y-axis (from the top of the image to the bottom). The width of the image is meaningless. It adds nothing to the image. If you were to open this image in a program like Photoshop you would see that every pixel has the same color as the pixel to it’s left or right. It cannot be any other way. Otherwise when the image is repeated one after another along the X-axis you would see spots or seams where the colors were different. Since CSS is used to repeat this image in the X-axis direction, there is no reason for the image to be larger than 1 pixel wide! Converting the 38×91 pixel image to a 1×91 reduces the size of the file by over 65%!

Let’s try a real example. Consider this gradient from Yahoo. This image is actually a sprite of several different gradients! It is 5 pixels wide and 3302 pixels tall and is 3466 bytes. Again, we can confirm that the extra 4 pixels in width provide no value. All the pixels in this image have the same color value as the pixels to the right or left. Using Photoshop, we cropped the image to be 1×3302 pixels with a size of 1920 bytes. This is a savings of 45% with absolutely no loss to image quality or user experience!

We performed this optimization on a sample of 300 or so gradient images. On average we reduced file size by 30-70%. PNG images tended to see an improvement of 10-30%.

Browser Performance Impact

Are there any negative effects to using gradient images that are only 1 pixel in length along the axis they repeat? This is what Sven wanted to know when he emailed the image. Consider an image that’s 32 x 300 images. It is repeated along the X-axis using CSS and is used as a background for a <DIV> that is 96 pixels wide. To “draw” an image on the screen, the fundamental operation the browser is doing is copying the bytes of the image into the buffer of bytes that display the screen. That means to draw the gradient background the browser has to copy the bytes of the 32 x 300 pixel image into the video memory 3 times (because 3 times 32 is 96). Consider if we had a 1 x 100 pixel image. The browser has to copy the bytes of the 1 x 300 pixel image into the video memory 96 times (because 1 times 96 is 96). So, it would seem that using a 1 x 100 pixel image is 32 times slower than using a 32 x 100 pixel image. Remember we aren’t talking about browser repaint or reflow events (where the browser has to recalculate where all the text and images goes and then redraw). We are talking purely about how quickly the computer can draw an image.

It sounds like we might have a performance problem.

Only we don’t. Computers can move data around very quickly. We are talking nanoseconds (10^-9). Meanwhile, transferring data over Internet connections is typically measured in millisecond or microseconds (10 ^ -3 or 10 ^ -6). So even though smaller images may make the browser do more work, even 32 times more work, the difference is so infinitesimal that they are not noticeable to the user. The time saving you will get by reducing the amount of data you have to send over the slow network however is impactful and beneficial.

Conclusions

The fact that gradients using images rely on CSS to repeat the image allows us to reduce the width or height of the gradient image without any visual difference. Performance is improved because we have reduced the size of the image. This technique can be applied to all images that are used as gradients. If a gradient image repeats along the X-axis it should only be 1 pixel wide. If a gradient image repeats along the Y-axis it should only be 1 pixel tall. As we saw the the example gradient from Yahoo, even gradient images that are already quite small in terms of dimensions can drastically reduce their size even further by reducing the width or height to 1 pixel.

Want to see what performance problems your website has? Oversized Gradient Image is just one of the 300+ web performance issues Zoompf detects when scanning your web applications. Get your instant free web performance assessment at Zoompf.com today!

March 22, 2010

Upcoming Conferences

Front-end Web performance is a growing space and several conferences are providing a forum for presentations and discussions about making the web fast. I’m excited to be a part of this trend and I’ll be presenting at a number of very cool conferences over the next two months. While two of these are physical conferences held in the United States one conference is an online conference that anyone can in the world can attend. Here is some information about upcoming conferences where I am presenting:

DevNation Atlanta

I’m be giving a great presentation at the touring DevNation conference’s stop in Atlanta on April 3rd entitled “Making the Web Fast.” It will serve as an introduction to frontend performance with a twist. Instead of just explaining optimizations such as caching, domain sharding, or image crunching we are going to do some live performance autopsies of real sites. We’ll see what they are doing right and what they are doing wrong and how much they could save by implementing some front-end optimization techniques. I will also reference some free tools and services, such as Zoompf’s free web performance scanning service, that attendees can use to speed up their own websites.

DevNation is a day long conference with some other great speakers focusing on web development. The conference’s venue is the Georgia Tech Research Institute at just off of Georgia Tech’s campus, which happens to be my alma mater. DevNation is an intimate conference with extremely cheap prices and it highly recommended to anyone in the Atlanta area who design, develops, or maintains web applications.

JSConf US 2010

For reasons I don’t entirely understand the awesome folks at JSConf asked me to present at JSConf 2010 about all the nasty stuff you can do with JavaScript. I will be sharing the stage with luminaries like Douglas Crockford (whose window.onerror is always defined, because nobody throws anything at Douglas Crockford and lives), Steve Souders, and John Resig. While they are all going to talk about important stuff I am there to talk about how to destroy the Internet using the evil side of JavaScript.

JSconf runs from April 17th and 18th with a hefty dose of partying and a whole other conference, ScurvyCon, on April 16th. The speaker line up is literally the best of the best. JSconf is already sold out and the tickets for ScurvyCon go on sale on April 4th. If you can’t make it JSConf is nice enough to post videos of all the talks after the conference so anyone can learn and enjoy.

Web Optimization Summit

The Web Optimization Summit is an especially cool conference. It physically takes place in Austin Texas on May 12th where you can attend and watch the speakers. But it is also a virtual conference, so anyone in the world can connect and attend the conference! I’ll be speaking on more advanced performance topic with a presentation entitled: Implementing a Web Performance Program without killing yourself. It addresses a problem we see time and time again at Zoompf: A developer or IT admin reads on of Steve’s performance books, or downloads YSlow, and takes it upon themselves, (and only themselves) to start optimizing website. Suddenly the app stops working because IT implemented HTTP caching without having proper changing control or file versioning. Or all the JavaScript and CSS in the development branch of source control has been minified. Or the design cannot be modified because all the original images have been crunched and indexed. Even worse these optimizations are hap hazard and not repeatable so site performance whips violently from fast to slow with each new publish. The talk explores how to add performance optimizations into your existing web development and deployment process. This allows for automated, repeatable performance optimizations that don’t add time to your development cycles.

The Web Optimization Summit has some other excellent speakers, such as Paul Irish and Kyle Simpson from Getify. The conference all takes place over a single day, is reasonably priced, and can be virtually attend from around the global.

Bribery

I’m very happy to be presenting at these conferences. If you are attending please stop on by and say hello. In fact, anyone who meets me and shows me a printed copy of their free Zoompf Web Performance Report with some feedback about the findings will get a special gift. More details on this soon. Hope to see you all at the conferences!

March 16, 2010

Free Performance Scanning Service and New Web Design

We have two big announcements for you all today.

The first announcement is that we have finished rolling out a complete web design for Zoompf.com. The awesome folks over at Zero G Creative did the design and we worked with them to get everything tweaked (include the Sisyphean task of making everything look pretty even in dead browsers like IE6) and to hook it into our new backend systems. We are very pleased with the results and we will be implementing addition changes in the coming weeks.If you run into any issues please let us know.

We are very proud of our second announcement. Today we are unveiling Zoompf’s new automated web performance scanning service. Simply plug in a URL and we scan your website for over 300 performance issues and then email you a pretty report in minutes. It’s completely free, so please use it as much as you’d like and as often as you’d like. We are experimenting with new features, such as PDF reports, load graphs, resource hierarchy graphs, and other cool features and will keep you posted.

For now enjoy the new Zoompf website and take your favorite websites for a spin with our free web performance scanning service!