Java 独立于迭代次数的性能测试
尝试回答此问题: 我做了一个性能测试:Java 独立于迭代次数的性能测试,java,performance,Java,Performance,尝试回答此问题: 我做了一个性能测试: class A{} class B extends A{} A b = new B(); void execute(){ boolean test = A.class.isAssignableFrom(b.getClass()); // boolean test = A.class.isInstance(b); // boolean test = b instanceof A; } @Test public void testPerf()
class A{}
class B extends A{}
A b = new B();
void execute(){
boolean test = A.class.isAssignableFrom(b.getClass());
// boolean test = A.class.isInstance(b);
// boolean test = b instanceof A;
}
@Test
public void testPerf() {
// Warmup the code
for (int i = 0; i < 100; ++i)
execute();
// Time it
int count = 100000;
final long start = System.nanoTime();
for(int i=0; i<count; i++){
execute();
}
final long elapsed = System.nanoTime() - start;
System.out.println(count+" iterations took " + TimeUnit.NANOSECONDS.toMillis(elapsed) + "ms.);
}
class A{}
类B扩展了{}
A b=新b();
void execute(){
布尔测试=A.class.isAssignableFrom(b.getClass());
//布尔测试=A.class.isInstance(b);
//布尔测试=A的b实例;
}
@试验
公共void testPerf(){
//预热代码
对于(int i=0;i<100;++i)
执行();
//计时
整数计数=100000;
最终长启动=System.nanoTime();
对于(int i=0;i
一百次迭代对于热身来说是不够的。默认的编译阈值是10000次迭代(一百次以上),所以最好至少超过这个阈值一点
一旦编译被触发,世界就不会停止;编译是在后台进行的。这意味着它的效果只有在稍微延迟后才会开始被观察到
有足够的空间对测试进行优化,这样整个循环都会被压缩成最终结果,这就解释了常数的原因
无论如何,我总是让一个外部方法调用内部方法大约10次来进行基准测试。内部方法根据需要进行大量迭代,比如10000次或更多次,以使其运行时间上升到至少几十毫秒。我甚至不必为nanoTime
操心,因为如果微秒精度对您很重要的话,这只是测量时间间隔太短的标志
当您这样做时,您可以使JIT在内部方法的编译版本被解释版本替换后更容易地执行它。另一个好处是,您可以确保内部方法的时间稳定。如果您想对一个简单函数进行真正的基准测试,您应该使用micro-基准测试工具,比如。尝试创建自己的基准测试会简单得多。JIT编译器可以消除没有任何作用的循环。这可以在10000次迭代后触发
我怀疑您正在计时的是JIT检测到循环没有做任何事情并将其删除所需的时间。这将比执行10000次迭代所需的时间稍长。您确定100000次迭代需要15毫秒吗?似乎很多…@assylias我猜他只测量了“启动时间”在JIT替换解释代码之前。我认为JIT将通过静态分析证明循环可以折叠为单个检查并编译,而无需循环。如果编译阈值为1,它将立即实现这一点。
@Test
public void testPerf() {
boolean test = false;
// Warmup the code
for (int i = 0; i < 100; ++i)
test |= b instanceof A;
// Time it
int count = Integer.MAX_VALUE;
final long start = System.nanoTime();
for(int i=0; i<count; i++){
test |= b instanceof A;
}
final long elapsed = System.nanoTime() - start;
System.out.println(count+" iterations took " + TimeUnit.NANOSECONDS.toMillis(elapsed) + "ms. AVG= " + TimeUnit.NANOSECONDS.toMillis(elapsed/count));
System.out.println(test);
}