2

I have a long process that has two main stages. The first stage and the second stage slightly vary in terms of their execution path.

I just realized that if I create a copy of the same method with a different name and use different names in each stage, according to JMH (-server, on java-7-openjdk-amd64), I get more than 25% speedup for the method calls in the second stage (over millions of calls to the method, measured with 5 invocations, after a 5 invocation warmup).

Is there a way to tell JVM to forget previous optimizations about a method and relearn from scratch?

In the following example code, the benchmarked method is run and the comparison is done between two versions calling checkChar and checkChar0 in stage2.

final public void run(){
   sumStg1=0;
   for(int i=0; i< 10000; i++){
      String str = consumeString();
      for(int i= 0; i<K; i++){
         sumStg1 += checkChar(str.charAt(i), i)?1:0;
      }
   }

   sumStg2=0;
   for(int j=0; j< 10000000; j++){
      String str = consumeString();
      for(int i=K/2; i<str.length(); i++){
         sumStg2 += checkChar(str.charAt(i), i)?1:0;
      }
   }
}

final public boolean checkChar(char in, int i){
   if(i < K/2){
     ...
   } else if (i < K){
     ...
   } else {
     ...
   }
}

//identical method to checkChar
final public boolean checkChar0(char in, int i){
   if(i < K/2){
     ...
   } else if (i < K){
     ...
   } else {
     ...
   }
}
topkara
  • 886
  • 9
  • 15

2 Answers2

0

Two ideas come to mind:

A) Call the method through a mutable CallSite and updating it with a new method handle pointing to the same method and then calling syncAll() should trigger recompilation of the calling methods.

A SwitchPoint provides similar functionality.

What I don't know is whether the JVM might apply any cleverness here, skipping recompilation if a method is replaced with itself.

B) Apply a class file retransformation that essentially doesn't change anything, except maybe appending some inert bytecode to the method body or whatever.

Note that I haven't tried any of this, so no guarantees.


It's also possible that you're not benchmarking what you intend to benchmark. JMH is no magic stick that makes all measurement problems go away by waving it at the code.

You say that your actual application consists of two phases and there is a single phase transition.

But in JMH you're using 10 iterations overall (with N invocations each) which means 10*N forward phase transitions and 10*N backward transitions as a new iteration starts. This will eventually cause the JITs to give up on recompilation.

JMH is designed to measure steady-state performance while your application relies on one-off behavior.

Community
  • 1
  • 1
the8472
  • 40,999
  • 5
  • 70
  • 122
  • Both options seem very interesting. However, isn't this sticky optimizer behavior against the core object oriented principles? It is very plausible that an inherited method is used in different ways by the subclasses, and the optimization will be geared towards whichever subclass uses it most **in the beginning stages** of the program/service. Am I missing something here? – topkara Jul 27 '15 at 02:21
  • It's not so much which (sub)classes are used globally (although class hierarchy analysis has an impact there too) but which classes are used *at a callsite* (assuming the code has been inlined to that callsite). So if you're changing the type profiles at a specific callsite that's a problem for the optimizer. It will try to accommodate a few times, but eventually give up to not waste CPU cycles optimizing over and over again. Maybe you did ask the wrong question... – the8472 Jul 27 '15 at 03:34
0

Another couple of ideas:

  • Load the class again in a new classloader and use that version instead of the statically loaded version.

  • Set a much larger value for -XX:CompileThreshold.

(Both of these have significant / obvious downsides, but if performance matters this much to you ....)

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • A separate classloader does sound like a practical approach. It makes me think whether I could use an anonymous class to achieve the same effect. – topkara Jul 27 '15 at 02:32
  • No ... that wouldn't help. An anonymous class is loaded ... and optimized ... just like a regular named one. "Anonymous" merely means that you cannot name the class in Java source code. – Stephen C Jul 27 '15 at 07:47