我有一个测试Calendar.getInstance().getTimeInMillis()和System.currentTimeMilli()的代码:
long before = getTimeInMilli();
for (int i = 0; i < TIMES_TO_ITERATE; i++)
{
long before1 = getTimeInMilli();
doSomeReallyHardWork();
long after1 = getTimeInMilli();
}
long after = getTimeInMilli();
System.out.println(getClass().getSimpleName() + " total is " + (after - before));我希望确保没有发生JVM或编译器优化,因此测试将是有效的,并将实际显示不同之处。
如何确定?
编辑:我更改了代码示例,这样就更清晰了。我在这里要检查的是,在不同的实现中调用getTimeInMilli()需要多长时间-- Calendar与System。
发布于 2011-03-09 07:04:40
我觉得你需要让JIT瘫痪。添加到您的run命令next选项:
-Djava.compiler=NONE发布于 2011-03-09 07:06:55
您希望进行优化,因为它会在现实生活中发生--如果JVM没有按照您感兴趣的实际情况进行优化,那么测试就无效了。
但是,如果您想确保JVM不删除它可能会考虑不执行操作的调用,一个选项是使用结果--因此,如果您重复调用System.currentTimeMillis(),则可以将所有返回值和起来,然后在最后显示和。
注意,您可能仍然存在一些偏见--例如,如果JVM能够廉价地确定上次调用System.currentTimeMillis()只经过了一小段时间,那么可能会有一些优化,因此它可以使用缓存的值。我不是说这是真的,但这是你需要考虑的事情。最终,基准测试只能真正测试您给它们带来的负载。
另一件需要考虑的事情是:假设您想对代码大量运行的真实情况进行建模,那么在进行任何计时之前,您应该运行大量代码--因为Hotspot JVM将越来越难优化,而且您可能关心经过严重优化的版本,并且不希望度量JITting和代码的“缓慢”版本的时间。
正如斯蒂芬提到的,你几乎可以肯定的是,你应该把时间控制在循环之外.别忘了用结果..。
发布于 2011-03-09 07:34:51
您所做的工作看起来像是基准测试,您可以阅读健壮的Java基准测试以获得一些关于如何使其正确的良好背景。一句话,你不需要关掉它,因为它不会发生在生产服务器上。相反,您需要知道是否接近“实时”估计/性能。在优化之前,您需要“热身”您的代码,如下所示:
// warm up
for (int j = 0; j < 1000; j++) {
for (int i = 0; i < TIMES_TO_ITERATE; i++)
{
long before1 = getTimeInMilli();
doSomeReallyHardWork();
long after1 = getTimeInMilli();
}
}
// measure time
long before = getTimeInMilli();
for (int j = 0; j < 1000; j++) {
for (int i = 0; i < TIMES_TO_ITERATE; i++)
{
long before1 = getTimeInMilli();
doSomeReallyHardWork();
long after1 = getTimeInMilli();
}
}
long after = getTimeInMilli();
System.out.prinltn( "What to expect? " + (after - before)/1000 ); // average time当我们使用这种方法度量代码的性能时,我们的代码需要工作的实时时间就会更少。更好的方法是用分离的方法度量代码:
public void doIt() {
for (int i = 0; i < TIMES_TO_ITERATE; i++)
{
long before1 = getTimeInMilli();
doSomeReallyHardWork();
long after1 = getTimeInMilli();
}
}
// warm up
for (int j = 0; j < 1000; j++) {
doIt()
}
// measure time
long before = getTimeInMilli();
for (int j = 0; j < 1000; j++) {
doIt();
}
long after = getTimeInMilli();
System.out.prinltn( "What to expect? " + (after - before)/1000 ); // average time第二种方法更精确,但也取决于VM。例如,HotSpot可以执行“堆内替换”,这意味着如果方法的某些部分经常被执行,它将被VM优化,旧版本的代码将在执行方法时与优化版本进行交换。当然,它需要从VM端执行额外的操作。JRockit不这样做,只有在再次执行此方法时才会使用优化版本的代码(因此没有“运行时”优化.我是说,在我的第一个代码样本中,所有的旧代码都会被执行.除了doSomeReallyHardWork内部--它们不属于这个方法,所以优化将很好地工作)。
更新:相关代码是在我回答时编辑的;)
https://stackoverflow.com/questions/5242405
复制相似问题