Guide to porting from Solaris to Linux on POWER

Six steps to accelerate your porting tasks

Accelerate your porting efforts by following this six-step guide. Learn the differences between Solaris and Linux® on POWER® that you commonly encounter during a port. Get an introduction to the development environment for Linux running on IBM POWER processor-based systems, and see how Sun's compiler/linker switches compare with those of GNU GCC and the IBM native compiler. Finally, learn about tools for performance analysis and software packaging for Linux on POWER. [This article has been updated to reflect the latest product versions. -Ed.]

Chakarat Skawratananond (chakarat@us.ibm.com), Linux on POWER Technical Consultant, IBM

Chakarat Skawratananond is currently a technical consultant in the IBM eServer Solutions Enablement organization, where he assists ISVs in enabling their applications for Linux on POWER architecture. He has published a number of articles for IBM developerWorks in the area of Linux migration. He can be contacted at chakarat@us.ibm.com.



Sean Perry, Senior Developer, IBM  

Sean Perry is a senior compiler developer in the IBM Rational group in Toronto. He has almost 20 years of experience writing C and C++ compilers for many different operating systems including AIX, Linux/ppc, Solaris, and zOS.



Matt Davis, Consultant, Freelance

Matt Davis was a Linux on POWER consultant in Austin, Texas before he came to IBM in May 2000 (while still studying at the University of Texas from which he earned two degrees with academic honors). He has been engaged with the Linux on POWER development community for nearly five years and is the author of roughly two dozen papers and articles regarding Linux on Intel and POWER architectures. In addition to involvement in the Open Source Community, Matt spends his spare time researching life sciences at the University of Texas.



08 September 2009 (First published 15 February 2005)

Also available in Russian

Generally, porting Solaris-based applications to Linux is a simple task since both Solaris and Linux are based on UNIX®. Porting often requires only a recompile with minor changes in some compiler and linker switches. Only when applications depend on system-specific implementations do they require major modifications. While both Solaris and Linux are designed to follow standards, differences in their implementations sometimes occur. This article highlights these differences and recommends possible solutions if an equivalent on the Linux side is not available.

The article is organized as follows:

  • A porting roadmap
  • Porting notes, including endianness and 32- and 64-bit porting issues
  • Development environment for Linux on POWER
  • Differences between Solaris and Linux
  • Performance tuning and software packaging tools available for Linux on POWER

We focus on migration from Solaris running on 32- or 64-bit SPARC, Intel®, or AMD x86 architectures to Linux running on POWER architecture. On the Solaris side, we base our discussion on version 9 and later. On the Linux side, we focus on the distributions available on IBM POWER processor-based servers: SUSE LINUX Enterprise Server (SLES) Version 11 and Version 10 service pack 2, and Red Hat Enterprise Linux (RHEL) Version 5 update 2.

Porting roadmap

Step 1: Prepare

You need to understand the differences between the source and target platforms. For example, you need to know if the endianness on the source platform is different from the endianness on the target platform. If your source platform is Solaris/x86, then consider endianness since Linux on POWER is big-endian, while Solaris/x86 is little-endian.

Determine if all the required third-party packages (such as databases and class libraries) are available on the target platform. For 32-bit applications, consider whether you need to migrate to 64-bit. The next section on General porting notes includes more information about endianness and 32- to 64-bit issues.

Also, decide which compiler to use on the target platform. If your application is performance sensitive, consider using the native compiler. The Development environment for Linux on POWER section gives more information on the available compilers for Linux on POWER.

Step 2: Configure

This step involves setting up the development environment, setting environment variables, making changes to makefiles, and so on. At the end of this stage, you should be ready to start building your application.

Step 3: Build

This step involves fixing compiler errors, linker errors, and more. It is not unusual for code to go through several iterations of Steps 2 and 3 before a clean build is produced.

Step 4: Runtime test and debug

After the application is successfully built, test it for runtime errors.

Step 5: Tune for performance

Now the ported code is running on the target platform. Monitor performance to ensure the ported code performs as expected. If not, you need to tune for performance. The Performance tuning section describes the performance tuning tools available for Linux on POWER.

Step 6: Package

Will you have to distribute the resulting code to others? If so, what packaging method do you want to use? Linux provides several ways to package your application such as a tarball, self-installing shell script, and RPM. The Software packaging section provides more information about software packaging for Linux.


General porting notes

This section helps you decide when to migrate applications from 32- to 64-bit, and covers considerations for applications crossing an endianness barrier. Applications migrating from Solaris on x86 platforms will cross an endian barrier. Developers familiar with 32- to 64-bit migration and byte ordering may wish to skip to the next section, "Development environment for Linux on POWER."

From 32 to 64 bits

Once you decide to port to Linux on POWER, you may also consider porting the application to a 64-bit one if it is currently at a 32-bit level; however, 32-bit applications that do not require 64-bit capabilities should remain 32-bit ones. Any porting effort involving a migration to 64 bits should be taken in two steps:

  • First, migrate to the target platform as a 32-bit entity.
  • Then, and only then, proceed to the 64-bit level.

Otherwise, issues arising from the platform migration can be easily confused with issues arising from the migration to 64 bits. That said, an application should be ported to 64 bits if possible for these reasons:

  • Benefit from more than 4GB of virtual address space.
  • Benefit from more physical memory (greater than 4GB) if users are likely to deploy it on a system with more than 4GB of physical memory.
  • Benefit from 64-bit size integers.
  • Benefit from full 64-bit registers to do efficient 64-bit arithmetic.
  • Use files larger than 2GB.

The application can remain 32 bits and still run on the 64-bit Linux on POWER kernel without requiring any code changes. IBM Linux on POWER processor-based servers support both 32-bit and 64-bit applications running simultaneously on the 64-bit architecture without any performance degradation between modes.

When converting 32-bit applications to 64-bit applications, two basic issues are likely to arise: data type inconsistency and interoperation between applications using different data models.

The 64-bit environment uses a different data type model than the 32-bit environment uses. For Linux on POWER, the ILP32 model is used in the 32-bit environment, while the LP64 model is used in the 64-bit environment. The differences between these two models are the sizes of long and pointer. Therefore, when an application is converted from ILP32 to LP64, fundamental changes in data type occur. Longs and integers are no longer the same size. Pointers and integers are no longer the same size. Also, the size of objects like structs and unions is bigger in the 64-bit environment if they include pointer or long data types. Other issues commonly spawned by these differences include:

  • Data truncation
  • Pointer assignment
  • Data alignment
  • Data sharing

IBM XL compilers provide the -qwarn64 option to help check for possible data conversion problems between 32- and 64-bit modes.

The topic of migrating applications from 32- to 64-bit environments is covered extensively in other publications, so we won't go into detail about how to deal with these porting issues here. (Refer to "Porting Linux applications to 64-bit systems" for more information.)

Byte ordering (endianness)

Since both SPARC and POWER architectures are big-endian, there are no endianness issues when porting applications between these platforms. However, if you are porting Solaris on x86 applications to Linux on POWER, you may need to deal with endianness portability issues since x86 is a little-endian architecture.

Endianness issues are often encountered during the process of migrating applications from one type of architecture to another. Endianness is the ordering of a data element and its individual bytes as they are stored and addressed in memory. There are two types of endianness: big-endian and little-endian.

For big-endian processors such as POWER, PowerPC™, and SPARC, when a word is placed in memory, starting from the lowest address, the most significant byte is placed first. For little-endian processors such as Intel and Alpha processors, the least significant byte is placed first.

Figure 1 shows how big-endian and little-endian processors place a hexadecimal value, like 0x89ABCDEF, in memory:

Figure 1. Byte ordering (endianness)
Byte ordering (endianness)

One source of endianness problems is non-uniform data reference. It is often featured by data type mismatches resulting from either data element casting, use of a union data structure, or the use and manipulation of bit fields. Listing 1 shows the endianness issue due to the non-uniform data reference using a pointer:

Listing 1. Non-uniform data reference
int main() {
        int value;
       char *p;
       p = (char*) &value;
      value = 0x89ABCDEF;
      printf("%X.%X.%X.%X\n" p[0], p[1], p[2], p[3]);
return 0;
}

Development environment for Linux on POWER

This section describes the fundamental elements of a Linux on POWER development environment, including distributions, compilers, and how Java™ technology fits in.

Linux distributions

Linux for POWER is offered in enterprise form by two leading Linux vendors, SUSE Linux and Red Hat. Both distributions are highly respected by the Linux community, and the differences between the distributions and versions are driven more by when each version is released. Most developers should have no problem deploying software from the same code base on either offering:

  • SLES11
    Announced in early 2009, Novell's SUSE Linux Enterprise Server version 11 provides significant new kernel improvements, enhancements in virtualization, management, hardware enablement, and interoperability. It includes features and updates designed to handle mission-critical workloads in the data center. SUSE Linux Enterprise Server offers an open, scalable, high-performance data center solution. It is based on the 2.6.27 kernel and provides GCC 4.3.2, glibc 2.9, binutils 2.19.
  • SLES10 SP2
    SUSE Linux Enterprise Server version 10, Service Pack 2 is based on the Linux 2.6.16 kernel and supports all enterprise features of Linux on POWER hardware. The development environment provides GCC 4.1.2, glibc 2.4.31, and the GNU binutils 2.16.91.
  • RHEL5.3
    Red Hat® Enterprise Linux® 5.3 is based on the Linux 2.6.18 kernel and provides GCC 4.1.2, glibc 2.5, and binutils 2.17. RHEL5 includes many enhancements over prior releases. These include per-queue, switchable on-the-fly I/O schedulers, IPv4/IPv6 performance enhancements, and kernel SMP locking enhancements for improved scalability and performance.
  • RHEL4.8
    Red Hat Enterprise Linux 4.8 is based on the Linux 2.6.9 kernel and provides GCC 3.4.6, glibc 2.3.4, and binutils 2.15. The GCC4 package is, however, updated to version 4.1.2. (See Resources for a link to a comparison of the features between RHEL3, RHEL4, and RHEL5 across the supported platforms.)

Compilers

Linux on POWER, like Solaris, offers a high-performance compiler set in addition to the GNU Compiler Collection—the IBM XL C/C++ compiler set. Details about its licensing are available at the XL C/C++ Advanced Edition for Linux Web site. (See Resources for a link.) Here is a brief overview of each compiler set and their advantages:

  • GCC
    For projects developed across multiple platforms where a GCC compiler is the original compiler, the GCC compiler is often used to deploy applications for Linux on POWER. This is especially true for applications where performance is not critical: small utilities, for example. GCC also allows some code prototypes that are only understood by GCC such as GCC-specific macros; however, many of these "GCC-isms" are incorporated in the IBM XL C/C++ compilers.
  • Advance Toolchain
    For projects that can take advantage of the latest gcc and toolchain technologies, an Advance Toolchain package is available for customers who prefer to remain on a GCC compiler. The Advance Toolchain provides a newer gcc compiler version and tuned runtime libraries for Power 6 when using SLES10 and RHEL5. In many cases, gcc compiled applications that take advantage of the Advance Toolchain compiled at a -O3 compilation level will have performance close to the IBM C/C++ compilers compiled at -O3. The advantage of the IBM compilers is the additional headroom available for continued performance improvements and tuning, which can be significant in some cases.
  • XL C/C++
    The IBM XL C/C++ compilers for Linux are available for Power systems. XL C/C++ compilers Version 10.1 are available for RHEL5, SLES10, and SLES11. Earlier versions of the IBM compilers like XL C/C++ Version 8 and Version 9 remain available if you want to build on older Linux distribution versions like SLES 9, SLES10 sp1, RHEL5, or RHEL 4. XL C/C++ compilers offer a high-performance alternative to GCC, as well as a number of additional features. Fortunately, the XL C/C++ compilers produce 32- and 64-bit GNU elf objects that are fully compatible with the objects GCC compilers produce, because the XL C/C++ compilers employ the same GNU libraries, linker, assembler, and binutils as GCC. In fact, functionality formerly offered exclusively by GCC compilers has been ported to XL C/C++ to facilitate source compatibility, including some GCC macros and inline functions, for example. But aside from compatibility, XL C/C++ offers unparalleled performance.

    Sophisticated XL C/C++ optimization routines have been developed for and tailored to the POWER architecture, and it shows. High-performance computing applications, especially those heavily reliant on floating-point operations, often benefit significantly from a simple recompile with XL C/C++.

    While XL C/C++ for Linux on POWER is not free, it is available to developers for a 60-day trial. Details are available at the XL C/C++ for Linux Web site. (See Resources for a link.)
  • XL Fortran
    The IBM XL Fortran for Linux compilers are also available for Power systems if Fortran is desired. XL Fortran Version 11.1 and XL Fortran Version 12.1 are available for RHEL5, SLES10, and SLES11. Details are available at the XL Fortran for Linux Web site. (See Resources for a link.)

Binutils

On Solaris 10, you have the option of using the native build utilities or the utilities provided with GNU. With Linux on POWER, the GNU binutils are used to generate objects with both the XL C/C++ compiler set and GCC. They are reviewed in significant detail at the GNU Binutils site. (See Resources for a link.)

Java technology

Java technology allows developers to deploy across multiple platforms without recompiling code, provided that the Java Runtime Environment (JRE) is compatible with the Java Developer Kit (JDK) for the platform on which the software was developed. The most current Linux on POWER Java development kits are supported on RHEL4, RHEL5, and SLES9, SLES10, and SLES11 by the IBM Developer Kit for Linux, Java Technology Edition version 1.4.2, version 5.0, and version 6. 32- and 64-bit versions are available for no-charge download (Resources) from IBM.


Differences between Solaris and Linux

Now let's review the differences between Solaris and Linux, including system calls, signals, data types, makefiles, compiler and linker options, and threading libraries.

System calls and library functions

System calls are interfaces used by user programs to have the kernel perform a specific function on behalf of the calling thread or process. To execute a system call, a context switch to the privileged kernel mode is required. Library functions are normal C functions. They do not have any context switching overhead since they are part of the address space for each process that uses them. Some Solaris system calls and library functions may not be available on Linux. When this happens, a wrapper-call may have to be implemented on the Linux side.

Linux on POWER currently provides more than 300 different system calls. See a list of system calls in /usr/include/asm-powerpc/unistd.h or /usr/include/asm/unistd.h, depending on which distribution you are using.

Here are a few examples of incompatibilities between Solaris and Linux:

  • regexp() and regcmp(): If you use the routines regexp() and regcmp() on Solaris, you need to replace them with regexec() and regcomp() on Linux.
  • File system interface routines: Solaris file system routines employ vfstab structures and contain vfs in the function name, such as getvfsent. Linux provides equivalent interfaces, but the routines use fstab structures and contain fs in the routine name, such as getfsent. The vfstab structure on Solaris is defined in /usr/include/sys/vfstab.h. The definition of fstab on Linux is in /usr/include/fstab.h.
  • Device Information Library Functions (libdevinfo): The libdevinfo library contains a set of interfaces for accessing device configuration data, such as major and minor numbers. The standard Linux installation does not support this.
  • CPU affinity: By default, a process in a multiprocessor system bounces among several CPUs. Explicitly binding a process to certain CPUs (assigning CPU affinity) may yield performance gain in some cases. System calls for CPU affinity on Solaris are different from those on Linux. The Linux 2.6 kernel provides sched_setaffinity() and sched_getaffinity() for CPU affinity. Please consult the Linux man pages for more information.

Table 1 lists the Solaris system calls that use a different name or signature, or are not available on Linux:

Table 1. Solaris system calls
SolarisLinuxNotes
acl, faclN/AGets or sets a file's Access Control List (ACL)
adjtimeN/ACorrects the time to allow synchronization of the system clock
auditN/AWrites a record to the audit log
auditonN/AManipulates auditing
auditsvcN/AWrites audit log to specified file descriptor
getacct, putacct, wracctN/AGets, puts, or writes extended accounting data
getaudit, setaudit, getaudit_addr, setaudit_addr N/AGets and sets process audit information
getauid, setauid N/AGets and sets user audit identity
getdentsgetdents**Reads directory entries and puts in a file system-independent format. The dirent structure is different on Linux and Solaris.
getmsg, getpmsgN/AGets next message off a stream
getpflags, setpflagsN/AGets or sets process flags
getppriv, setpprivN/AGets or sets a privilege set
getustack, setustackN/ARetrieves or changes the address of per-LWP stack boundary information
issetugidN/ADetermines if the current executable is running setuid or setgid
llseek_llseekMoves extended read/write file pointer
_lwp_cond_signal, _lwp_cond_broadcastN/ASignals a condition variable
_lwp_cond_wait, _lwp_cond_timedwait, _lwp_cond_reltimedwaidN/AWaits on a condition variable
_lwp_infoN/AReturns the time-accounting information of a single LWP
_lwp_killN/ASends a signal to a LWP
_lwp_mutex_lock, _lwp_mutex_unlock, _lwp_mutex_trylockN/AMutual exclusion
_lwp_selfN/AGets LWP identifier
_lwp_sema_wait, _lwp_sema_trywait, _lwp_sema_init, _lwp_sema_postN/ASemaphore operations
_lwp_suspend, _lwp_continueN/AContinues or suspends LWP execution
memcntlN/AMemory management control
meminfoN/AProvides information about memory
mountmount*Mounts a file system. The signatures of this system call on Solaris and Linux are different.
msgidsN/ADiscovers all message queue identifiers
msgrcvmsgrcv*Message receive operation. Linux uses struct msgbuf type in one of its arguments.
msgsnapN/AMessage queue snapshot operation
msgsndmsgsnd*Message send operation. Linux uses struct msgbuf type in one of its arguments.
ntp_adjtimeN/AAdjusts local clock parameters
ntp_gettimeN/AGets local clock values
open, openatopen*Opens a file. openat() is not available in Linux.
pcsampleN/AProgram execution time profile
p_onlineN/AReturns or changes processor operational status
priocntlN/AProcess scheduler control
priocntlsetN/AGeneralized process scheduler control
processor_bindsched_setaffinityBinds LWPs to a processor
processor_infoN/ADetermines type and status of a processor
pset_bindN/ABinds LWPs to a set of processors
pset_create, pset_destroy, pset_assignN/AManages sets of processors
pset_infoN/AGets information about a processor set
pset_listN/AGets a list of processor sets
pset_setattr, pset_getattrN/ASets or gets processor set attributes
putmsg, putpmsgN/ASends a message on a stream
rename, renameatrename*Changes the name of a file. Linux does not have renameat().
resolvepathN/AResolves all symbolic links of a path name
semidsN/ADiscovers all semaphore identifiers
setrctl, getrctlN/ASets or gets resource control values
settaskid, gettaskid, getprojidN/ASets or gets task or project IDs
shmidsN/ADiscovers all shared memory identifiers
sigsend, sigsendsetN/ASends a signal to a process or a group of processes
__sparc_utrap_installN/AInstalls a SPARC V9 user trap handler
fstatatN/AGets file status
swapctlN/AManages swap space
uadminN/AAdministrative control
unlink, unlinkatunlink*Removes directory entry. Linux does not have unlinkat().
futimesatN/ASets file access and modification times. It resolves the path relative to the fildes argument.
waitidN/AWaits for child process to change state
yieldsched_yieldYields execution to another lightweight process

Signals

Signals are used to notify a process or thread of a particular event. Linux supports both POSIX standard signals and POSIX real-time signals. Every signal has a unique name and a corresponding signal number. Several signal numbers are architecture dependent. For example, the signal number of SIGSTOP for Solaris is 23, but it's 19 for Linux on POWER. The definition of signal numbers on Linux can be found at /usr/include/bits/signum.

For all possible signals, the system defines a default action to take when a signal occurs:

  • Terminate: Default action is to terminate the process.
  • Ignore: Default action is to ignore the signal.
  • Core: Default action is to terminate the process and dump core.
  • Stop: Default action is to stop the process.

For a full list of Linux signals, including a short description of each and the default behavior when the signal is delivered, consult the signal man page in Section 7 by invoking the following command: # man 7 signal. Note that for Linux:

  • SIGABRT and SIGIOT are identical.
  • SIGCLD and SIGCHLD are identical.
  • SIGPOLL and SIGIO are identical.
  • Default action for SIGPWR for Linux is to terminate the process, but ignore on Solaris.

Table 2 shows the signals that are supported by Solaris, but not by Linux on POWER:

Table 2. Signals supported by Solaris
NameDefault actionDescription
SIGEMTcoreEmulation trap
SIGWAITINGignoreConcurrency signal used by threads library
SIGLWPignoreInter-LWP signal used by threads library
SIGFREEZEignoreCheckpoint suspend
SIGTHAWignoreCheckpoint resume
SIGCANCELignoreCancellation signal used by threads library
SIGLOSTignoreResource lost (but supported in Linux running on SPARC)
SIGXRESignoreResource control exceeded

sigset_t is defined differently on Solaris and Linux. On Linux, it is defined in /usr/include/bits/sigset.h as:

Listing 2. How sigset_t is defined in Linux
# define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long
int)))
typedef struct
   {
       unsigned long int __val[_SIGSET_NWORDS];
   } __sigset_t;
#endif

On Solaris, it is defined in /usr/include/sys/signal.h as:

Listing 3. How sigset_t is defined in Solaris
typedef struct  {                                     /* signal set type */
             unsigned int       __sigbits[4];
} sigset_t;

Base data type and alignment

There are two different classes of data types available on a system: base data types and derived data types.

Base data types are all data types defined by the C and C++ language specification. Table 3 compares base data types for Linux on POWER and Solaris (values given in bytes):

Table 3. Base data types
Data type for:Linux on POWER, ILP32Linux on POWER, LP64Solaris, ILP32Solaris, LP64
_Bool,bool1111
char1111
wchar_t2444
short2222
int4444
float4444
long4848
pointer4848
long long8888
double8888
long double16*16*1616

*The default size for long double in Linux on POWER is 128 bits starting from Red Hat Enterprise Linux 5 (RHEL5) and SUSE Linux Enterprise Server 10 (SLES10). Before RHEL5 or SLES10, they can be increased to 128 bits if the compiler option -qldbl128 in XL compilers is used.

When porting applications between platforms or between 32-bit and 64-bit modes, you need to consider the differences between alignment settings available in the different environments to avoid possible degradation in performance and data corruption. For the IBM XL C/C++ compiler, each data type within aggregates (C/C++ structures/unions and C++ classes) will be aligned along byte boundaries according to either the linuxppc or bit-packed rules (using -qalign option) where linuxppc is the default. linuxppc uses GNU C/C++ alignment rules to maintain binary compatibilities with GNU C/C++ objects.

Table 4 shows the alignment values for linuxppc and bit-packed rules:

Table 4. Alignment values
Data typelinuxppcbit-packed
_Bool,bool11
char11
wchar_t (32-bit)21
wchar_t (64-bit)41
int41
short21
long (32-bit)41
long (64-bit)81
long long81
float41
double81
long double161

SPARC platforms generally require data alignment to equal data size: two-byte types must be on a two-byte boundary, and four-byte types must be on a four-byte boundary. So when you port from Solaris to Linux, you need to take special care with those data types of different size between Solaris and Linux.

System-derived data types

A derived data type is a derivative or structure of existing base types or other derived types. System-derived data types can have different byte sizes depending on the employed data model (32- or 64-bit) and the hardware platforms. Table 5 shows some of the derived data types on Linux that are different from those on Solaris:

Table 5. Derived data types
Data type for:Solaris ILP32Solaris LP64Linux on POWER ILP32Linux on POWER LP64
gid_tlongintunsigned intunsigned int
mode_tunsigned longunsigned intunsigned intunsigned int
pid_tlongintintint
uid_tlongintunsigned intunsigned int
wint_tlongintunsigned intunsigned int

GNU Make versus Solaris Make

If you use Solaris Make in the source platform, you need to modify your makefile in order to use GNU Make on Linux. For detailed information about the difference between Solaris Make and GNU Make, please consult Chapter 6 of the "AIX 5L Porting Guide."

Compiler options

Table 6 is a list of widely used compiler options for Sun Studio compiler and the equivalent options for the GNU Compiler Collection and IBM's XL compilers:

Table 6. Compiler options
Sun Studio optionGNU GCC optionXL C/C++ optionDescription
-#-v-vInstructs the compiler to report information on the progress of the compilation.
-###-###-#Traces the compilation without invoking anything.
-dn-static-qstaticlinkSpecifies static linking.
-dy(Default)(Default)Specifies dynamic linking.
-G-shared-qmkshrobjProduces a shared object rather than a dynamically linked executable.
-xmemalign-malign-natural,
-malign-power
-qalignSpecifies the maximum assumed memory alignment and the behavior of misaligned data accesses.
-xO1, -xO2, -xO3, -xO4,-xO5-O, -O2, -O3-O,-O2,-O3,-O4,-O5 Optimizes code at a choice of levels during compilation.
-KPIC-fPIC-qpic=largeGenerates position-independent code for use in shared libraries (large model).
-Kpic-fpic-qpic=smallGenerates position-independent code for use in shared libraries (small model).
-mt-pthread Use _r invocation modeCompiles and links for multithreaded code.
-R dirlist-Wl, -rpath, dirlist-Wl, -rpath, dirlistBuilds a dynamic library search path into the executable file.
-xarch-mcpu, -march-qarch, -qtuneSpecifies the target architecture instruction set.

XL C/C++ compilers support a subset of GNU compiler options to facilitate porting applications developed with gcc and g++ compilers. This support is enabled when either the gxlc or gxlc++ invocation command is used with select GNU compiler options. These invocation commands use a plain-text configuration file to control GNU-to-XL C/C++ option mappings and defaults. You can modify this configuration file to better meet your requirements. See your XL compiler manual for more information about gxlc and gxlc++.

Solaris thread and NPTL

Now let's look issues you can encounter when migrating multithreaded applications from Solaris to Linux.

Solaris supports two threading implementations: Solaris threads and POSIX threads (pthreads). A few functions implemented by the Solaris threads API are not implemented by the pthreads API, and vice versa. For those functions that do match, the associated arguments might not. The following features are exclusively supported by the Solaris threads API:

  • The ability to create daemon threads. Daemon threads do not affect the process exit status. A process can exit either by calling exit() or by having every non-daemon thread in the process call thr_exit().
  • The ability to suspend or continue the execution of the thread using thr_suspend() and thr_continue(). Note that thr_suspend() suspends the target thread with no regard to the locks that the thread might be holding. If the suspending thread calls a function that requires a lock held by the suspended target thread, deadlock occurs.
  • The ability to allow a thread to wait for any undetached thread in the process to terminate. This is achieved when the first argument of thr_join() is set to 0. If you set the first argument of pthread_join() to 0, the program will be terminated with a segmentation fault.

Table 7 compares the key Solaris threads functions with the pthreads functions. For other Solaris threads functions, please consult the "Multithreaded Porting Guide" from Sun (see Resources).

Table 7. Threads and pthreads functions
Solaris threads APILinux POSIX threads APIDescription
thr_create()pthread_create()Creates a new thread of control.
thr_exit()pthread_exit()Terminates the execution of the calling thread.
thr_join()pthread_join()Suspends the calling thread until the target thread completes.
thr_kill()pthread_kill()Sends a signal to another thread.
thr_self()pthread_self()Returns the thread ID of the calling process.
thr_yield()sched_yield()Makes the current thread yield to another thread.
thr_getprio()pthread_getschedparam()Retrieves a thread's priority parameters.
thr_setprio()pthread_setschedparam()Modifies a thread's priority parameters.
thr_getspecific()pthread_getspecific()Binds a new thread-specific value to the key.
thr_setspecific()pthread_setspecific()Binds a new thread-specific value to the key.
thr_getconcurrency()pthread_getconcurrency()Gets thread concurrency level.
thr_setconcurrency()pthread_setconcurrency()Sets thread concurrency level.
thr_sigsetmask()pthread_sigmask()Changes or examines the calling thread's signal mask.
thr_keycreate()pthread_key_create()Creates a key that locates data specific to a thread.
N/Apthread_key_delete()Deletes a key that locates data specific to a thread.
thr_suspend()N/ASuspends the execution of the specified thread.
thr_continue()N/AResumes the execution of a suspended thread.
fork1()fork()Regular fork.
forkall()N/AReplicate all forks.

The behavior of fork() in Solaris 9 and earlier releases is different from the behavior of fork() in POSIX threads. In POSIX threads, fork() creates a new process, duplicating the complete address space in the child; however, it duplicates only the calling thread in the child process. Solaris threads API also provides the replicate-all-forks semantics, forkall(). This function duplicates the address space and all the threads in the child. This feature is not supported by POSIX thread standard.

Some POSIX thread routines implemented in Solaris are not in Linux, and vice versa. Table 8 lists those routines:

Table 8. POSIX thread routines
RoutineSolarisLinux
pthread_cond_reltimedwait_npyn
pthread_mutexattr_getrobust_npyn
pthread_mutexattr_setrobust_npyn
pthread_mutex_consistent_npyn
pthread_mutex_reltimedlock_npyn
pthread_rwlock_reltimedrdlock_npyn
pthread_rwlock_reltimedwrlock_npyn
pthread_attr_getaffinity_npny
pthread_attr_setaffinity_npny
pthread_cleanup_pop_restore_npny
pthread_cleanup_push_defer_npny
pthread_getattr_npny
pthread_kill_other_threads_npny
pthread_rwlockattr_getkind_npny
pthread_rwlockattr_setkind_npny
pthread_timedjoin_npny
pthread_tryjoin_npny

The Linux threading library in all the released versions of Linux prior to 2.6 is known as LinuxThreads. This library has been supported by GNU C library since glibc 2.0 and is largely POSIX-compliant. Starting in the 2.6 kernel, a new and improved threading library known as the Native POSIX Threading Library (NPTL) is introduced. This implementation provides a significant performance improvement over LinuxThreads. NPTL is also far more compliant with the POSIX specification than the LinuxThreads package was; however, simply using the 2.6 kernel does not mean that the NPTL is being used. Issue the following command to see which POSIX implementation you are using:

$ getconf GNU_LIBPTHREAD_VERSION

NPTL implements the one-to-one threading model where there is a one-to-one relationship between user threads and kernel threads. NPTL also implements the interprocess POSIX synchronization primitives. Specifically, the thread option PTHREAD_PROCESS_SHARED is now supported. By default, each thread is created with the detachstate attribute set to PTHREAD_CREATE_JOINABLE, scheduling policy set to SCHED_OTHER, and no user-provided stack.

If your Solaris application uses POSIX threads API, then porting them to Linux will be straightforward. Note that even when using GCC, Solaris does not support NPTL. Table 9 shows the default values of attributes for POSIX threads on Linux:

Table 9. Default values of POSIX threads attributes on Linux
AttributeDefault values
scopePTHREAD_SCOPE_SYSTEM
detachstatePTHREAD_CREATE_JOINABLE
schedparam0
inhiritschedPTHREAD_EXPLICIT_SCHED
schedpolicySCHED_OTHER

Though many applications will migrate from the 2.4 kernel to the 2.6 without recompilation, the addition of NPTL may require minor modifications in multithreaded applications. Instructions for migrating applications by using LinuxThreads to NPTL is beyond the scope of this article. Additional information can be found in the LinuxDevices.com article "Migrating to Linux kernel 2.6" (Resources).


Performance tuning

Once the code has been ported and successfully executed on Linux, complete performance monitoring and tuning to ensure that the ported code performs well on the target platform. This section includes a list of tools available for Linux on POWER to help accomplish that.

Common performance tools

Two common tools—the sysstat package and nmon—can make performance monitoring and tuning easier:

  • The sysstat package contains the common extended tools for basic performance monitoring, including tools like mpstat, iostat, and sar.
  • nmon combines a variety of classic system monitoring tools into a one-stop data gathering tool. A number of really handy post-processing add-ons are available to summarize, graph, and consolidate information.

OProfile

OProfile is a system-wide profiler for Linux based on hardware-related events such as cache misses or CPU cycles. For example, OProfile can help you determine which of the source routines causes the most cache misses. OProfile utilizes hardware performance counters provided in many CPUs including IBM POWER4™, POWER5™, POWER6™ and PowerPC™ 970. Please visit the OProfile Web site for more information (Resources for a link).

OProfile for Linux on POWER is available with SLES10, SLES11, RHEL5, and in the Advance Toolchain. A quick reference for OProfile on an installed system can be found at /usr/share/doc/packages/oprofile.

Post-link optimization (FDPRpro)

This tool optimizes the executable image of a program by collecting information on the behavior of the program while the program is used for a typical workload. It then re-analyzes the program (together with the collected profile), applies global optimizations (including program restructuring), and creates a new version of the program that is optimized for that workload. The new program generated by the optimizer typically runs faster and uses less real memory than the original program.

At the time of this writing, the Post-Link Optimization tool is supported on SLES8 and later and RHEL3 and later. For more information, please visit the alphaWorks Post-Link Optimization for Linux on POWER site (Resources for a link).


Software packaging

Application software is delivered to users in a unit called a package. A package is a collection of related files (binaries, libraries, documentation, and source code) and metadata. Metadata is used by the package-management system to coordinate all of the pieces in the package. Solaris uses pkgadmin as its package manager. RPM is the package management system widely used on Linux. For further information about RPM, please visit www.rpm.org (Resources for a link).

Note that the format of the package specification template files used by pkgadmin in Solaris is different from the spec file used by RPM; translating packaging information from template file into spec files requires a substantial effort.


Summary

The porting effort from Solaris to Linux on POWER in most cases involves just a recompile or minor changes in compiler/linker switches. However, the design of Solaris and Linux is fundamentally different:

  • Solaris is focused on performance, scalability, and reliability while sacrificing portability.
  • Linux is designed with portability in mind, and it is supported on almost all hardware platforms available today.

Today's Linux distributions are based on the Linux 2.6 kernel, which continues to take advantage of significant community and corporate improvements. SLES10 SP2, RHEL5.2, and SLES11 all have significantly improved performance, scalability, and reliability from the earlier releases, which were based on the Linux 2.4 kernel. For Linux running on Power systems, applications have access to the full power, performance, scalability, virtualization, and management capabilities.

Keep in mind that there are some system-specific features available on Solaris that are not available on Linux.

Acknowledgments

We would like to thank Steve Munroe, Mark Brown, Kevin Li, and Ralph Nissler for their invaluable comments.

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Linux on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Linux
ArticleID=427150
ArticleTitle=Guide to porting from Solaris to Linux on POWER
publish-date=09082009