健壮的 Java 基准测试

参考:http://www.ibm.com/developerworks/cn/java/j-benchmark2/index.html

1 度量时间:

两种时间:System.currentTimeMillis    vs    System.nanoTime    vs    ThreadMXBean.getCurrentThreadCpuTime

1.1 System.currentTimeMillis的问题:

分辨率不足够精确;

假设它反映 “墙上时钟” 的时间:由于标准时间到夏时制的转换或 Network Time Protocol(NTP)同步等事件,它的值偶尔会有突变(向前或向后)。

1.2 System.nanoTime的优势:

只适用于度量时间差。

精确性和精度应该不会比 System.currentTimeMillis 差,在一些平台上与System.currentTimeMillis 相同。

在现代硬件和操作系统上可以提供微秒级的精确性和精度。

1.3 ThreadMXBean.getCurrentThreadCpuTime的不足:

平台可能不支持;

“在某些 Java 虚拟机实现中,启用线程 CPU 时间度量可能导致很大的开销”。某些操作系统度量线程 CPU 时间所需的 microaccounting 总是打开的,所以getCurrentThreadCpuTime 没有额外的性能影响;其他操作系统在默认情况下关闭这个特性,如果启用它,它会降低进程中的所有线程或所有进程的性能。

分辨率不明确;

当前线程使用的 CPU 时间可能是不相关的。


2 时间度量 API本身的耗时

所有时间度量 API 需要注意的问题:它们都有执行开销,如果过于频繁地执行这些 API,就会严重歪曲度量值。

这个问题的影响高度依赖于平台。例如,在 Windows 的现代版本中,System.nanoTime 涉及一个执行时间为微秒级的操作系统调用,所以调用它的频率不应该高于每 100 微秒一次,否则对度量的影响就会超过 1%。(相反,System.currentTimeMillis 只需要读取一个全局变量,所以执行得非常快,是纳秒级的。

如果仅仅考虑对度量的影响,可以更频繁地调用它;但是,这个全局变量的更新没这么频繁,根据 表 1 来看,大约是每 10 到 15 毫秒一次,所以频繁地调用它是没有必要的)。

另一方面,在大多数 Solaris(和某些 Linux®)机器上,System.nanoTime 常常比 System.currentTimeMillis 执行得快。

 

3 影响度量的Java因素:

3.1 代码预热

类装载

混合模式:解释模式和编译模式的混杂

3.2 动态优化
3.2.1 去优化:

编译器可以停止使用已编译的方法,并对它进行一段时间的解释,然后重新编译它

    A 使单态调用转换失效的类装载;

   B是不常用的分支:最初编译时只编译最常用的代码路径,而不常用的分支(比如异常路径)仍采用解释方式;但如果不常用的分支变成了经常执行的,它们就成了热点,这会触发重新编译。

3.2.2 OSR:堆栈上替换

    A 在使用 OSR 时,代码质量可能是次优的。例如,OSR 有时候无法提升循环、消除数组边界检查或解开循环(参见 参考资料)。如果使用 OSR,可能无法得到最佳性能。

    B 假设希望获得最佳性能,那么解决 OSR 问题的惟一方法是了解什么时候会出现 OSR,并调整代码结构来避免它。这通常需要把关键的内部循环放在单独的方法中。

3.2.3 DCE:消除死代码

    在某些情况下,编译器可以判断出某些代码根本不影响输出,所以编译器会消除这些代码。

3.3 资源回收

典型的 JVM 会自动执行两种资源回收:垃圾收集和对象终结(GC/OF);但均不受控制。

需要把任务的 GC/OF 与同一JVM 会话中其他代码造成的 GC/OF 分开时:惟一的方法是在执行基准测试之前尝试清理 JVM,还要尝试确保任务本身的 GC/OF 在度量结束前完全完成。

问题:在度量循环内调用 System.gc 和 System.runFinalization 会歪曲 GC/OF 成本,比如System.gc 会用一个 stop-the-world 收集器对所有代进行一次全面的垃圾收集。?

3.4 缓存

比如:文件系统缓存

3.5 准备
3.5.1 电源切换等环境因素
3.5.2 避免其它程序的影响
3.5.3 JVM 选项

有许多 JVM 选项会影响基准测试。比较重要的选项包括:

JVM 的类型:服务器(-server)与客户机(-client)。

确保有足够的内存可用(-Xmx)。

使用的垃圾收集器类型(高级的 JVM 提供许多调优选项,但是要小心使用)。

是否允许类垃圾收集(-Xnoclassgc)。默认设置是允许类 GC;使用 -Xnoclassgc 可能会损害性能。

是否执行 escape 分析(-XX:+DoEscapeAnalysis)。

是否支持大页面堆(-XX:+UseLargePages)。

是否改变了线程堆栈大小(例如,-Xss128k)。

使用 JIT 编译的方式:总是使用(-Xcomp)、从不使用(-Xint)或只对热点使用(-Xmixed;这是默认选项,产生的性能最好)。

在执行 JIT 编译之前(-XX:CompileThreshold)、后台 JIT 编译期间(-Xbatch)或分级的 JIT 编译期间(-XX:+TieredCompilation)收集的剖析数据量。

是否执行偏向锁(biased locking,-XX:+UseBiasedLocking);注意,JDK 1.6 及更高版本会自动执行这个特性。

是否激活最近的试验性性能调整(-XX:+AggressiveOpts)。

启用还是禁用断言(-enableassertions 和 -enablesystemassertions)。

启用还是禁用严格的本机调用检查(-Xcheck:jni)。

为 NUMA 多 CPU 系统启用内存位置优化(-XX:+UseNUMA)。

 

4 统计学度量标准

4.1 平均值  vs  标准差
4.2 度量:

两个任务的平均值之差超过了三倍标准偏差(选用两个标准偏差中较大者)

4.3 置信区间 bootstrapping技术?

 

 

5 使用 Benchmark 解决性能难题 

public static void main(String[] args) throws Exception {

    Callable<Integer> task = 

        new Callable<Integer>() { public Integer call() { return fibonacci(35); } };

    System.out.println("fibonacci(35): " + new Benchmark(task));

}

protected static int fibonacci(int n) throws IllegalArgumentException {

    if (n < 0) throw new IllegalArgumentException("n = " + n + " < 0");

    if (n <= 1) return n;

    return fibonacci(n - 1) + fibonacci(n - 2);

}

 

 

6 测试建议:

1 如果希望测试一种新算法的性能,那么不但要在基准测试环境中进行度量,还应该在真实应用程序场景中度量,了解它是否会产生显著的性能差异。

2 不要忽视剖析。应该用能够找到的各种剖析工具运行基准测试,从而确认其行为符合预期。

3 最后,要想得出正确的性能结论,就必须了解低层的操作执行方式。

 

所有时间度量 API 需要注意的问题:它们都有执行开销,如果过于频繁地执行这些 API,就会严重歪曲度量值。这个问题的影响高度依赖于平台。例如,在 Windows 的现代版本中,System.nanoTime 涉及一个执行时间为微秒级的操作系统调用,所以调用它的频率不应该高于每 100 微秒一次,否则对度量的影响就会超过 1%。(相反,System.currentTimeMillis 只需要读取一个全局变量,所以执行得非常快,是纳秒级的。如果仅仅考虑对度量的影响,可以更频繁地调用它;但是,这个全局变量的更新没这么频繁,根据 表 1 来看,大约是每 10 到 15 毫秒一次,所以频繁地调用它是没有必要的)。另一方面,在大多数 Solaris(和某些 Linux®)机器上,System.nanoTime 常常比 System.currentTimeMillis 执行得快。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值