Tuesday, March 16, 2021

C1 & C2 Compilers

JVM implementation contains two JIT compilers, commonly referred to as C1 and C2 compilers.

The JIT compilation itself takes processing time and memory. The more aggressive the optimization it applies, the more resources in terms of CPU and memory it compilation is going to take.

C1 compiler runs quickly but it results in produces less optimized code

C2 compiler takes more time and resources, but results in producing well optimized code.


C1 compiler

This is more suitable for client side applications which typically have fewer resources (CPU, memory capacity) at their disposal. They require faster startup and should typically be more responsive to end user. Also client applications runs for a shorter period of time. Typically they run for a few hours before they are shutdown.

C1 compiler does simple optimizations that are not resource heavy, so that it does not introduce noticeable impact to the startup time or the responsiveness of the application.

C1 compiler is traditionally referred to as client compiler and till early releases of Java 7, it is enabled with -client option when starting the JVM. 


C2 compiler

This is most suitable for server side applications. Applications running on server typically has more resources (CPU, memory) at their disposal. Server applications typically run for a longer period of time. Its not uncommon to see servers applications kept running for months without getting restarted.

C2 compiler does aggressive optimization of bytecodes. This might bring in an additional lag when the compiler performing its job, but the long run efficiency from this aggressively compiled code outweighs the overhead incurred. 

C2 compiler is traditionally referred to as server compiler and till early releases of Java 7, it is enabled with -server option when starting the JVM. 


Choosing C1 vs. C2

Often tuning JVM for JIT compilation is about making a choice between C1 vs. C2. There is no default rule to state which one is best for which application. 

For GUI applications, where responsiveness is an important measure of performance of the application C1 might better at startup and initial load. C2 might bring in a slight improvement in responsiveness over time, but if this improvement will make a noticeable difference would depend on the nature and complexity of the application.

Server side applications and batch applications typically benefit from the use of C2 compiler. Longer the program runs and more no. of times a section of code is getting executed, cumulative benefit accrued is bound to outweigh the overhead caused by compilation.


JIT compiler options

In Java versions 7 & prior, there are 3 options to choose from, to select a compiler when starting JVM

  1. -client
  2. -server
  3. -d64

We have seen the -client and -server options in this post. -d64 can be thought of as a synonym for -server option. Only difference is -server can be specified for both 32 bit and 64 bit OS whereas -d64 can be specified only for 64 bit OS. JVM will throw an error if we specify -d64 on a 32 bit system

Even when specifying an option to use, there is no guarantee that the JVM uses it. This is because for some hardware architecture, JVM might have implementation for only one of the compilers. In this case, the option we specify gets ignored and the only compiler available will be used


Default compiler

When we do not specify an option at startup, JVM determines the default compiler to use. Its makes this decision based on

  1. What is the OS used
  2. Is it 32 bit or 64 bit 
  3. No. of CPUs on the system

The logic used to determine is a bit complex. But as a thumb rule, we can take that if the system has 64 bit OS or has 2 of more CPU's, -server option is used. But be aware that this thumb rule does not always hold good. 

 

Determining the compiler used

We can determine which JIT compiler is used, by running the java -version command.  

>java -version

openjdk version "1.8.0_41"
OpenJDK Runtime Environment (build 1.8.0_41-b04)
OpenJDK Client VM (build 25.40-b25, mixed mode)

The last line indicate that -client option is used. This is on my Windows laptop running OpenJDK 1.8. Output on your system might vary.

When I run the command with -server option, I see the -server option is getting used as is evident from the last line in the below output

>java -server -version

openjdk version "1.8.0_41"
OpenJDK Runtime Environment (build 1.8.0_41-b04)
OpenJDK Server VM (build 25.40-b25, mixed mode)


But since Java 8, tiered compilation is the default. This internally uses C1 and C2 for compilation and uses a tiered approach based on the hotness of the code that is getting executed. We will look at tiered compilation in depth in our next post.

 


No comments:

Post a Comment