Guideline: Make loops as compact as possible
Compact loops tend to run faster and are easier to optimize. If possible, remove any code that is
loop-independent, or that rarely runs, from the loop body. Although the TRJIT compiler tries to
determine loop-invariant code and extract such code from loop bodies, proving such loop-invariant
properties can sometimes be difficult, because of virtual calls and dynamic class loading.
Guideline: Use locals instead of fields or static variables, where possible
If a field or static variable is accessed within a loop body, consider using local variables to hold the
contents of the field or static variable for the duration of the loop. A JIT compiler might not optimize
memory access to a field or static variable out of the loop, because such accesses can be visible
outside the scope of the current method (for example, callee methods and other threads).
Figure 15 shows a loop with an assignment to a static variable, myStaticX, inside the loop. The JIT
compiler might not be able to optimize the assignment out of the loop.
public static int myStaticX;
// Static variable myStaticX;
public void methodBad() {
for (int i = 0; i < N; i++) {
//
Static
assignment
myStaticX = i;
}
}
Figure 15. Example of a poorly behaved loop with static assignment - The assignment to myStaticX might not be
removed from the loop body
In contrast, Figure 16 shows a well-behaved loop without any field or static variable accesses. The
static assignment to myStaticX occurs outside the loop body.
public static int myStaticX;
// Static variable myStaticX;
public void methodGood() {
int temp = 0;
for (int i = 0; i < N; i++) {
temp = i;
}
myStaticX = temp; // Static assignment is outside of loop.
}
Figure 16. Example of a well-behaved loop with no static or field assignments - The assignment to myStaticX is
outside the loop body
Guideline: System.arraycopy() is well-optimized by the JIT
When copying the elements of one array to another, consider using the System.arraycopy() function
that is defined in the Java API, instead of writing your own loop or routine. TRJIT recognizes the
IBM Just-In-Time Compiler (JIT) for Java
Best practices and coding guidelines for improving performance
System.arraycopy() function and generates highly optimized platform-specific code to perform the
array-copy operations.
Guideline: TRJIT can also optimize special loops such as memset and array translate
Certain hardware platforms offer vector or other complex instructions that you can use to improve the
performance of array operations. An example of this are the translate instructions that are offered on
the IBM System z® platform; the translate instructions take bytes from an input array, find the
corresponding output bytes in a lookup table, and insert them into an output array. All operations are
performed in hardware, yielding significant performance benefits.
TRJIT has an optimization to recognize special loops and to transform them to take advantage of
these special hardware instructions [18]. The examples in Figure 17, Figure 18 and Figure 19 show
the basic idioms for memset, array translate and search string. If any potential loops are coded to
similarly match the idioms, then TRJIT tries to transform such loop candidates to exploit the hardware
instructions.
// Initializes an array to a particular value.
public void memset() {
byte myArray[];
// Byte or Char array
for (int i = 0; i < myArray.length; i++) {
myArray[i]
=
C;
}
}
Figure 17. Basic Idiom for memset
// Translates an input array to an output array via a lookup table.
public void arraytranslate() {
byte in[];
// Byte or Char array
byte out[];
// Byte or Char array
int i = 0; // in array index.
int j = 0;
// out array index.
byte map[];
// Lookup table.
for (i = 0; i
byte T = Map[in[i]];
if (T == exitChar) break; //Terminate on certain chars (optional)
out[j] = T;
j++;
}
}
Figure 18. Basic Idiom for arraytranslate
IBM Just-In-Time Compiler (JIT) for Java
Best practices and coding guidelines for improving performance
// Searches a char array for specific characters.
public void searchString() {
char myCharArray[ ];
// Byte or Char array
for (int i = 0; i < myCharArray.length; i++) {
char T = myCharArray [i];
if (T == 0x0A || T == 0x0D || T <= 0x40) // Exit condition.
break;
i++;
}
return myCharArray [i];
}
Figure 19. Basic Idiom for search string
Synchronization
Although synchronization is very important for concurrent programming in Java, a cost is associated with
synchronization. This includes the cost of acquiring, as well as releasing, the lock that a thread holds.
Another associated cost is starvation – the longer a thread holds onto a resource, the longer other
threads might have to wait to acquire access to the resource. Incorrect uses of synchronization can also
lead to deadlocks within the Java application.
The performance cost that is associated with volatile is almost the same as synchronization. Long
volatiles are particularly expensive on some 32-bit platforms.
Minimizing the cost of synchronization usually means minimizing the contention on a shared resource.
•
As much as possible, use the java.util.concurrent API because this offers more scalable
nonblocking data structures.
•
Avoid synchronization on the same lock when it is possible to use different locks to access
different data by threads.
•
Use the synchronized keyword judiciously. Make synchronized blocks short and move thread-
safe code out of synchronized blocks in the application.
•
Use thread-local data. Restrict data to a single thread or use java.lang.ThreadLocal
to maintain
data on a per-thread basis.
•
Avoid synchronizing static methods.
IBM Just-In-Time Compiler (JIT) for Java
Best practices and coding guidelines for improving performance