by Stephen Satchell
How to Port Linux* Applications
Porting your Linux* applications to the Itanium® architecture can be straightforward if you follow these suggestions, which highlight the key areas you need to tackle.
In prior articles we have looked at generic considerations when porting existing applications to the Intel® Itanium® architecture. Now let's talk specifically to Linux* programmers.
If you are working in languages that do not compile to native IA-64 code - scripting languages like PERL*, PYTHON*, PHP*, M4*, AWK*, JAVA* et al, SQL, shell scripts, bc scripts, and so forth - your code as currently written will work with suitably modified script engines that have been ported to the Itanium-based platform. Check the documentation to see if the engine does require you to make changes (most won't).
Are you working in C, Fortran, or C++? Read on.
Make Plenty of Workspace
This is going to sound stupid: Before you even think about Itanium porting, get a brand new drive of at least 18 GB capacity for your existing development system. If you can afford to get a SCSI drive (and adapter) I strongly recommend you do so. Part of porting Itanium software is finding and fixing size-change problems, so you are going to be compiling your source code many times to find and fix all the problems. As you should: Let the computer do as much of the book-keeping as it can.
The larger playground means you will have room for the different tools that are available. Start with the Native User Environment (NUE),*, a userland simulator for Itanium that lets you use your existing computer as a development platform.
Finally, to try out your newly ported application on your old, trusty development system, you will also need the simulator root file system* to be able to run your freshly compiled u rland programs.
You may want to play with multiple compilers: the egcs port for Itanium that comes with the NUE, and the SGIPro compiler that is available separately. HP* distributes its tools via CD-ROM, so you don't have to download 250 megabytes of stuff from their Web site. (I did, and got yelled at by my DSL supplier's network administrator...)
The Linux* Simulator from HP* comes in the form of RPM (Red Hat Package Management) files, so be sure you also have the appropriate package manager tools available. Red Hat, of course, is a piece of cake. Debian users use the "alien" utility to make the necessary conversion. The NUE is a tarball. The SGI compiler is an RPM file.
Rules of Thumb
The most painful part of porting non-IA-64 code to the Itanium® architecture is this: Integer variables cannot hold pointers. This is a departure from the original Kernighan & Ritchie idea that "integer" should be defined as the most "natural" size the machine uses. In the Itanium-based system, the integer and unsigned types are 32 bits, not 64. This means that a lot of code originally written for IA-32, as well as for Motorola 68000 and other 32-bit processors would work just fine when pointers and integers are intermixed.
To find violations, you need to turn on warnings in the egcs or sgicc compiler, and take heed of all of "warning: cast to pointer from integer of different size" and fix the code. Bad things will happen if you don't.
Unless you are porting code that has already successfully run on other 64-bit processors (Alpha, PA RISC, SPARC64, etc.) you may also need to look for places where your code is not 64-bit clean. For example, HP* relates in their experience with porting tools to IA-64 Linux that the version of ping they converted made assumptions about the timeval structure, specifically that it was 8 bytes long, instead of the 16 by defined in the IA-64 Linux.
Another big problem will be hand-tuning that was done on other architectures, particularly hand-coded assembler. Some developers have a bad habit of removing the original C code when in-line assembler is added. Assembler on IA-64 is such a pain in the butt that it's better just to stick with what the compiler generates. If you just can't stand leaving C code alone, then use a separate file that defines the assembler function and call it from the C code. Use register-passing to keep the performance up - the function-calling system in Itanium processors is relatively inexpensive.
Keep Them Data Types Straight
The char and short types are as you would expect, one and two bytes respectively. The int type is four bytes. The long and the long long type are eight bytes. The floating types are pretty much the same as in other systems: the float type is four bytes, the double type is eight bytes, and the long double type is ill-defined in length at this time. Pointers are, of course, eight bytes long.
When going through and checking variables, consider using the unsigned versions wherever possible. The reason is that in Itanium architecture the shorter integer types are loaded as unsigned quantities into the 64-bit registers, and if the variable is declared a signed type the code generator has to add an instruction to extend the sign properly. Changing signed to unsigned may reduce code bloat significantly.
Byte-order in words is little-endian. This is important only if you export data in binary form within structures. Follow the usual rules concerning endian management if it's important to your application. Most apps already handle the problems that endian difference can cause.
Variable alignment is critical in Itanium programming. This means that structures that mix integer and pointer types may need to have their elements shuffled so as to avoid causing mis gnment. The alignment rules are simple: if the start address (in bytes) is a multiple of the length, you are in great shape. Don't worry about bit-fields, because the Itanium architecture includes instructions that support bit-fields nicely.
I Can See Parallel Now
The above rules of thumb will get your compiled applications running on Itanium-based systems. You aren't done yet, though. Practices that cost you only a little bit when running on the Intel® Pentium® III microprocessor will cost you dearly when you move to the Itanium microprocessor - indeed, the cost is that your application will run about as fast on the new system as it did on the old one! To fully take advantage of the new processor, you need to do some tweaking to increase the amount of parallelism in your code available to the compiler so the Itanium processor can do multiple things at once.
Profile your newly-minted application and determine where it spends its time. Then go through those functions and recode long strings of statements in which each statement depends on something from the previous statement. Check loops to see if you are using a single variable as the base for computed array offsets - consider creating separate variables that are manipulated separately so that they can be manipulated in parallel.
One optimization that isn't around yet, but is coming, is the ability for the compiler to reorder function statements for those functions declared with the static keyword. In many cases, "helper" functions aren't used outside of the file they appear in, so adding "static" can reduce maintenance headaches as well as giving future itanium compilers some additional optimization ammo.
Finally, keep up to date on tools. With each release of the compilers, expect to see better and better code optimization built into the beasts.
About the Author
Stephen Satchell has for the past three decades designed, written, debugged, measured, enhanced, and maintained software on a wide variety of computers, including the highly-parallel ILLIAC IV. When not writing or utilizing benchmarks to write critical-analytical reviews of computer products, he works on Linux development and telephony over coax and the Internet. He can be reached at firstname.lastname@example.org