Java Performance On POWER7 - Best Practice: June 28, 2011
Java Performance On POWER7 - Best Practice: June 28, 2011
Hong Hua, Dirk Michel Power Systems Performance Younes Manton, Julian Wang JIT Development
Java Performance on POWER7 - Best Practice Java Performance on POWER7 - Best Practice Preface Acknowledgments: Disclaimer: 1. Introduction 2 Performance Considerations 2.1 32-bit versus 64-bit Java 2.2 Memory and Page Size Considerations 2.2.1 Medium and Large Pages for Java Heap and Code Cache 2.2.2 Configuring Large Pages for Java Heap and Code Cache 2.2.3 Prefetching 2.2.4 Compressed References 2.2.5 JIT Code Cache 2.3 Application Scaling 2.3.1 Choosing the right SMT mode 2.3.2 Using Resource Sets 2.3.3 Java Lock Reservation 2.3.4 Java GC Threads 2.3.5 Java Concurrent Marking 2.5 Java Garbage Collection Tuning 2.5.1 GC Strategy: Optthruput (Default) 2.5.2 GC Strategy: Subpool 2.5.3 GC Strategy: Optavgpause 2.5.4 GC Strategy: Gencon 2.5.5 Optimal Heap Size 3.0 Improving Performance 3.1 Introduction 3.2 32-bit or 64-bit Java 3.3 Medium and Large Pages 3.4 Scaling 3.4.1 Application Scaling 3.4.2 SMT Scaling - DayTrader Workload 3.4.3 SMT Scaling - Java Workload Example 3.5 Memory Pre-fetching 3.6 Affinity - Enhanced Performance Tuning 4.0 Tools 4.1 Verbose GC Log 4.2 Garbage Collection and Memory Visualizer 4.3 Java Lock Monitor 4.4 Java Health Center 5.0 Summary 3 3 3 3 4 5 5 5 6 6 6 7 7 8 8 8 10 10 10 11 11 11 11 12 12 14 14 14 15 16 16 17 18 18 21 22 22 22 22 23 24
POW03066-USEN-00.doc
Page 2
Acknowledgments: Disclaimer:
All performance data contained in this publication was obtained in the specific operating environment and under the conditions described below and is presented as an illustration. Performance obtained in other operating environments may vary and customers should conduct their own testing.
POW03066-USEN-00.doc
Page 3
1. Introduction
Out of the box AIX is a robust, solid and scalable operating system. However, some changes to the default settings may be necessary in order for customers to realize the best possible performance for their applications based on the applications specific characteristics and needs. This document describes performance considerations, tuning options, existing tools, and diagnostic options that can be used to guide tuning decisions to maximize performance for a given application or workload. The following performance considerations will be discussed: 32-bit versus 64-bit Java, memory and various page sizes, application scaling, affinity, consolidation, and Java Garbage Collection tuning. Data has been collected to illustrate the benefits of the following scenarios: 32-bit and 64-bit Java, various page sizes, affinity, and scaling along with existing tools that can be used to guide tuning decisions.
POW03066-USEN-00.doc
Page 4
2 Performance Considerations
2.1 32-bit versus 64-bit Java
64-bit applications that do not require large amounts of memory typically run slower than 32-bit applications. This is due to the larger data types, like 64-bit pointers instead of 32-bit pointers, which increases the demand on memory throughput. The exception to this is when the processor architecture has more processor registers in 64-bit mode than in 32-bit mode and 32-bit application performance is negatively impacted by this. Due to a small number of registers, the demand on memory throughput can be higher in 32-bit mode than in 64-bit mode. Running an application in 64-bit mode is required to achieve best performance. The Power Architecture does not require running applications in 64-bit mode to achieve best performance since 32-bit and 64-bit modes have the same number of processor registers. Considerations: Applications with a small memory requirement typically run faster as 32-bit application than 64-bit application 64-bit applications have larger demand on memory due to larger data types, like long and pointers are 64-bit instead of 32-bit o Memory foot print increases due to larger data types o Memory alignment of application data contributes to memory demand o More memory bandwidth required For best performance, use 32-bit Java unless the memory requirement of the application requires running in 64-bit mode.
Platform All
No Yes
2.2.1 Medium and Large Pages for Java Heap and Code Cache Medium and large pages can be enabled for the Java heap and JIT code cache independently of other memory areas. The JVM supports at least three page sizes, depending on the platform: 4KB (default), 64KB, 16MB. The Xlp64K and Xlp16M options can be used to select the desired page granularity for the heap and code cache. The Xlp option is an alias for Xlp16M. It is important to note that large pages, specifically 16MB, do have some overhead and are best suited to long running applications with large memory requirements. The Xlp64K option provides many of the benefits of 16MB pages with less overhead and may be suitable for workloads that benefit from large pages but dont take full advantage of 16MB pages. Note: Starting with IBM Java 6 SR7, the default page size is 64KB. 2.2.2 Configuring Large Pages for Java Heap and Code Cache Large pages must be configured by the system administrator using the vmo command. The following example demonstrates how to dynamically configure 1GB of 16MB pages: # vmo -o lgpg_regions=64 -o lgpg_size=16777216 To permanently configure large pages, the -r option needs to be specified to the above vmo command. It is recommended to run the bosboot command to configure the large pages at boot time: # vmo -r -o lgpg_regions=64 -o lgpg_size=16777216 # bosboot -a Non-root users must have the CAP_BYPASS_RAC_VMM capability enabled to use large pages. The system administrator can add this capability using the chuser command like in the example below: # chuser capabilities=CAP_BYPASS_RAC_VMM,CAP_PROPAGATE <user_id> 2.2.3 Prefetching Prefetching is an important strategy in order to reduce memory latency and take full advantage of on-chip caches. The XtlhPrefetch option can be specified to enable aggressive prefetching of thread-local heap memory shortly before objects are allocated. This will ensure that the memory required for new objects allocated from the TLH will be fetched into cache ahead of time if possible, thereby reducing latency and increasing overall object allocation speed. This option can
POW03066-USEN-00.doc
Page 6
give noticeable gains on workloads that frequently allocate objects, such as transactional workloads. 2.2.4 Compressed References For truly huge workloads 64-bit JVMs may be necessary to meet an applications needs. 64-bit processes primarily offer a much larger address space, thereby allowing for larger Java heaps, JIT code caches, and reducing the effects of memory fragmentation in the native heap. However 64-bit processes also must deal with the increased overhead. The overhead comes from the increased memory usage and decreased cache utilization. This overhead is present with every single object allocation, as each object must now be referred to with a 64-bit address rather than a 32-bit address. To alleviate this, the Xcompressedrefs option can be used. When enabled, the JVM will use 32-bit references to objects instead of 64-bit references where ever possible. Object references are compressed and decompressed as necessary at very minimal cost. The need for compression/decompression is determined by the overall heap size and the platform the JVM is running on; smaller heaps can do without compression/decompression, thereby eliminating even this overhead. In order to determine the compression/decompression overhead for a given heap size on a particular platform, the following command can be invoked: java Xgcpolicy:<policy> Xmx<size><M|G> Xcompressedrefs verbose:gc version The resulting output will contain the following: <attribute name="compressedRefsDisplacement" value="0x0" /> <attribute name="compressedRefsShift" value="0x0" /> Values of 0 for the named attributes essentially indicate that no work has to be done in order convert between 32- and 64-bit references for the given invocation. Under these circumstances 64-bit JVMs running with Xcompressedrefs can reduce the overhead of 64-bit addressing even more and achieve better performance. Note that with -Xcompressedrefs the maximum size of the heap will be much smaller than the theoretical maximum size allowed by a 64-bit JVM, although greater than the maximum heap under a 32-bit JVM. 2.2.5 JIT Code Cache JIT compilation is an important factor in optimizing performance. Because compilation is carried out at runtime it is impossible to estimate the size of the program or the number of compilations that will be carried out. The JIT compiler uses a fixed size buffer to store compiled code and for the majority of applications the default size is more than sufficient. However, certain programs, especially those that take advantage of certain language features such as reflection, can produce a significant number of compilations and fill the JIT code cache. Once the cache is full no more compilations are performed. This can have a negative impact on performance if the program begins to call many interpreted methods that can not be compiled as a result. The Xjit:codetotal=<size> (size in KiB) option can be used to specify the size of the JIT code cache and the default is chosen at runtime based on platform characteristics. It is important to only alter the code cache size if it is insufficient, as a large but empty code cache will needlessly consume resources. To determine if the code cache is sufficient the -Xjit:verbose option can be used to
POW03066-USEN-00.doc Page 7
print method names as they are compiled. If compilation fails because the code cache is full an error to that effect will also be printed.
The default SMT mode on POWER7 depends on the AIX version and the compatibility mode the processors are running with. The following table shows the default SMT modes: AIX Version AIX 6.1 AIX 6.1 AIX 5.3 Compatibility Mode POWER7 POWER6/POWER6+ POWER6/POWER6+ Default SMT Mode SMT4 SMT2 SMT2
Most applications benefit from SMT. However, some applications do not scale with an increased number of logical CPUs on an SMT enabled system. One way to address such an application scalability issue is to change to a lower SMT mode with fewer logical CPUs; for examples, changing from SMT4 to SMT2. Another way is the usage of RSETs as described in the following section. 2.3.2 Using Resource Sets Resource sets (rsets) allow specifying on which logical CPUs an application can run. This is useful when an application that doesnt scale beyond a certain number of logical CPUs should run on large LPAR. For example, an application that scales well up to 8 logical CPUs should run on an LPAR that has 64 logical CPUs.
POW03066-USEN-00.doc
Page 8
Resource sets can be created with the mkrset command and attached to a process using the attachrset command. An alternative way is creating a resource set and attaching it to an application in a single step through the execrset command. The following example demonstrates how to use execrset to create an rset with CPU 4 to 7 and starts the application attached to it: execrset -c 4-7 -e <application> In addition to running the application attached to a rset, the MEMORY_AFFINITY environment variable should be set to MCM to assure that the applications private and shared memory get allocated from memory that is local to the logical CPUs of the rset: MEMORY_AFFINITY=MCM In general, rsets should be created on core boundaries. For example, a system with four virtual processors (cores) running in SMT4 mode will have 16 logical CPUs. Creating an rset with four logical CPUs should be created by selecting four SMT threads that belong to one core. An rset with eight logical CPUs ld be created by selecting eight SMT threads that belong to two cores. The smtctl command can be used to determine which logical CPUs belong to which core: smtctl This system is SMT capable. This system supports up to 4 SMT threads per processor. SMT is currently enabled. SMT boot mode is not set. SMT threads are bound to the same physical processor. proc0 has 4 SMT threads. Bind processor 0 is bound Bind processor 1 is bound Bind processor 2 is bound Bind processor 3 is bound
proc4 has 4 SMT threads. Bind processor 4 is bound Bind processor 5 is bound Bind processor 6 is bound Bind processor 7 is bound
The smtctl output above shows that the system is running in SMT4 mode with bind processor (logical CPU) 0 to 3 belonging to proc0 and bind processors 4 to 7 to proc1. An rset with four logical CPU should be created either for CPUs 0 to 3 or for CPUs 4 to 7.
POW03066-USEN-00.doc
Page 9
To achieve best performance with rsets that are created across multiple cores, all cores of the rset should be in the same scheduler resource allocation domain (SRAD). The lssrad command can be used to determine which logical CPUs belong to which SRAD: lssrad -av REF1 SRAD 0 0 1 1
The example output above shows a system that has two SRADs. CPUs 0 to 31 belong to the first SRAD while CPUs 32 to 63 belong to the second SRAD. In this example, an rset with multiple cores should be created either using the CPUs of the first or second SRAD. Note: A user must have root authority or have CAP_NUMA_ATTACH capability to use rsets. 2.3.3 Java Lock Reservation Synchronization and locking are an important part of any multi-threaded application. Shared resources must be adequately protected by monitors to insure correctness, even if some resources are only infrequently shared. If a resource is primarily accessed by a single thread at any given time that thread will frequently be the only thread to acquire the monitor guarding the resource. In such cases the cost of acquiring the monitor can be reduced with the XlockReservation option. With this option it is assumed that the last thread to acquire the monitor will likely also be the next thread to acquire it. The lock is therefore said to be reserved for that thread, thereby minimizing its cost to acquire and release the monitor. This option is well-suited to workloads using many threads and many shared resources that are infrequently shared in practice. 2.3.4 Java GC Threads The garbage collector used by the JVM takes every opportunity to exploit parallelism on multiCPU machines. All phases of the GC can be executed in parallel with multiple helper threads dividing up the work in order to complete the task as quickly as possible. Depending on the GC strategy and heap size in use, it may be beneficial to adjust the number of threads that the GC uses. The number of GC threads can be specified with the Xgcthreads<number> option. The default number of GC threads is equal to the number of logical processors on the machine and it is usually not helpful to exceed this value, reducing it however will reduce GC overhead and may be desirable in some situations. 2.3.5 Java Concurrent Marking The gencon policy combines concurrent marking with generational garbage collection. If generational garbage collection is desired but the overhead of concurrent marking, with respect to both the overhead of the marking thread and the extra book-keeping required when allocating and manipulating objects, is not desired then concurrent marking may be disabled with the Xconcurrentlevel0 option. This option is appropriate for workloads that benefit from gencons
POW03066-USEN-00.doc Page 10
optimizations for object allocation and lifetimes but also require maximum throughput and minimal GC overhead while application threads are running. In general for both the gencon and optavgpause GC policies, concurrent marking can be tuned with the -Xconcurrentlevel<number> option which specifies the ratio between the amounts of heap allocated and the amounts of heap marked. The default value is 8. The number of low priority mark threads can be set with the -Xconcurrentbackground<number> option. By default 1 thread is used for concurrent marking.
POW03066-USEN-00.doc
Page 11
2.5.4 GC Strategy: Gencon The Xgcpolicy:gencon strategy employs a generational garbage collection scheme that attempts to deal with many varying workloads and memory usage patterns. In addition, gencon also uses concurrent marking to minimize pause times. The gencon strategy works by dividing the heap into two categories: the new space and the old space. The new space is dedicated to short-lived objects that are created frequently and unreferenced shortly there after. The old space is for long-lived objects that have survived long enough to be promoted from the new space. This GC policy is very well suited to workloads that have many short-lived objects, such as transactional workloads, because garbage collection in the new space (carried out by the so called scavenger) is cheaper per object overall than garbage collection in the old space. By default 25% of the heap is dedicated to the new space. The division between the new space and the old space can be controlled with the - Xmn<size><M|G> option, which specified the size of the new space; the remaining space is then designated as the old space. (Alternatively, -Xmns and -Xmnx can be used to set the starting and maximum new space sizes if a non-constant new space size is desired. See below for a discussion on constant v.s. non-constant heaps in general.) 2.5.5 Optimal Heap Size By default the JVM provides a very flexible heap configuration that allows the heap to grow and shrink dynamically in response to the needs of the application. This allows the JVM to claim only as much memory as necessary at any given time, thereby cooperating with other processes running on the system. The starting and maximum size of the heap can be specified with the Xms<size><M|G> and -Xmx<size><M|G> options respectively. This flexibility however comes at a cost, as the JVM must request memory from the operating system whenever the heap needs to be grown and return memory whenever it shrinks. This behavior can lead to various worse-case scenarios. If the application's heap requirements oscillate it may cause excessive heap growth and shrinkage. If the JVM is running on a dedicated machine the overhead of heap resizing can be eliminated by requesting a constant sized heap. This can be accomplished by setting -Xms equal to -Xmx. Choosing the right size for the heap is very important, as GC overhead is directly proportional to the size of the heap! The heap should be large enough to satisfy the application's maximum memory requirements and also contain some wiggle room. The GC has to work much harder when the heap is near full capacity due to fragmentation and other issues, so 20-30% of extra space above the application's maximum needs can lower overall GC overhead. If an application requires more flexibility than can be achieved with a constant sized heap it may be beneficial to tune the sizing parameters for a dynamic heap. One of the most expensive GC events is object allocation failure. This occurs when there is not enough contiguous space in the current heap to satisfy the allocation and results in a GC collection and a possible heap expansion. If the current heap size is less than Xmx the heap will be expanded in response to the allocation failure if the amount of free space is below a certain threshold. Therefore, it is important to insure that when an allocation fails the heap is expanded to not only allow the failed allocation to succeed, but also many future allocations, otherwise the next failed allocation could trigger yet another GC collection. This is known as heap thrashing. The -Xminf, -Xmaxf, Xmine, and -Xmaxe group of options can be used to effect when and how the GC resizes the heap. The -Xminf<factor> option (where factor is a real number between 0 and 1) specifies the minimum free space in the heap; if the total free space falls below this factor the heap is expanded. The -Xmaxf<factor> option specifies the maximum free space; if the total free space rises above this factor the heap is shrunk. These options can be used to minimize heap thrashing and excessive resizing. The -Xmine<size><M|G> and -Xmaxe<size><M|G> options specify
POW03066-USEN-00.doc Page 12
the minimum and maximum sizes to shrink and grow the heap by. These options can be used to insure that the heap has enough free contiguous space to allow satisfy a reasonable number of allocations before failure. Regardless of whether or not the heap size is constant, it should never exceed the physical memory available to the process; otherwise the operating system may have to swap data in and out of memory. An application's memory behavior can be determined by using various tools, including verbose GC logs. See the "Tools" section for more information on verbose GC logs and other tools.
POW03066-USEN-00.doc
Page 13
The following graph demonstrates the performance difference of 32-bit and 64-bit Java running a WebSphere Application Server (WAS) workload. For this example, the applications Java heap size was set to 2 GB RAM.
Single WAS - 32-bit vs 64-bit
120.0%
100.0%
80.0%
60.0%
40.0%
20.0%
Figure 1
The data in Figure 1 shows 64-bit with Xcompressedrefs and 32-bit baseline is 3.8% and 7.3% faster than 64-bit baseline respectively. For best performance, use 32-bit Java for workload that has heap size requirement less than 2.5 GB and spawn a few hundred threads.
POW03066-USEN-00.doc
Page 14
140.00 120.00 100.00 80.00 60.00 40.00 20.00 0.00 4K pages 64K pages % Throughput 16M pages
Figure 2
The data in Figure 2 shows IBM Java can take advantage of medium (64 KB) and large (16 MB) page sizes that are supported by the current AIX versions and POWER processors. The performance improvement of using medium and large pages is a result of efficient use of the hardware translation caches (TLB Translation Look-aside Buffer). Most customers will realize 64 KB page size benefit by default with Java 6 SR7, WAS V7.0.0.9.
POW03066-USEN-00.doc
Page 15
250%
200%
150%
100%
50%
Figure 3
Test Configuration 4 JVM Instances 8 JVM Instances 16 JVM Instances Test Configuration 4 JVM Instances 8 JVM Instances 16 JVM Instances
All tests were done on a 16 core, two sockets system with hardware prefetching disabled and the usage of RSETs. Figure 3 shows the performance improvement running with multiple JVM instances that allow sub chip level affinitization, and limit number of threads per WAS instance which lead to better scaling. Based on these results, JVM per 2 cores is the most optimal configuration.
POW03066-USEN-00.doc
Page 16
250%
200%
150%
100%
50%
Figure 4
Test Configuration ST - Single Thread Mode SMT2 - Two SMT Thread Mode SMT4 - Four SMT Thread Mode
For DayTrader like workload, POWER7 SMT4 shows 2X speed up over ST.
POW03066-USEN-00.doc
Page 17
140% 120% 100% 80% 60% 40% 20% 0% ST baseline SMT2 % Throughput SMT4
Figure 5
Test Configuration ST - Single Thread Mode SMT2 - Two SMT Thread Mode SMT4 - Four SMT Thread Mode
For workload that do not shared data, SMT speed up would be in the 30-40% range.
POW03066-USEN-00.doc
Page 18
140% 120% 100% 80% 60% 40% 20% 0% HW Prefetch On HW Prefetch Off % Throughput SW Prefetch On
Figure 6
For most Java applications, it is recommended to turn off HW data prefetch with AIX command dscrctl n s 1. Java 6 SR7 exploits HW transient prefetch on POWER 7.
POW03066-USEN-00.doc
Page 19
140% 120% 100% 80% 60% 40% 20% 0% HW Prefetch On HW Prefetch Off % Throughput SW Prefetch On
Figure 7
The results with 16M page size are the same as 64K page size (Figure 6).
POW03066-USEN-00.doc
Page 20
140% 120% 100% 80% 60% 40% 20% 0% Baseline Without HW prefetch Without HW prefetch & RSETS % Throughput
Figure 8 Test Configuration Baseline Disable HW prefetch Disable HW prefetch & enable SW prefetch % Performance Gain 100.00 118.00 123.30
Figure 8 shows 23.3% performance gain by turning off hardware pre-fetching and enable aggressive prefetching of thread-local heap memory (-XtlhPrefetch Java option). Applications that frequently allocate objects will see noticeable gain. Notice: The performance gain of turning off hardware pre-fetching may vary with the application or workload.
POW03066-USEN-00.doc
Page 21
4.0 Tools
Various tools and diagnostic options are available that can provide detailed information about the state of the JVM. The information provided can be used to guide tuning decisions in order to maximize performance for a given application or workload.
POW03066-USEN-00.doc
Page 22
POW03066-USEN-00.doc
Page 23
5.0 Summary
In general, AIX/Java default settings deliver optimal performance for applications running on POWER. However, some changes to the default settings may be necessary to realize the best possible performance based on the applications specific characteristics and needs. The existing tools and diagnostic options help guide tuning decisions to maximize performance for a given application. Recommendations: 1. Use 32-bit Java for workload that has heap size requirement less than 2.5GB and when the application spawns a few hundred threads. 2. Scale JVM/WAS instances with an instance for every 2 cores 3. Affinitize JVM/WAS instances on a subset of cores within a chip (avoid span JVM/WAS instances across chip boundary). 4. Turning off HW data prefetch with AIX command dscrctl n s 1 5. Prior to Java 6 SR7 / WAS V7.0.0.9, enable 64 KB page size. To realize additional performance gain, enable 16 MB page size.
POW03066-USEN-00.doc
Page 24
IBM Corporation 2009 IBM Corporation Systems and Technology Group Route 100 Somers, New York 10589 Produced in the United States of America February 2011 All Rights Reserved This document was developed for products and/or services offered in the United States. IBM may not offer the products, features, or services discussed in this document in other countries. The information may be subject to change without notice. Consult your local IBM business contact for information on the products, features and services available in your area. All statements regarding IBM future directions and intent are subject to change or withdrawal without notice and represent goals and objectives only. IBM, the IBM logo, ibm.com, AIX, POWER7 and WebSphere are trademarks or registered trademarks of International Business Machines Corporation in the United States, other countries, or both. If these and other IBM trademarked terms are marked on their first occurrence in this information with a trademark symbol ( or ), these symbols indicate U.S. registered or common law trademarks owned by IBM at the time this information was published. Such trademarks may also be registered or common law trademarks in other countries. A current list of IBM trademarks is available on the Web at "Copyright and trademark information" at www.ibm.com/legal/copytrade.shtml Other company, product, and service names may be trademarks or service marks of others. IBM hardware products are manufactured from new parts, or new and used parts. In some cases, the hardware product may not be new and may have been previously installed. Regardless, our warranty terms apply. Copying or downloading the images contained in this document is expressly prohibited without the written consent of IBM. Information concerning non-IBM products was obtained from the suppliers of these products or other public sources. Questions on the capabilities of the non-IBM products should be addressed with those suppliers. All performance information was determined in a controlled environment. Actual results may vary. Performance information is provided AS IS and no warranties or guarantees are expressed or implied by IBM. Buyers should consult other sources of information, including system benchmarks, to evaluate the performance of a system they are considering buying. When referring to storage capacity, 1 TB equals total GB divided by 1000; accessible capacity may be less. The IBM home page on the Internet can be found at: http://www.ibm.com. The IBM Power Systems home page on the Internet can be found at: http://www.ibm.com/systems/power/
The Power Architecture and Power.org wordmarks and the Power and Power.org logos and related marks are trademarks and service marks licensed by Power.org. Java and all Java-based trademarks and logos are trademarks of Sun Microsystems, Inc. In the United States and/or other countries.
POW03066-USEN-00
POW03066-USEN-00.doc
Page 25