Thread environment variables

Within the libpthreads.a framework, a series of tuning knobs have been provided that might impact the performance of the application.

If possible, use a front-end shell script to invoke the binary executable programs. The shell script should specify the new values that you want to override the system defaults for the environment variables described in the sections that follow.

AIXTHREAD_COND_DEBUG

The AIXTHREAD_COND_DEBUG variable maintains a list of condition variables for use by the debugger. If the program contains a large number of active condition variables and frequently creates and destroys condition variables, this can create higher overhead for maintaining the list of condition variables. Setting the variable to OFF will disable the list. Leaving this variable turned on makes debugging threaded applications easier, but can impose some overhead.

AIXTHREAD_ENRUSG

The AIXTHREAD_ENRUSG variable enables or disables the pthread resource collection. Turning it on allows for resource collection of all pthreads in a process, but will impose some overhead.

AIXTHREAD_GUARDPAGES=n

     *      +-----------------------+
     *      | pthread attr          |
     *      +-----------------------+ <--- pthread->pt_attr
     *      | pthread struct        |
     *      +-----------------------+ <--- pthread->pt_stk.st_limit
     *      | pthread stack         |
     *      |   |                   |
     *      |   V                   |
     *      +-----------------------+ <--- pthread->pt_stk.st_base
     *      | RED ZONE              |
     *      +-----------------------+ <--- pthread->pt_guardaddr
     *      | pthread private data  |
     *      +-----------------------+ <--- pthread->pt_data
The RED ZONE on this illustration is called the Guardpage.

The pthread attr, pthread, and ctx represent the PTH_FIXED part of the memory allocated for a pthread.

The approximate byte sizes in the diagram below are in brackets for 32-bit. For 64-bit, expect the pieces comprising PTH_FIXED to be slightly larger and the key data to be 8 K, but otherwise the same.

     *      +-----------------------+
     *      | page alignment 2      |
     *      | [8K-4K+PTH_FIXED-a1]  |
     *      +-----------------------+
     *      | pthread ctx [368]     |
     *      +-----------------------+<--- pthread->pt_attr
     *      | pthread attr [112]    |
     *      +-----------------------+ <--- pthread->pt_attr
     *      | pthread struct [960]  |
     *      +-----------------------+ <--- pthread
     *      | pthread stack         |         pthread->pt_stk.st_limit
     *      |   |[96K+4K-PTH_FIXED] |
     *      |   V                   |
     *      +-----------------------+ <--- pthread->pt_stk.st_base
     *      | RED ZONE [4K]         |
     *      +-----------------------+ <--- pthread->pt_guardaddr
     *      | pthread key data [4K] |
     *      +-----------------------+ <--- pthread->pt_data
     *      | page alignment 1 (a1) |
     *      | [<4K]                 |
     *      +-----------------------+

The RED ZONE on this illustration is called the Guardpage.

The decimal number of guardpages to add to the end of the pthread stack is n, which overrides the attribute values that are specified at pthread creation time. If the application specifies its own stack, no guardpages are created. The default is 0 and n must be a positive value.

The guardpage size in bytes is determined by multiplying n by the PAGESIZE. Pagesize is a system-determined size.

AIXTHREAD_DISCLAIM_GUARDPAGES

The AIXTHREAD_DISCLAIM_GUARDPAGES variable controls whether the stack guardpages are disclaimed when a pthread stack is created. If AIXTHREAD_DISCLAIM_GUARDPAGES=ON, the guardpages are disclaimed. If a pthread stack does not have any guardpages, setting the AIXTHREAD_DISCLAIM_GUARDPAGES variable has no effect.

AIXTHREAD_MNRATIO

The AIXTHREAD_MNRATIO variable controls the scaling factor of the library. This ratio is used when creating and terminating pthreads. It may be useful for applications with a very large number of threads. However, always test a ratio of 1:1 because it may provide for better performance.

AIXTHREAD_MUTEX_DEBUG

The AIXTHREAD_MUTEX_DEBUG variable maintains a list of active mutexes for use by the debugger. If the program contains a large number of active mutexes and frequently creates and destroys mutexes, this can create higher overhead for maintaining the list of mutexes. Setting the variable to ON makes debugging threaded applications easier, but may impose the additional overhead. Leaving the variable set to OFF disables the list.

AIXTHREAD_MUTEX_FAST

If the program experiences performance degradation due to heavy mutex contention, then setting this variable to ON will force the pthread library to use an optimized mutex locking mechanism that works only on process-private mutexes. These process-private mutexes must be initialized using the pthread_mutex_init routine and must be destroyed using the pthread_mutex_destroy routine. Leaving the variable set to OFF forces the pthread library to use the default mutex locking mechanism.

AIXTHREAD_READ_GUARDPAGES

The AIXTHREAD_READ_GUARDPAGES variable enables or disables read access to the guardpages that are added to the end of the pthread stack. For more information about guardpages that are created by the pthread, see AIXTHREAD_GUARDPAGES=n.

AIXTHREAD_RWLOCK_DEBUG

The AIXTHREAD_RWLOCK_DEBUG variable maintains a list of read-write locks for use by the debugger. If the program contains a large number of active read-write locks and frequently creates and destroys read-write locks, this may create higher overhead for maintaining the list of read-write locks. Setting the variable to OFF will disable the list.

AIXTHREAD_SUSPENDIBLE={ON|OFF}

Setting the AIXTHREAD_SUSPENDIBLE variable to ON prevents deadlock in applications that use the following routines with the pthread_suspend_np routine or the pthread_suspend_others_np routine:
  • pthread_getrusage_np
  • pthread_cancel
  • pthread_detach
  • pthread_join
  • pthread_getunique_np
  • pthread_join_np
  • pthread_setschedparam
  • pthread_getschedparam
  • pthread_kill
There is a small performance penalty associated with this variable.

AIXTHREAD_SCOPE={S|P}

The S option signifies a system-wide contention scope (1:1), and the P option signifies a process-wide contention scope (M:N). One of these options must be specified; the default value is S.

Use of the AIXTHREAD_SCOPE environment variable impacts only those threads created with the default attribute. The default attribute is employed when the attr parameter of the pthread_create() subroutine is NULL.

If a user thread is created with system-wide scope, it is bound to a kernel thread and it is scheduled by the kernel. The underlying kernel thread is not shared with any other user thread.

If a user thread is created with process-wide scope, it is subject to the user scheduler, which means the following
  • It does not have a dedicated kernel thread.
  • It sleeps in user mode.
  • It is placed on the user run queue when it is waiting for a processor.
  • It is subjected to time slicing by the user scheduler.

Tests show that some applications can perform better with the 1:1 model.

AIXTHREAD_SLPRATIO

The AIXTHREAD_SLPRATIO thread tuning variable controls the number of kernel threads that should be held in reserve for sleeping threads. In general, fewer kernel threads are required to support sleeping pthreads because they are generally woken one at a time. This conserves kernel resources.

AIXTHREAD_STK=n

The AIXTHREAD_STK=n thread tuning variable controls the decimal number of bytes that should be allocated for each pthread. This value may be overridden by pthread_attr_setstacksize.

AIXTHREAD_AFFINITY={default|strict|first-touch}

The AIXTHREAD_AFFINITY controls the placement of pthread structures, stacks, and thread-local storage on an enhanced affinity enabled system.
  • The default option will not attempt any special placement of this data, balancing it over the memory regions used by the process as determined by the system settings
  • The strict option will always place this data in memory local to the pthread; this may incur some performance penalty during the creation of the pthread as the existing data is migrated from one memory region to another, however, may improve run-time performance.
  • The first touch option is similar in placement of memory local to the pthread, however, it will not attempt to migrate any data within the memory. The in-memory pages are needed by the thread for this data (including paging in memory from paging space), and will be placed local. This option allows a balance between startup time and runtime performance.

AIXTHREAD_PREALLOC=n

The AIXTHREAD_PREALLOC variable designates the number of bytes to pre-allocate and free during thread creation. Some multi-threaded applications may benefit from this by avoiding calls to sbrk() from multiple threads simultaneously.

The default is 0 and n must be a positive value.

AIXTHREAD_HRT

The AIXTHREAD_HRT=true variable allow high-resolution time-outs for application's pthreads. You must have root authority, or CAP_NUMA_ATTACH capability to enable high-resolution time-outs. This environment variable is ignored, if you do not have the required authority or capabilities.

MALLOCBUCKETS

Malloc buckets provides an optional buckets-based extension of the default allocator. It is intended to improve malloc performance for applications that issue large numbers of small allocation requests. When malloc buckets is enabled, allocation requests that fall within a predefined range of block sizes are processed by malloc buckets. All other requests are processed in the usual manner by the default allocator.

Malloc buckets is not enabled by default. It is enabled and configured prior to process startup by setting the MALLOCTYPE and MALLOCBUCKETS environment variables.

For more information on malloc buckets, see General Programming Concepts: Writing and Debugging Programs.

MALLOCMULTIHEAP={considersize,heaps:n}

Multiple heaps are required so that a threaded application can have more than one thread issuing malloc(), free(), and realloc() subroutine calls. With a single heap, all threads trying to do a malloc(), free(), or realloc() call would be serialized (that is, only one call at a time). The result is a serious impact on multi-processor machines. With multiple heaps, each thread gets its own heap. If all heaps are being used, then any new threads trying to do a call will have to wait until one or more of the heaps is available. Serialization still exists, but the likelihood of its occurrence and its impact when it does occur are greatly reduced.

The thread-safe locking has been changed to handle this approach. Each heap has its own lock, and the locking routine "intelligently" selects a heap to try to prevent serialization. If the considersize option is set in the MALLOCMULTIHEAP environment variable, then the selection will also try to select any available heap that has enough free space to handle the request instead of just selecting the next unlocked heap.

More than one option can be specified (and in any order) as long as they are comma-separated, for example:
MALLOCMULTIHEAP=considersize,heaps:3
The options are:
considersize
This option uses a different heap-selection algorithm that tries to minimize the working set size of the process. The default is not to use this option and use the faster algorithm.
heaps:n
Use this option to change the number of heaps. The valid range for n is 1 to 32. If you set n to a number outside of this range (that is, if n<=0 or n>32), n will be set to 32.

The default for MALLOCMULTIHEAP is NOT SET (only the first heap is used). If the environment variable MALLOCMULTIHEAP is set (for example, MALLOCMULTIHEAP=1) then the threaded application will be able to use all of the 32 heaps. Setting MALLOCMULTIHEAP=heaps:n will limit the number of heaps to n instead of the 32 heaps.

For more information, see the Malloc Multiheap section in General Programming Concepts: Writing and Debugging Programs.

SPINLOOPTIME=n

The SPINLOOPTIME variable controls the number of times the system tries to get a busy mutex or spin lock without taking a secondary action such as calling the kernel to yield the process. This control is intended for MP systems, where it is hoped that the lock being held by another actively running pthread will be released. The parameter works only within libpthreads (user threads). If locks are usually available within a short amount of time, you may want to increase the spin time by setting this environment variable. The number of times to retry a busy lock before yielding to another pthread is n. The default is 40 and n must be a positive value.

The MAXSPIN kernel parameter affects spinning in the kernel lock routines (see Using the schedo command to modify the MAXSPIN parameter).

YIELDLOOPTIME=n

The YIELDLOOPTIME variable controls the number of times that the system yields the processor when trying to acquire a busy mutex or spin lock before actually going to sleep on the lock. The processor is yielded to another kernel thread, assuming there is another executable one with sufficient priority. This variable has been shown to be effective in complex applications, where multiple locks are in use. The number of times to yield the processor before blocking on a busy lock is n. The default is 0 and n must be a positive value.