【问题标题】:CPU execution time in JavaJava中的CPU执行时间
【发布时间】:2011-11-20 00:02:37
【问题描述】:

我想计算我的函数在 Java 中执行所需的 CPU 时间。目前我正在做如下。

   long startTime = System.currentTimeMillis();
    myfunction();
    long endTime = System.currentTimeMillis();
    long searchTime = endTime - startTime;

但我发现对于相同的 I/P,我得到不同的时间取决于系统负载。

那么,如何获得我的函数执行所用的准确 CPU 时间。

【问题讨论】:

    标签: java time execution


    【解决方案1】:

    您可以在这里寻找答案:

    How do I time a method's execution in Java?

    有很多例子可以计算方法的执行时间

    【讨论】:

    • 是的,但没有人真正回答他关于如何测量“CPU 时间”的问题。
    【解决方案2】:

    有许多分析器(Jprofile、Jprobe、Yourkit)可用于分析此类数据。不仅如此,还有更多……(例如内存利用率、线程详细信息等)

    【讨论】:

      【解决方案3】:
      1. System.currentTimeMillis() 只会测量 wall-clock time,永远不会测量 CPU 时间。
      2. 如果您需要挂钟时间,那么System.nanoTime() 通常比currentTimeMillis() 更精确(而且永远不会更差)。
      3. ThreadMXBean.getThreadCPUTime() 可以帮助您了解给定线程使用了多少 CPU 时间。使用ManagementFactory.getThreadMXBean() 获取ThreadMXBeanThread.getId() 以查找您感兴趣的线程的id。请注意,此方法不需要在每个JVM 上都支持!

      【讨论】:

      • 如果我对JavaDoc的理解正确,System.currentTimeMillis()也可能在系统时间改变时突然改变。因此,我认为System.nanoTime() 应该始终优于System.currentTimeMillis() 来衡量经过的时间。
      【解决方案4】:

      随着 JVM 预热,所花费的时间会有所不同。第二次运行它总是比第一次快。 (第一次它必须加载类和调用静态块)在你运行方法10000次之后它会再次更快(它将代码编译为本机代码的默认阈值)

      要为微基准测试获得可重现的平均时间,我建议您忽略前 10,000 次迭代,然后运行 ​​2-10 秒。

      例如

      long start = 0;
      int runs = 10000; // enough to run for 2-10 seconds.
      for(int i=-10000;i<runs;i++) {
          if(i == 0) start = System.nanoTime();
          // do test
      }
      long time = System.nanoTime() - start;
      System.out.printf("Each XXXXX took an average of %,d ns%n", time/runs);
      

      非常重要:每个方法只执行其中一个循环。这是因为它根据使用方式优化了整个方法。如果你有一个这样的繁忙循环,那么后面的循环会显得更慢,因为它们没有运行并且优化很差。

      【讨论】:

      • 问题是关于“确切的 CPU 时间花费”,这个答案是关于挂钟时间的流逝,如 Joachim Sauer 的回答所详述。当然,如果关注的是挂钟时间,这个有很好的提示。
      • 如上所述,此答案将包括您的线程暂停的任何时间,例如在 GC 期间,因此不是进行相对性能比较的好方法,也不回答指定 CPU 时间的问题.
      • 这是否意味着 JIT 将编译该方法 10,000 次?之后它将不再这样做,所以它会更快?谢谢
      【解决方案5】:

      进行微基准测试的正确方法是了解并正确使用 Java micobenchmark harness (JMH),从 OpenJDK 12 开始,JEP 230 Microbenchmark Suite 对其进行了扩充。搜索“java jmh”将产生一些有用教程的链接。我喜欢Jakob Jenkov's blog post,当然还有Aleksey Shipilëv 的任何东西,他是JMH 的主要开发者和维护者。只需在提供的链接上选择他的 JMH 演讲的最新版本即可。

      Java 基准测试非常重要,而且测试代码所做的工作越少,兔子洞就越深。在试图控制性能问题时,时间戳可能会非常具有误导性。时间戳确实起作用的一个地方是当您尝试测量外部事件的等待时间(例如等待对 HTTP 请求的回复和此类事情)时,只要您可以确保在两个事件之间花费的时间可以忽略不计解除等待线程的阻塞并采用“之后”时间戳,并且只要线程首先被适当地解除阻塞。这通常是当且仅当等待至少在几十毫秒的数量级时才会出现这种情况。如果您等待,那很好。尽管如此,热身和缓存效应仍会发生,并随时破坏测量结果对实际性能的适用性。

      就测量“准确的 CPU 时间”而言,可以采用 Joachim Sauer 的回答中详述的方法。使用 JMH 时,可以从外部测量 CPU 使用率,然后根据测量的迭代次数进行平均,但是由于这将包括线束的开销,这种方法适用于比较测量,但不适合导出“我的函数 xy,平均,在我使用的 CPU 架构上每次迭代都会花费如此多的 CPU 秒数。”。在现代 CPU 和 JVM 上,这样的观察几乎是不可能的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-01-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-19
        • 2023-03-22
        • 1970-01-01
        相关资源
        最近更新 更多