Lazy Finder

2010-01-19 20:57:40 UTC

This is an expansion of a reply I wrote to a tweet by Daniel Jalkut. He wrote:

Imagine if the iPhone home screen showed a matrix of “generic” icons before filling in real ones. Mac Finder is a disgrace.

He’s referring to behavior introduced in Snow Leopard: When you visit a folder for the first time in a session, the Finder shows every symbolic link and alias with the kUnknownFSObject icon ( this one ), every application with the generic application icon, every file with the generic document icon, and every folder with the generic folder icon, before displaying the item’s real icon and then its Quick Look thumbnail.

Compare the environment of SpringBoard (on a non-jailbroken device) to that of Finder:

iPhone Mac OS X

Every item is of one kind: Application.

Items are of any of three kinds: File, folder, and bundle. The Finder must handle each kind differently.

Everything is on one iPhone’s worth of flash memory.

Files may be distributed over any number of volumes, local and remote; however, the general case is all files on one hard disk, which is the startup disk.

Because the iPhone doesn’t allow background processes, it’s the only app running, with only a few built-in, light-on-file-system-access exceptions (the heaviest of which is probably Mail).

Any number of applications may be running, and they may be accessing files on the same volume you’re browsing.

Accessing any file in flash memory is as quick as accessing any other file (random access).

Disks are not so predictable: Accessing one file and then another can incur milliseconds of seek time. Doing this repeatedly for dozens or hundreds of files (possibly in multiple Finder windows at different scroll positions) may cause the disk to thrash. You can hope that the OS can put the requests into a favorable order, but you can’t rely on it, and there’s only so much it can do.

Flash memory is always active.

Most users aren’t using flash memory. Hard disks may be spun down to conserve power. If this is the case, the disk will need to be spun up, which can take seconds.

All files (that is, all applications) are local.

Some volumes may be on remote machines, across a local network or the internet; depending on throughput and latency, every access to such a volume can take tenths of a second.

All applications are in one place, making caching of icons or their filenames easy.

Applications aren’t the only user-visible bundles, and any bundle can be anywhere.

Compare also how SpringBoard and Finder obtain icons*:

iPhone Mac OS X

Assuming that the icons themselves aren’t cached:

  1. Look up the application’s icon filename in the bundle’s Info.plist (or a cache of icon filenames).

  2. Load the icon from the indicated file.

(All of this may happen inside NSWorkspace and/or Icon Services.)

  1. If the item is a symbolic link or alias, find the original file. If it still exists, start over with it from this step. If it does not exist, jump to step 7.

  2. Get the item’s custom-icon bit.
  3. If the custom icon bit is set, open the resource fork (or, for folders and bundles, the resource fork of the “Icon\r”** file) and search for icon resources of ID -16455. (This step probably happens in Icon Services.)

    If this step succeeds, we have the icon.

  4. If the item is a bundle, look up the application’s icon filename in the bundle’s Info.plist.

  5. Load the icon from the indicated file.

    If this step succeeds, we have the icon.

  6. Identify the item’s HFS file type (if available) or its filename extension. For bundles, the file type may be in Info.plist. For bundles and packages, the file type and creator may be in a PkgInfo file inside the item, which would be yet another file open+read.

  7. Look up the icon for the file types (probably using Icon Services). For anything but a document of an installed application, this will be a generic icon (such as the generic application icon). If the icon does come from an installed application, it will need to be read from a file inside that application bundle.

SpringBoard hasn’t much to do, it’s in a straightforward environment, and the task and environment provide a couple of obvious caching strategies. The iPhone doesn’t have as much processing power, but what it has is enough—it can just get and display the icon without being lazy about it.

In fact, SpringBoard probably doesn’t even need to be asynchronous about it; all it needs to do is keep three pages of icons (current, next, and previous) in short-term memory. When the user flips one page, drop the farthest page out of the short-term memory cache and load the next one into it.

Meanwhile, on the Mac, getting an icon is not straightforward, and the environment can throw a monkey wrench into the works at any point. Every icon can take dozens, hundreds, or thousands of milliseconds to display, and more icons mean more opportunities for a stall. The solution is to load and show the icons asynchronously and in parallel—but then, what to show in the meantime?

Thus, for the Finder, lazy loading makes sense. The Finder can show you what it has (filenames and other basic metadata) immediately. You can work with those files, scroll to other files, or move through the folder hierarchy without having to wait for icons. And while you do that, the Finder has all the time it needs to asynchronously fetch the icons and, if it’s still appropriate, display them.

It’s a feature, not a bug.

* I’m speculating, since I don’t have the source code to either. These steps are how I would implement each one if I were imitating the current stock behavior.
** “\r” here means, as it does in C, the carriage-return character (U+000D).

14 Responses to “Lazy Finder”

  1. Daniel Jalkut Says:

    Thanks for elaborating. First, I would like to say that my point is first and foremost a marketing/usability point, and not a technical one. For *whatever* reasons, and you seem to enumerate many of them, the lazy loading behavior on the Mac and in the Finder gives a negative aesthetic experience. My point in the tweet is that I don’t think Apple would allow, with its current emphasis on the sleekness and elegance of the phone, such a disgraceful behavior.

    I do not disagree with you that laziness is the right approach in handling the display of dozens of items for which some attributes are not readily available. I do appreciate and agree that the ability to navigate files in the Finder before their icons are available is preferable to not being able to navigate them at all.

    However, the experience on my machine and on machines of friends I have queried seems to be the worst of both worlds: a significant delay before any icons appear, followed by a slow lazy-loading of icons that exhibits no user-pleasing smarts. There appears to be no predictive loading of adjacent screenfuls of icons, for instance, which are exceedingly likely to be scrolled into view. Furthermore, I’m not sure what you mean exactly by “per session”, but I witness the lazy reloading of these icons several times per day, without logging out or rebooting the system. The delay is often several seconds long, typically taking longer than, for example, the Flickr browser in MarsEdit takes to load and display a corresponding number of image thumbnails from *over the internet*.

    So over all, I would say that a poor user experience in 10.5 and earlier (postponement of item delay until, apparently, all icons were available), has been replaced with a poor user experience in 10.6: lazy loading with little or not performance tuning for user experience.

    I believe the Finder should be able to optimize for a positive user experience here, especially when I have not modified preferences or the style of view. There seems to be a lack of attention to detail here, and I don’t accept that it’s entirely necessary just because of the significant variables in desired behavior, or limitations in the Mac’s hardware.

  2. Steven Fisher Says:

    It’s worth noting that Apple likely has the infrastructure to improve Finder icon load times thanks to fsevents. I’d like to see fsevents used for more in the future.

    I was a little disappointed Apple didn’t use it to calculate folder sizes in 10.6.

  3. Peter Hosey Says:

    Daniel Jalkut:

    … a significant delay before any icons appear, followed by a slow lazy-loading of icons that exhibits no user-pleasing smarts.

    In my testing, the no-icons period happens while directory information (i.e., the list of names) is still coming in. It’s easy to test on a network (e.g., accessing ftp://ftp.apple.com while downloading in iTunes and/or torrenting), and in that test case, you can easily imagine it taking multiple seconds between batches of filenames arriving.

    Progressive display presents one real problem: If a file comes in on the same row where a file you were just about to click was previously, you click (or right-click, or double-click) on the wrong file. This is more likely in some sorts than others, assuming that the file records come in sorted at all. Even if they come in sorted by name, if you have the list sorted by (for example) modification date, you still get the problem. And I could be wrong, but I don’t think you can rely on files coming in in name order at Finder’s layer.

    As for the failure to pre-fetch icons in adjacent screenfuls, I agree there, and I think it would be worth filing.

    So over all, I would say that a poor user experience in 10.5 and earlier (postponement of item delay until, apparently, all icons were available), has been replaced with a poor user experience in 10.6: lazy loading with little or not performance tuning for user experience.

    It seems to me that the real problem in 10.6 is exactly what it was before: A delay in which nothing appears. The difference is 10.6 waits only until the names (and other basic metadata) are in, whereas the previous behavior was to wait until all the icons had also arrived before displaying anything at all.

    Even with the lack of pre-fetching, I maintain that this is an improvement: Files are available to work with earlier than they were before.

    Steven Fisher:

    It’s worth noting that Apple likely has the infrastructure to improve Finder icon load times thanks to fsevents. I’d like to see fsevents used for more in the future.

    I was a little disappointed Apple didn’t use it to calculate folder sizes in 10.6.

    I’m not sure what you’re expecting FSEvents to do here. All FSEvents does is tell the application “the directories in which event(s) occurred” (source). It doesn’t tell the app anything about the directories, nor about anything in them.

  4. Dan Messing Says:

    So, you’ve explained why it is technically more tricky on the Mac to load icons, but just because it’s tricky isn’t an excuse for a poor user experience. Surely there are some steps that could be taken to cache some commonly used icons, such as those in the Applications folder. On my MBP, I actively avoid opening that folder because I can’t stand my computer grinding to a halt for 10 seconds or more as the icons attempt to load.

    Couldn’t the actual locations of these icons be stored so that finding each icon file comes down to a single table lookup? Sure, it’s adding more code in the form of invalidating cache’s, but surely some smart Apple engineer is up to it.

  5. Peter Hosey Says:

    Dan Messing: Actually, the relative paths to bundles’ icons are cached in the Launch Services cache. So that saves the Info.plist check if the bundle is already in the cache. Of course, I don’t know when bundles enter the cache, but if you’ve ever looked at a bundle before, step #4 should go away.

    That just leaves all the other steps. ☺

    On my MBP, I actively avoid opening [the Applications] folder because I can’t stand my computer grinding to a halt for 10 seconds or more as the icons attempt to load.

    That shouldn’t happen. On my machine, it takes no more than a second to load the icons, and Shark shows nothing but reading the directories and loading the icons (both of which happen on dispatch queues). I admit that my machine has faster disks, but I don’t believe that they’re ten times as fast.

    Try running DiskWarrior. As a programmer, you might also try using Shark and/or Instruments to trace your system.

  6. Dan Messing Says:

    Well, 10 seconds may have been an exaggeration, but you’re right, I should do some profiling to see what the heck is going on. I do believe that with that folder in particular things have gotten slower for me under 10.6.

    I don’t disagree with your points, I just think that there are some more optimizations that could be taking place. I was expecting a little more out of the rewritten Finder. Ah well, at least the with / without toolbar animation is pretty. :)

  7. ssp Says:

    I think that Peter’s points are correct but the real problem – as usual – is that the Finder is a royal POS. Of course it cannot be expected to cache all icons that may be needed for the system, but it simply seem particularly slow and dump when displaying them. That’s already painful enough when opening your applications folder (which may be one of the main point of lack-of-grace that triggered Daniel’s comment), but once you start working with slow volumes (think intercontinental AFP connections on DSL lines) it becomes a sad joke. Even displaying a folder with a hundred generic folder icons can take ages there – and even cause multi-second stalls in the Finder.

    I think Daniel’s point says nothing more than Apple love the iPhone experience and work hard to make it smooth. It has the advantage of being a relatively simple problem as well when it comes to the icons. OTOH Apple don’t give a damn about any non-trivial aspect of the Finder experience (as Mr Siracusa if you can’t take my word for it…) which also happens to be technically much more complex than the iPhone case as Peter outlined here.

  8. Allan Donald Says:

    Even with the lack of pre-fetching, I maintain that this is an improvement: Files are available to work with earlier than they were before.
    Not to come over all Siracusa, but the Finder is supposed to be spatial: the files *are* their icons. If you walked into a crowded room and everyone’s face was a generic blank that was slowly replaced by their true features, wouldn’t that freak you out? Same problem with the files. That a go-ahead list-view-toting engineer can be clicking on the files while the icons are fetched is one thing; for everyone else it’s a metaphor-destroying flash of unstyled content.

    I appreciate that it’s hard to do, but my LC II could handle it. Disks may have gotten larger, but so has my CPU. And doing hard things so that the user has it easy is supposed to be the point, isn’t it?

  9. Riccardo Mori Says:

    Thanks for this explanation, Peter. I had noticed this behaviour and I didn’t know what to make of it. As you said, this was introduced in Mac OS X 10.6, so now I’m curious to know what has changed in 10.6 to make it behave this way, because in this regard (icon redrawing), the Finder in my PowerBook G4 with Mac OS X 10.5.8 seems almost faster.

    Cheers,
    Rick

  10. Peter Hosey Says:

    Allan Donald: Disks have gotten larger and faster, which is what really matters. The real problems are the cases where disks aren’t fast (e.g., scrolling a Finder window on a spun-down disk), or are on other (possibly distant) machines.

    I’m not sure what to say about machines like your LC II. For local browsing, of course it worked fine (most of the time), and a modern Mac could work fine even more of the time. But I wonder about network browsing, as both local networks and Internet connections were far slower back then. That’s the biggest slow point, even today.

    That a go-ahead list-view-toting engineer can be clicking on the files while the icons are fetched is one thing; for everyone else it’s a metaphor-destroying flash of unstyled content.

    Fair point. If Apple agrees with you, they may change the behavior back, at least for browsing local volumes (spun-down disks are a 10% case and disk thrashing isn’t entirely the performance-killer it once was). You may want to file a bug and state your case directly to them.

  11. Dave M. Says:

    Yes, the Springboard shows correct icons as you slide from page to page. However, also note that when the Springboard has to “render” icons on pages not being displayed but are soon to be displayed since the user is sliding from page to page quickly, that Springboard will appear to “lock up” while it renders the missing icons. I would prefer the generic icons over those pauses any day of the week.

    Granted, they wouldn’t look good, but does it really look all that good having the Springboard freeze while it tries to make the next screen look “pretty”?

  12. Dave H Says:

    What drives me nuts is when I open a Finder window to a folder on one drive and everything grinds to a halt while the Finder spins up my backup drives looking for… something. Evidently it thinks that there might be something relevant on the other drives (an app that claims one of my files, perhaps?).

    IIRC, this can happen in open/save dialogs, too.

  13. Steven Fisher Says:

    Peter Hosey:

    I’m not sure what you’re expecting FSEvents to do here. All FSEvents does is tell the application “the directories in which event(s) occurred”. It doesn’t tell the app anything about the directories, nor about anything in them.

    Yes, I know that. :) Knowing a directory has changed is enough to invalidate cache entries, though. Mac OS X can get a lot more aggressive about caching things (even between sessions and restarts) than it has been in the past. If a directory can’t be changed without a daemon hearing about it, there’s no reason not to cache it’s size between restarts. Likewise, if the entire Applications directory hasn’t changed, there’s no reason all the icons in it can’t be cached simply between restarts.

    (Resubmitted as I missed the spam-prevention question.)

  14. Gwynne Raskind Says:

    Dave H:

    What drives me nuts is when I open a Finder window to a folder on one drive and everything grinds to a halt while the Finder spins up my backup drives looking for… something. Evidently it thinks that there might be something relevant on the other drives (an app that claims one of my files, perhaps?).
    IIRC, this can happen in open/save dialogs, too.

    I have this problem constantly, usually at completely random times that don’t have anything to do with filesystem access at all. Using fs_usage I was able to trace it to fseventd poking about in /Volumes/Backup/.fseventd/<some numbers here>, and there I was stuck, as I have no idea what any of that is about. Since my backup drive takes some 5-8 seconds to spin up, the result is I spend a lot of time staring at my screen waiting for otherwise instantaneous things to happen. It gets particularly annoying when I’m debugging code that deals with open/save dialogs; what should be 10 seconds spent testing my latest change becomes 20 seconds when the Open panel beachballs the application – 5-8 seconds spinning up the drive, and another several for me to recover from my boredom at waiting for the rainbow to go away and continue testing.

    As for the Finder, in all honesty I think its inability to cache icons properly is one of its lesser issues. .DS_Store files littering the filesystem without actually remembering what the window’s supposed to look like, anyone?

Leave a Reply

Do not delete the second sentence.