8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

如何用 Java 编写正确的微基准测试?

politus 1月前

54 0

如何用 Java 编写(并运行)正确的微基准测试?我正在寻找一些代码示例和注释,以说明各种需要考虑的事情。例如:基准测试是否应该测量时间/

如何用 Java 编写(并运行)正确的微基准测试?

我正在寻找一些代码示例和注释来说明各种值得思考的事情。

例如:基准测试应该测量时间/迭代还是迭代/时间,为什么?

相关: 秒表基准测试可以接受吗?

帖子版权声明 1、本帖标题:如何用 Java 编写正确的微基准测试?
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由politus在本站《eclipse》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 请参阅几分钟前的[这个问题][1],了解一些相关信息。编辑:抱歉,这不应该是一个答案。我应该以评论的形式发布。[1]:

  • @Raedwald 我认为 JEP 旨在为 JDK 代码添加一些微基准,但我不认为 jmh 会包含在 JDK 中......

  • Java HotSpot 创建者提供了 有关编写微基准测试的提示 :

    规则 0: 阅读有关 JVM 和微基准测试的权威论文。Brian Goetz,2005 年的 。不要对微基准测试抱有太高的期望;它们只能测量有限范围的 JVM 性能特征。

    规则 1: 始终包含一个预热阶段,该阶段会全程运行测试内核,足以在计时阶段之前触发所有初始化和编译。(预热阶段的迭代次数较少是可以的。经验法则是几万次内循环迭代。)

    规则 2: 始终使用 等运行 -XX:+PrintCompilation , -verbose:gc ,这样您就可以验证编译器和 JVM 的其他部分在计时阶段没有执行意外的工作。

    规则 2.1: 在计时和预热阶段的开始和结束时打印消息,以便您可以验证计时阶段没有来自规则 2 的输出。

    规则 3: 注意 -client -server 以及 OSR 和常规编译之间的区别。 -XX:+PrintCompilation 标志报告 OSR 编译,其中带有 at 符号以表示非初始入口点,例如: Trouble$1::run @ 2 (41 bytes) 。如果您追求最佳性能,则首选服务器而不是客户端,常规而不是 OSR。

    规则 4: 注意初始化效果。不要在计时阶段首次打印,因为打印会加载并初始化类。不要在预热阶段(或最终报告阶段)之外加载新类,除非您专门测试类加载(在这种情况下只加载测试类)。规则 2 是抵御此类效果的第一道防线。

    规则 5: 注意反优化和重新编译的影响。不要在计时阶段第一次采用任何代码路径,因为编译器可能会丢弃并重新编译代码,因为之前乐观地认为该路径根本不会使用。规则 2 是抵御此类影响的第一道防线。

    规则 6: 使用适当的工具来了解编译器的想法,并期待对其生成的代码感到惊讶。在形成关于什么导致某件事情更快或更慢的理论之前,请自己检查代码。

    规则 7: 减少测量中的噪音。在安静的机器上运行基准测试,并多次运行,丢弃异常值。使用将 -Xbatch 编译器与应用程序序列化,并考虑设置 -XX:CICompilerCount=1 以防止编译器与自身并行运行。尽量减少 GC 开销,设置 Xmx (足够大的)equals Xms 并使用 UseEpsilonGC (如果可用)。

    规则 8: 使用库进行基准测试,因为它可能更高效,并且已经为此目的进行了调试。例如 JMH , Caliper or Bill 和 Paul 的 Excellent UCSD Benchmarks for Java .

  • 这也是一篇有趣的文章:ibm.com/developerworks/java/library/j-jtp12214

  • 此外,除非您能接受 + 或 - 15 毫秒的精度(这在大多数 OS + JVM 组合中很常见),否则切勿使用 System.currentTimeMillis()。请改用 System.nanoTime()。

  • 来自 javaOne 的一些论文:azulsystems.com/events/javaone_2009/session/…

  • 需要注意的是,System.nanoTime() 并不保证比 System.currentTimeMillis() 更准确。它只保证至少一样准确。不过,它通常准确得多。

  • 必须使用 System.nanoTime() 而不是 System.currentTimeMillis() 的主要原因是前者保证单调递增。将两次 currentTimeMillis 调用的返回值相减实际上可能会产生负数结果,这可能是因为系统时间已被某些 NTP 守护程序调整。

  • 引用 10

    我知道这个问题已经被标记为已回答,但我想提一下两个可以帮助我们编写微基准的库

    Google 的 Caliper

    入门教程

    1. http://codingjunkie.net/micro-benchmarking-with-caliper/
    2. http://vertexlabs.co.uk/blog/caliper

    OpenJDK 中的 JMH

    入门教程

    1. 避免 JVM 上的基准测试陷阱
    2. 使用 JMH 进行 Java 微基准测试
    3. JMH简介
  • +1 它可以被添加为已接受答案的第 8 条规则:规则 8:因为很多事情都可能出错,所以您应该使用现有的库,而不是尝试自己做!

  • 引用 12

    @Pangea jmh 现在可能比 Caliper 更优秀,另请参阅:groups.google.com/forum/#!msg/mechanical-sympathy/m4opvy4xq3U/…

  • Java 基准测试的重要事项包括:

    • 计时 之前, 先运行代码几次,让 JIT 预热一下
    • 确保运行时间足够长,以便能够在几秒或(最好)几十秒内测量结果
    • 虽然您无法 System.gc() 在迭代之间调用它,但最好在测试之间运行它,以便每个测试都有望获得一个“干净”的内存空间来工作。(是的,这 gc() 更多的是一种暗示而不是保证,但根据我的经验,它很 可能 真的会进行垃圾收集。)
    • 我喜欢显示迭代次数和时间,以及时间/迭代的分数,该分数可以缩放,这样“最佳”算法的分数为 1.0,其他算法的分数则以相对方式计算。这意味着您可以在较长时间内运行 所有 算法,迭代次数和时间均会发生变化,但仍会获得可比较的结果。

    我刚刚开始写一篇关于 .NET 基准测试框架设计的博客。我 之前 写过 几篇 ,也许可以给你一些启发 - 当然,不是所有的内容都合适,但有些内容可能合适。

  • 小挑剔:在我看来,“以便每个测试得到”应该是“以便每个测试可能得到”,因为前者给人的印象是调用 gc 总是会释放未使用的内存。

  • 引用 15

    @SanjayT.Sharma:嗯,我们的意图是确实如此。虽然不能严格保证,但这实际上是一个非常强烈的暗示。将进行编辑以使其更清晰。

  • 我不同意调用 System.gc()。这只是一个提示,仅此而已。甚至不是“希望它会做某事”。你永远不应该调用它。这是编程,不是艺术。

  • @gyabraham:是的,这是一个提示 - 但据我观察,它通常会被采纳。所以,如果你不喜欢使用 System.gc(),你打算如何尽量减少一次测试中由于之前测试中创建的对象而产生的垃圾收集?我是务实的,不是教条的。

  • @gyabraham:我不知道你说的“大退步”是什么意思。你能详细说明一下吗?再说一遍——你有什么建议可以提供更好的结果吗?我确实明确说过,这不是保证……

  • jmh 是 OpenJDK 的最新补充,由 Oracle 的一些性能工程师编写。绝对值得一看。

    jmh 是一个 Java 工具,用于构建、运行和分析用 Java 和其他针对 JVM 的语言编写的纳米/微型/宏观基准测试。

    样本测试评论 中隐藏着非常有趣的信息 .

    参见:

    • 避免 JVM 上的基准测试陷阱
    • 讨论jmh的主要优势
  • 另请参阅此博客文章:psy-lob-saw.blogspot.com/2013/04/... 有关开始使用 JMH 的详细信息。

返回
作者最近主题: