Intel Mac performance

I should receive my new iMac tomorrow, so my tests were done on my DTK. Several sites have done performance tests showing the Intel iMac to be slower than a G5. However, anyone using a G4 (as I am) will see a big speedup with an Intel mac. I use a PowerBook as my primary system, so I’m forced to use a lower-performance G4. If and when I get a MacBook, it will outperform my PowerBook by a huge margin.

I did some very crude tests running a small command line program that writes some system information to a file and timing it using time. Even running in emulation, the DTK is faster than my PowerBook.

On my PowerBook:
[mike: Development]$ time ./inventory >/tmp/invreal 0m0.642s
user 0m0.006s
sys 0m0.046s

On the DTK, native version:
[mike: Development]$ time ./inventory >/dev/null

real 0m0.031s
user 0m0.005s
sys 0m0.012s

Emulated version on the DTK:
[mike: Development]$ time ./inventoryppc >/tmp/inv

real 0m0.368s
user 0m0.090s
sys 0m0.045s

DTK Exchange

I’ll be getting a new Intel iMac thanks to Apple’s DTK Exchange Program. I’m now setting up a server-based home directory, so I can access my email & other stuff from both my PowerBook and the iMac, which will become my primary machine.

Universal builds for PPC & x86

The latest version of XCode allows you to specify separate settings for x86 & PPC code, although it isn’t really obvious how to do it. After some digging I figured it out.

Some of the build settings such as SDKROOT & GCC_VERSION allow you to specify which architecture they apply to by appending _ppc or _i386 to the settings name. Here’s how I’m able to build a universal binary that will run on OS X 10.2 or later (which requires it to be built with GCC 3.3) as well as x86.

First, set up the project & target settings as required for building the x86 version. Then add the following variables to the build panel of the project or target settings window (hit the ‘+’ button to add a variable & edit the name).

MACOSX_DEPLOYMENT_TARGET_ppc  10.2
GCC_VERSION_ppc               3.3
SDKROOT_ppc                   /Developer/SDKs/MacOSX10.2.8.sdk

Those settings will override the defaults when building a PPC binary, while the defaults will be used when building x86.

Intel porting tip

I now have most of my code working on the Intel Mac. Once again, I need to reiterate this bit of advice: Never assume Macs are Big Endian.

We already have a cross platform product that works on both Macs & PCs. Since it deals with binary data read from a file, it needs to handle byte ordering issues. In our code we used #ifdef __MAC__ for pieces of code that are sensitive to byte ordering. We also used #ifdef __MAC__ for a lot of other Mac-dependent stuff that had nothing to do with byte ordering. This was the cause of almost all of the problems I had with the port.

I’m sure a lot of other developers are doing the same thing. If you ever plan to port to Intel, go through your code and change any such tests to use #ifdef __LITTLE_ENDIAN__ or #ifdef __BIG_ENDIAN__ instead. Those things will bite you badly when you port to Intel. Better yet, use any of the byte order utilities whenever possible.

Porting to Intel V

For any networking code, make sure you’re using htonl & htons when building a socket address structure. If you look at the structure you’re passing to connect(), the IP address & port should appear reversed. Dealing with these byte ordering issues can be very confusing. Always be aware of what byte order is expected for any data used externally or passed to system calls.

Porting to Intel IV – W00t!

I got a major part of my application working on the Intel Mac.

Here are a few macros I came up with to handle the byte ordering issues when reading & writing binary data from a file:

#define W(w) ((unsigned short)w)
#define WSWAP(w) (W((W(w) << 8 ) | (W(w) >> 8 )))
#define DW(d) ((unsigned long)d)
#define DWSWAP(d) ((DW(d) >> 24) | ((DW(d) >> 8 ) & 0xff00) | ((DW(d) & 0xff00) << 8 ) | (DW(d) << 24))

#if defined(__LITTLE_ENDIAN__)
#define LITTLE_ENDIAN_WORD(w) W(w)
#define LITTLE_ENDIAN_DWORD(d) DW(d)
#define BIG_ENDIAN_WORD(w) WSWAP(w)
#define BIG_ENDIAN_DWORD(d) DWSWAP(d)
#else
#define LITTLE_ENDIAN_WORD(w) WSWAP(w)
#define LITTLE_ENDIAN_DWORD(d) DWSWAP(d)
#define BIG_ENDIAN_WORD(w) W(w)
#define BIG_ENDIAN_DWORD(d) DW(d)
#endif

Porting to Intel III

The XCode debugger (and gdb) will confuse you with word & long values. For example, I have an IP address & port stored as the bytes 00 50 c0 a8 0 64 (that’s 192.168.0.100:80). Displaying memory in the debugger will show it as a8c05000 00006400 if you use the default word size of 4. Setting the word size to 1 will show the proper values.

Porting to Intel II

Never assume Macs are big-endian. I found code which uses #ifdef __MAC__ to decide whether byte order swapping is required – that’s just plain wrong.