Go forward in time to October 2005.
Profiling the file chooser, part 3: Don't load folders unnecessarily
In parts 1 and 2 I got a pretty nice speed-up in the file chooser by removing work that doesn't need to be done.
Some time ago I realized that the file chooser loads your $cwd unnecessarily at startup, even when you set it to load another folder later. Moreover, even if you did that, the file chooser would reload the file list upon being mapped. This is because some apps, notoriously the GIMP, create a single file chooser instance that they keep around for the whole lifetime of the program; they unmap and remap the chooser instead of destroying it and creating it again. The file chooser has to reload its file list if it gets unmapped and remapped, because the underlying file system may not give notifications about changed files.
So, today I wrote a little unit test for the intended behavior — don't (re)load things unnecessarily — and fixed the file chooser code. I ran the timing code again, and the current scoreboard is this:
| First run | Average of 100 runs | |
|---|---|---|
| Code as of 2005/09/09 | 3.180 sec | 0.818 sec |
| Code as of 2005/09/26 | 2.294 sec | 0.483 sec |
| Code as of 2005/09/27 | 1.056 sec | 0.366 sec |
So, we are down to 0.366 sec, from being at 0.818 sec in the beginning. You can get the patch here; it's in CVS HEAD now. Also, yesterday's patch is now in the gtk-2-8 branch as well.
Dom: About excessive complexity, think of what you say about OOo: "But these things tend not to require a JVM, VB interpreter, thousands of C++ vtables, hundreds of images from on-disk, and its own CORBA-like component system in place before the first window gets rendered to screen."
Think of MS Office. VM? Check - Office uses p-code. VB interpreter? Check. Thousands of C++ vtables? Check. Hundreds of images? Check. Component system? Check. And it still loads faster.
MS has people working full-time on performance issues, which is a luxury we don't have.
Profiling the file chooser, part 2: Fixing OPEN mode
The last time I found that the file chooser was always creating its widgets for the "save" modes, even if it didn't need them, and this was the main thing slowing it down on startup. I wrote a little unit test for the expected behavior, fixed the code, and ran it with the unit test.
My timing code creates and destroys a file chooser in OPEN mode a hundred times, showing my home directory, and takes timings. The current scoreboard is this:
| First run | Average of 100 runs | |
|---|---|---|
| Code as of 2005/09/09 | 3.180 sec | 0.818 sec |
| Code as of 2005/09/26 | 2.294 sec | 0.483 sec |
As before, the first run is suspicious because the buffer cache is semi-cold. This still needs to get profiled and fixed at some point if we want all file choosers to appear in under 0.1 sec. But so far, we've managed to reduce the average startup time from 0.818 sec. to 0.483 sec. I've committed the patch to CVS head; you can get it here if you want to play with it in the stable branch.
Also, this only affects file choosers in OPEN and SELECT_FOLDER modes. Those in the "save" modes (SAVE and CREATE_FOLDER) are still as slow as before. But hey, one thing at a time.
Quickie bookmarks for the file chooser
The bookmarks pane in the file chooser is great for mouse users. If you are a touch typist, you may prefer the following crude form of bookmarks. Stick this in your ~/.gtkrc-2.0:
binding "some-shortcuts" {
bind "<Alt>T" {
"location-popup" ("/home/federico/todo.txt")
}
bind "<Alt>M" {
"location-popup" ("/mount/name/with/an/obnoxiously/large/path/")
}
}
class "GtkFileChooserDefault" binding "some-shortcuts"
With that, you can use Alt-T Enter to open your todo.txt, and Alt-M Enter to go to a folder with an annoying name.
Emmanuele Bassi has been busy implementing "recently used files" and bookmarks support for GTK+. With this, we can kill that part of libegg and have code that is properly shared across applications. One of the nice things about Emmanuele's work is that he is profiling GMarkup as he goes along.
Dan Winship writes some excellent points on sanitizing containers with private children, mainly for the benefit of GUI editors.
I hadn't seen Lorenzo Colitti's analysis of the GNOME login sequence; his bootcharts are pretty interesting.
Profiling the file chooser, part 1: Superfluous widgets in OPEN mode
The last time I measured performance in GtkFileChooser, I was looking into why the file chooser takes so much time to start up. Those tests were flawed for a number of reasons.
First, I deliberately created an empty directory and made my test program start up there. I was trying to profile the file chooser's raw startup time without loading any files into it. But that's not a typical usage case. A typical case is this:
You launch a program. For people who do this from the panel's launchers, the program's cwd is $HOME. For people who do it from a terminal, the program's cwd is of course wherever you were in the shell at that time.
You hit File/Open in your program. Last time I smacked my forehead upon discovering that the file chooser reads your cwd even if it doesn't need to.
In the typical case, your program will end up scanning $HOME twice, or else scanning $HOME and some other folder if the program calls gtk_file_chooser_set_current_folder().
So this time I wrote a little program which first sets the cwd to $HOME, and then creates and destroys a file chooser a hundred times; it does this for a file chooser in OPEN mode. I ran that under sysprof, looked for the function with the biggest cumulative time, and the results were surprising:
That bad boy is inside the code for GtkFileChooserEntry. I expected most of the time to go into file system fuckery due to scanning folders more than needed, but the main culprit turns out to be GtkFileChooserEntry. The entry does a bunch of string collations when adding items to its completion list. But what completion list? The Open dialog doesn't even have an entry!
Actually, there's a hidden entry somewhere in the file chooser (chooser->priv->save_file_name_entry). It is the one that would show up if you switched the chooser to be in SAVE mode. So in OPEN mode, we are paying for things we can't even use or see.
I wrote a script that generates an strace of the test program, and then extracts very trivial timings from it. I took timings before doing any modifications to the file chooser's code, and then took timings again after #ifdef-ing out all the coded that references the save_file_name_entry. This table shows the number of seconds that the file chooser takes to come up:
| First run | Average of all runs | |
|---|---|---|
| Original code | 3.180 sec | 0.818 sec |
| After changes | 0.893 sec | 0.444 sec |
I'm suspicious of the "First run" column, since that result depends a lot on whether the cache is warm and other factors. Still, the results in the second column look promising. They mean that after making the proper changes (instead of just #ifdef-ing code), the file chooser's startup time will be about half of what it used to be.
I need to shuffle some code around to make this happen, as right now the file chooser's startup sequence creates all the widgets it may ever need, including the OPEN and SAVE widgets, and then hides the ones that don't correspond to its current mode of operation. The code assumes that all the widgets are present all the time; I need to change that.
The scripts and the testing program are here.
You'll need GTK+ from the HEAD branch of CVS; the 2.8 branch won't do. I'll be backporting the changes to 2.8 when get them working.
Christian Neumair deserves beer. He's the guy that knows all the Nautilus bugs by heart and will point you to relevant bug numbers in a second, even if those bugs have been open since 2001.
Adrian makes some back-of-the-envelope calculations to compute how much electricity is consumed by playing World of Warcraft. And a friend of his talks about a nifty dongle to measure power consumption, which lets you see spikes when you peg the CPU.
With the latest happennings in bug #171073, we are very close to having Nautilus's trash work just right for removable devices. The only missing bit is to have the trash window update the item counts correctly — I haven't been able to figure that out.
The trash in Nautilus uses a fancy "merged directory" mechanism. It is meant to display all your Trash directories together, that is, all the .Trash* directories from your local and removable volumes. It looks to me like this never had the necessary infrastructure underneath, so it was never very well tested, and people just assummed that it is one of the things that never worked right anyway: the last interesting change to nautilus-merged-directory.c happened in 2002.
But now, with HAL and volume monitoring and everything, we can have trash that Just Works(tm). It would actually be nice to have a way to empty each volume's trash individually. This would solve the question of "how do I free up space in my USB stick?".
Go backward in time to August 2005.
Federico Mena-Quintero <federico@gnome.org> Wed 2005/Sep/07 16:02:21 CDT