VarHandle instance methods performance

Frank Yuan frank.yuan at oracle.com
Wed Apr 24 09:51:40 UTC 2019


Hi Aleksey

I happened to see the performance to access a field by VarHandle API is much worse than the native access.

I tested the following situations:
1. reading a volatile field directly
2. calling getVolatile against this volatile field
3. calling getVolatile against another non-volatile field

As my expectation, Situation 2 has similar performance with situation 3, but both of them have 100 times of situation 1 execution time in my test.

I think it should be due to some overhead, and it doesn't violate the JEP 193 performance requirement. But I still can't figure out why it's so slow after runtime compiling? Hope you can give me some point. Thanks!


My test code is as below:

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;

public class Test5 {

    static final int iter_num = 100000000;
    private volatile int vf = 1;
    private int f = 1;
    final VarHandle vhf;
    final VarHandle vhvf;
    final ThreadMXBean threadMXBean;
    
    public Test5 () throws Exception {
        vhf = MethodHandles.lookup().findVarHandle(
                Test5.class, "f", int.class);
        vhvf = MethodHandles.lookup().findVarHandle(
                Test5.class, "vf", int.class);
        
        threadMXBean = ManagementFactory.getThreadMXBean();
        
        //System.out.println(threadMXBean.isCurrentThreadCpuTimeSupported());
        //System.out.println(threadMXBean.isThreadCpuTimeEnabled());
    }

    
    public void measGetVolatileField() {
        int tmpProgress = 0;
        long startCpu = threadMXBean.getCurrentThreadCpuTime();
        long startUser = threadMXBean.getCurrentThreadUserTime();
        for (int i = 0; i < iter_num; ++i) {
            tmpProgress += vf;
        }
          
        long endCpu = threadMXBean.getCurrentThreadCpuTime();
        long endUser = threadMXBean.getCurrentThreadUserTime();
        
        long durCpu = endCpu -startCpu;
        long durUser = endUser - startUser;
        System.out.println("measGetVolatileField");
        System.out.println("cpu time: " + durCpu);
        System.out.println("user time: " + durUser);
        System.out.println(tmpProgress);
    }
    
    
    public void measGetVolatileFieldByVHWithVolatile() {
        int tmpProgress = 0;
        long startCpu = threadMXBean.getCurrentThreadCpuTime();
        long startUser = threadMXBean.getCurrentThreadUserTime();
        for (int i = 0; i < iter_num; ++i) {
            tmpProgress += (int) vhvf.getVolatile(this);
        }
          
        long endCpu = threadMXBean.getCurrentThreadCpuTime();
        long endUser = threadMXBean.getCurrentThreadUserTime();
        
        long durCpu = endCpu -startCpu;
        long durUser = endUser - startUser;
        System.out.println("measGetVolatileFieldByVHWithVolatile");
        System.out.println("cpu time: " + durCpu);
        System.out.println("user time: " + durUser);
        System.out.println(tmpProgress);
    }
    
    
    public void measGetFieldByVHWithVolatile() {
        int tmpProgress = 0;
        long startCpu = threadMXBean.getCurrentThreadCpuTime();
        long startUser = threadMXBean.getCurrentThreadUserTime();
        for (int i = 0; i < iter_num; ++i) {
            tmpProgress += (int) vhf.getVolatile(this);
        }
          
        long endCpu = threadMXBean.getCurrentThreadCpuTime();
        long endUser = threadMXBean.getCurrentThreadUserTime();
        
        long durCpu = endCpu -startCpu;
        long durUser = endUser - startUser;
        System.out.println("measGetFieldByVHWithVolatile");
        System.out.println("cpu time: " + durCpu);
        System.out.println("user time: " + durUser);
        System.out.println(tmpProgress);
    }
    
    public static void main(String[] args) throws Exception {
        
        for (int i = 0; i < 5; i++) {
            Test5 test = new Test5 ();
            
            
            Thread threadA = new Thread(() -> test.measGetVolatileField());
            Thread threadB = new Thread(() -> test.measGetVolatileFieldByVHWithVolatile());
            Thread threadC = new Thread(() -> test.measGetFieldByVHWithVolatile());
            
            threadA.start();
            threadA.join();
            
            threadB.start();
            threadB.join();
            
            threadC.start();
            threadC.join();
           
        }

    }

}




More information about the core-libs-dev mailing list