Let1kWindowsBloom results for Mac OS X

This page was originally created in late 2001. Results are for antiquated versions of the Mac OS X operating system...

UPDATE 21/11/2005: I've updated this page to include some results from Tiger. See below.

I've been making civilised attempts at switching entirely over to MacOS X since its initial release but have found the OS´s performance to be disappointing. I have therefore followed the progress of the OS with keen interest in hope of further improvements, making tests with a few tools I have found online. The tool whose results I want to discuss is Rob Terrell's Let1kWindowsBloom.

This tool measures the time it takes to open and close 1000 windows and can be downloaded here. I ran several tests with this app, each time changing some environmental variables to see how they affected performance. Some of these variables could be changed by altering settings in System Preferences, but others required third-party tools, the ones below:

ShadowKiller - An app that removes window shadows in MacOS X

Duality 3 - Akin to MacOS 9's Kaleidoscope, this utility lets you change themes.

The environmental variables I changed during the testing were the following:

Opaque Aqua - A theme identical to Aqua, but with no transparencies.
No background image - Background in MacOS X set to "Solid Color"
Thousands of colors - Changed to 16 bit color
No shadows - Shadows removed with ShadowKiller

The results below were got by running Let1kWindowsBloom three times under each setting and calculating the average. In all cases the Dock was hidden and no other running applications, with bouncing in the Dock disabled. The computer used was a G4/450Mhz Sawtooth with 640MB of RAM and the stock ATI Rage 128 Pro. A setting marked "X" is on, off is "-".

Results in MacOS X 10.1.3

Opaque Aqua
No background image
Thousands of colors
No shadows

Result in seconds

-
-
-
-

55

X
-
-
-

54

-
X
-
-

54

-
-
X
-

53

-
-
-
X

45

X
X
-
-

54

X
X
X
-

48

-
X
X
-

49

-
-
X
X

41

X
X
X
X

38


It seems that neither transparency nor the background image are important variables in this case. The greatest speed improvement comes from changing to 16-bit color and removing the window shadows, especially the latter. Unfortunately the interface becomes extremely uncomfortable with the shadows disabled due the lack of depth in layered windows.

Results in MacOS X 10.2 (Jaguar build 6C115)

New 16/08/2002

Unfortunately 10.2 seems to have broken the functionality of Duality and ShadowKiller so I could not include them in my tests, but here are the results. As before, the Dock was hidden, bouncing turned off and no other running application, with the results a calculated average of three runs.

No background image
Thousands of colors

Result in seconds

-
-

54

X
-

52

-
X

50

X
X

49

 There seems to be little or no improvement in Jaguar, which is disappointing when you consider the results of running the same test in MacOS 9.

Results in MacOS 9.2.2

No background image

Result in seconds

-

13

X

12



Results in Mac OS X 10.4.3

Unfortunately I did not have the original test machine available, so a scientific comparison is not possible. However, I got the following results on a 1.25Ghz Powerbook Aluminum, with 1.25GB of RAM and a 64MB ATI9600 video card.

OptimizationsResult in seconds
None12
No background image, no window shadows12
Thousands of colors, no shadows12
No Finder running11

Perhaps unsurprisingly, quitting the Finder seems to improve results, probably because the Desktop doesn't have to be redrawn every time a window is disposed of -- only the background image.



Source code to Let1kWindowsBloom

/*
 * Creates and destroys 1000 windows using Carbon or Classic
 *
 * By Rob Terrell 
 * http://www.vgg.com/rob/
 * 
 */

#include Dialogs.h
#include Fonts.h
#include MacWindows.h
#include Menus.h
#include QuickDraw.h
#include TextEdit.h

#include Timer.h
#include stdio.h
#include sioux.h

static void Initialize(void)
{
#if !TARGET_API_MAC_CARBON
	InitGraf(&qd.thePort);
	InitFonts();
	InitWindows();
	InitMenus();
	TEInit();
	InitDialogs(nil);
#endif
	InitCursor();
}

void main(void)
{
	int c;
	WindowPtr w;
	Rect r;
	UnsignedWide start, end;
	long elapsed;
	
	Initialize();
	SetRect(&r, 100,100, 500, 300);
	
	Microseconds(&start);
	
	for (c=0; c<1000; c++) {
		w = NewWindow(nil, &r, "\pWindowTest", true, 
                          0, (WindowRef)-1L, false, 0L);
		if (w!=nil) DisposeWindow(w);		
	}
	Microseconds(&end);
	
	elapsed = end.lo - start.lo;
	SIOUXSettings.asktosaveonclose = false;
	printf("Total time to create and dispose %i windows: %d seconds
	(%i microseconds) ", c, elapsed / 1000000, elapsed);
	
}

Let1kCocoaWindowsBloom

For the sake of curiosity, I decided to alter Let1kWindowBloom and make it use Cocoa calls to create 1000 windows consecutively. There seems to be little performance difference, as both almost certainly use the same lower-level calls. However, it can be interesting to see the difference in speed between buffering types. Click here to download (includes source and XCode project. And here's the code:

/* Let1kCocoaWindowsBloom
 * Creates and destroys 1000 windows using Cocoa calls
 *
 * By Sveinbjorn Thordarson, based on code by Rob Terrell 
 * http://sveinbjorn.sytes.net
 * 
*/
#import Foundation/Foundation.h
#import Cocoa/Cocoa.h
#import Carbon/Carbon.h

int main (int argc, const char * argv[])
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int c;
    NSWindow *w;

    // window style mask
    // Try changing this to a different combination of these values
    // to get a feeling for the overhead involved in drawing different 
    // window types
    //
    // NSTexturedBackgroundWindowMask
    // NSResizableWindowMask
    // NSMiniaturizableWindowMask
    // NSBorderlessWindowMask
    // NSTitledWindowMask
    // NSClosableWindowMask
    unsigned int styleMask = NSTitledWindowMask;

    // backing store -- can be NSBackingStoreBuffered, 
    // NSBackingStoreRetained or NSBackingStoreNonretained
    // The last of these is, of course, the fastest
    unsigned int bst = NSBackingStoreNonretained;

    // Window size -- performance decreases linearly with window size
    NSRect r = { { 100, 100 }, { 400, 200 } };
	
    UnsignedWide start, end;
    long elapsed;
	
    Microseconds(&start);
	
    for (c=0; c<1000; c++) 
    {
        w = [[NSWindow alloc] initWithContentRect: r 
                styleMask: styleMask 
                backing: bst 
                defer: YES];
        [w setTitle: @"WindowTitle"];
        [w orderFront: [NSApplication sharedApplication]];
	if (w != NULL)
	    [w release];
    }

    Microseconds(&end);
    elapsed = end.lo - start.lo;	
    printf("Total time to create and dispose %i windows: %d seconds (%i microseconds) ", 
              c, elapsed / 1000000, elapsed);

    [pool release];
    return 0;
}