Snow Leopard Review

 

I thought I would highlight what I found to be the most interesting points from the Snow Leopard Ars Technica review, for those who couldn’t make it through the 23 page review and provide a few thoughts on the OS overall.

Read after the break for a list of UI and usability changes as well as a list of interesting changes for Cocoa developers, including code samples.

Snow Leopard Ars Technica Review

User Centric Thoughts


Through the first half of this article, I’ll focus on user interface changes and just general usability improvements in the OS.

Dock

There were several changes to the Dock, but the one I found the most interesting (and didn’t know before reading) was the “Minimize windows into the application icon” option. Instead of little windows appearing in the Dock, when clicking the application icon you are shown a list of minimized windows. Very reminiscent of Windows and the task bar (as there is no preview, only the window title), but surely useful for those out there who minimize lots of windows.

Finder

The Finder was completely rewritten for Snow Leopard and should provide a strong foundation moving forward. There is heavy use of Core Animation in the new Finder, meaning that it just “looks prettier” most of the time. There are animations when renaming files on your Desktop for instance. And a feature that I personally love:

List view also has a few enhancements—accidental, incidental, or otherwise. The drag area for each list view item now spans the entire line. In Leopard, though the entire line was highlighted, only the file name or icon portion could be dragged. Trying to drag anywhere else just extended the selection to other items in the list view as the cursor was moved. I’m not sure whether this change in behavior is intentional or if it’s just an unexamined consequence of the underlying control used for list view in the new Cocoa Finder. Either way, thumbs up.

Overall the Finder looks very similar to the Leopard version, but is more responsive and has a feature here and there that reminds you that this is a new version.

Radnom Refinements

This is just an assortment of interesting tidbits I picked up while reading.

  • Safari runs plugins as separate processes. If a plugin crashes, Safari won’t.
  • Menlo is the new default font for Monospaced fonts (See my article here)
  • Resolution Independence still sucks
  • Core Location support – your Mac can find itself
  • Wake from Sleep feature – with a Time Capsule or AirPort Extreme station, you can access contents from a sleeping Mac over the local network at any time. Works great with the “Back to my Mac” feature.
  • No ZFS support

Developer Centric Thoughts


Here on out is several points of interest for developers.

File Compression

Snow Leopard introduces per file compression to the HFS+ file system used by Apple.

Resource Forks & Extended File Attributes

To bring file compression to the already fragile HFS+ file system and maintain backwards compatibility, Apple stores the compressed file data in resource forks, and either compressed or uncompressed in extended file attributes. What this means:

And where can the complete contents of a potentially large file be hidden in such a way that pre-Snow Leopard systems can still copy that file without the loss of data? Why, in the resource fork, of course. The Finder has always correctly preserved Mac-specific metadata and both the resource and data forks when moving or duplicating files. In Leopard, even the lowly cp and rsync commands will do the same. So while it may be a little bit spooky to see all those “empty” 0 KB files when looking at a Snow Leopard disk from a pre-Snow Leopard OS, the chance of data loss is small, even if you move or copy one of the files.

Performance Gains

You might first think that all this file compression would either waste space or waste CPU cycles. John from Ars Technica proposes that given the known fact that the physical motions of a hard drive are the slowest part of modern computers, storing the compressed data in resource forks and extended attributes makes sense because that data is stored in one of two locations on the disk. And because these two areas are frequently used, the read/write head of the hard drive is close by and has less moves to make and can be quicker. Also, because the two files are accessed so frequently, caching occurs providing even greater performance benefits.

QuickTime X

Snow Leopard introduced a completely rewritten 64-bit API for QuickTime. The new QuickTime X Player is nice and fancy, but the underlying API has underwent the knife. QuickTime debuted in 1991 and after 18 years has finally seen a significant update.

64 Bit

The interesting part is the new QuickTime X API in QTKit is smart. The API is optimized for playback and is 64 bit only. Transparently, if an application needs features that QTKit (QuickTime X) cannot deliver (and there are many currently), QTKit will revert to the previous QuickTime 7 API. And if a developer writes a 32 bit application and wants to use the newer QuickTime X API, QTkit will just spawn another process that is 64 bit to deliver content back to the 32 bit application, all transparently. The user will get the best experience with the least amount of effort from the developer, which is always a win.

File System API Unification

Briefly, between POSIX functions, CoreFoundation, and Cocoa itself, there are several ways to access data about the filesystem. Currently there is no unified approach to fetch all this data.

When opening a file in Leopard Preview, there are:

  • Four conversions of an FSRef to a file path
  • Ten conversions of a file path to an FSRef
  • Twenty-five calls to getattrlist()
  • Eight calls to stat()/lstat()
  • Four calls to open()/close()

Snow Leopard will use NSURL for all file system operations, instead of strings representing file paths. To the end user, this means the user could move a file and the application wouldn’t lose track of it as the NSURL has a unique identifier that is not based on file location alone.

Clang and LLVM

Performance Gains

Clang brings with it the two headline attributes you expect in a hot, new compiler: shorter compile times and faster executables. In Apple’s testing with its own applications such as iCal, Address Book, and Xcode itself, plus third-party applications like Adium and Growl, Clang compiles nearly three times faster than GCC 4.2. As for the speed of the finished product, the LLVM back-end, whether used in Clang or in LLVM-GCC, produces executables that are 5-25% faster than those generated by GCC 4.2.

Static Analyzer

The static analyzer is the single best feature in Snow Leopard as far as I’m concerned. Essentially Xcode is smarter and can analyze all ways your code might interact to determine errors in your logic. Unprecedented.

Read more about my thoughts on the static analyzer in Xcode 3.2 here.

Blocks

Blocks are an extension to C based languages, currently only supported by Apple in it’s 4 compilers shipping with Snow Leopard. Essentially, blocks are a way to pass a “block” of code. Not the same as a function, which has it’s own scope.

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FILE *fp = fopen(filename, "r");
 
if (fp == NULL) {
  perror("Unable to open file");
}
else {
  char line[MAX_LINE];
 
  while (fgets(line, MAX_LINE, fp)) {
    work;
    work;
    work;
  }
 
  fclose(fp);
}

The example above is boilerplate code and assumes you want to do some “work;” with the line once you’ve read it in from a file. By using blocks, you could create a function that takes the filename and a block, simplifying moving through the file greatly.

foreach_line(filename, ^ (char *line) {
  work;
  work;
  work;
});

API Use

John informs us that Apple uses blocks in over 100 new API calls that would simply not be possible prior to Snow Leopard.

Threading and Grand Central Dispatch

The age old problem in computing:

This is the enemy: hardware with more computing resources than programmers know what to do with, most of it completely idle, and all the while the user is utterly blocked in his attempts to use the current application.

Grand Central Dispatch makes great progress in helping developers alleviate the headaches in asynchronously executing tasks in their application.

Overview

Essentially, Grand Central Dispatch (GCD) is a system level library that manages a global pool of available threads, and grabs tasks from queues your application sets up. The more resources the system has available, the more threads GCD has free and the faster it can grab tasks from your application queues. Since the system is managing the threads, there is no application overhead for thread management and the possibility of too many threads, and yet your application can get the last bit of performance from the system by using all available resources. All automatically.

Let’s say a program has a problem that can be split into eight separate, independent units of work. If this program then creates four threads on an eight-core machine, is this an example of creating too many or too few threads? Trick question! The answer is that it depends on what else is happening on the system.

If six of the eight cores are totally saturated doing some other work, then creating four threads will just require the OS to waste time rotating those four threads through the two available cores. But wait, what if the process that was saturating those six cores finishes? Now there are eight available cores but only four threads, leaving half the cores idle.

There is a performance gain here is as well. If you were managing threads at your application level, you have to create and release threads as you use them. GCD uses a global thread pool, so the threads are always active. Whether or not they are working is the only change. By simply maintaining active threads, the system can pull just a little bit more performance from the system.

First Example

- (IBAction)analyzeDocument:(NSButton *)sender
{
  NSDictionary *stats = [myDoc analyze];
  [myModel setDict:stats];
  [myStatsView setNeedsDisplay:YES];
  [stats release];
}

The above method is a simple action called by a button click that will analyze a document and display the results. Under normal circumstances this would be nearly instantaneous. However, if a user attempted to analyze a very large document, the processing still takes place on the main event processing thread and the application appears to hang. Refactoring this to use threads and avoid race conditions, with callbacks for analyzeComplete would be a mess and most developers would balk at the trouble to make this four line method asynchronous. However, with GCD and Blocks, it becomes trivial.

- (IBAction)analyzeDocument:(NSButton *)sender
{
  dispatch_async(dispatch_get_global_queue(0, 0), ^{
    NSDictionary *stats = [myDoc analyze];
    dispatch_async(dispatch_get_main_queue(), ^{
      [myModel setDict:stats];
      [myStatsView setNeedsDisplay:YES];
      [stats release];
    });
  });
}

Now when the user clicks the “Analyze” button, a block is placed on the application queue to be processed as soon as possible. This block analyzes the document, and once that is complete, the block placed onto the event queue with ” dispatch_async()” will be called, therefore updating the UI. Simply wonderful.

Second Example

Here is a truly gorgeous example from John.

for (i = 0; i < count; i++) {
    results[i] = do_work(data, i);
} 
 
total = summarize(results, count);

Taking this simple for() loop and making it execute asynchronously with GCD is actually quite simple.

dispatch_apply(count, dispatch_get_global_queue(0, 0), ^(size_t i) {
    results[i] = do_work(data, i);
});
 
total = summarize(results, count);

I love it.

GCD Conclusion

John sums up the importance and far reaching effects of GCD on the future of Mac OS X.

When I first heard about Grand Central Dispatch, I was extremely skeptical. The greatest minds in computer science have been working for decades on the problem of how best to extract parallelism from computing workloads. Now here was Apple apparently promising to solve this problem. Ridiculous.

But Grand Central Dispatch doesn’t actually address this issue at all. It offers no help whatsoever in deciding how to split your work up into independently executable tasks—that is, deciding what pieces can or should be executed asynchronously or in parallel. That’s still entirely up to the developer (and still a tough problem). What GCD does instead is much more pragmatic. Once a developer has identified something that can be split off into a separate task, GCD makes it as easy and non-invasive as possible to actually do so.

Cocoa Framework Changes of Interest

  • The faster shutdown time for Snow Leopard is partly possible due to the system killing your application. You can mark your application as needed to properly shut down and stall the process. However if you don’t, your application will be sent the SIGKILL signal.
  • NSCashe class
  • NSBlockOperation class
  • Hefty work to NSURL
  • Gesture and multitouch event support
  • Ability to set desktop images
  • Block-based sheet APIs
  • Block-based enumerations for lines, words, and the like in NSString and NSAttributedString
  • New NSPropertyList APIs with better error handling and performance
  • Core Data integration with Spotlight
  • Read more at the Mac Dev Center from Apple

More Reading


Full Ars Technica Review

Read the complete Snow Leopard Ars Technica review.

Many thanks to John for the very complete review and insight into Snow Leopard. All code examples in my article were taken from his.

Ars Technica Archives

Comments are closed.
Trackbacks are closed.