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