简体   繁体   English

如何计时Java程序执行速度

[英]How to time Java program execution speed

How do you time the execution of a java program?你如何计时 Java 程序的执行时间? I'm not sure what class I should use to do this.我不确定我应该使用什么课程来做到这一点。

I'm kinda looking for something like:我有点在寻找类似的东西:

// Some timer starts here
for (int i = 0; i < length; i++) {
  // Do something
}
// End timer here

System.out.println("Total execution time: " + totalExecutionTime);
final long startTime = System.currentTimeMillis();
for (int i = 0; i < length; i++) {
  // Do something
}
final long endTime = System.currentTimeMillis();

System.out.println("Total execution time: " + (endTime - startTime));

Be aware that there are some issues where System#nanoTime() cannot be reliably used on multi-core CPU's to record elapsed time ... each core has maintains its own TSC ( Time Stamp Counter ): this counter is used to obtain the nano time (really it is the number of ticks since the CPU booted).请注意,存在一些问题,即System#nanoTime()无法在多核 CPU 上可靠地用于记录经过的时间……每个核都有自己的 TSC(时间戳计数器):此计数器用于获取 nano时间(实际上它是自 CPU 启动以来的滴答数)。

Hence, unless the OS does some TSC time warping to keep the cores in sync, then if a thread gets scheduled on one core when the initial time reading is taken, then switched to a different core, the relative time can sporadically appear to jump backwards and forwards.因此,除非操作系统进行一些 TSC 时间扭曲以保持内核同步,否则如果在读取初始时间时将线程安排在一个内核上,然后切换到不同的内核,则相对时间可能会偶尔出现倒退和转发。

I observed this some time ago on AMD/Solaris where elapsed times between two timing points were sometimes coming back as either negative values or unexpectedly large positive numbers.我前段时间在 AMD/Solaris 上观察到了这一点,其中两个时间点之间的经过时间有时会以负值或意外大的正数的形式返回。 There was a Solaris kernel patch and a BIOS setting required to force the AMD PowerNow!需要一个 Solaris 内核补丁和一个 BIOS 设置来强制使用 AMD PowerNow! off, which appeared to solved it.关闭,这似乎解决了它。

Also, there is (AFAIK) a so-far unfixed bug when using java System#nanoTime() in a VirtualBox environment;此外,在 VirtualBox 环境中使用 java System#nanoTime()时,存在 (AFAIK) 迄今为止未修复的错误; causing all sorts of bizarre intermittent threading problems for us as much of the java.util.concurrency package relies on nano time.由于java.util.concurrency包依赖于纳米时间,因此给我们带来了各种奇怪的间歇性线程问题。

See also:也可以看看:

Is System.nanoTime() completely useless? System.nanoTime() 完全没用吗? http://vbox.innotek.de/pipermail/vbox-trac/2010-January/135631.html http://vbox.innotek.de/pipermail/vbox-trac/2010-January/135631.html

You can make use of System#nanoTime() .您可以使用System#nanoTime() Get it before and after the execution and just do the math.在执行之前和之后获取它,然后进行数学计算。 It's preferred above System#currentTimeMillis() because it has a better precision.它比System#currentTimeMillis()System#currentTimeMillis()因为它具有更好的精度。 Depending on the hardware and the platform used, you may otherwise get an incorrect gap in elapsed time.根据所使用的硬件和平台,您可能会在经过的时间出现错误的间隔。 Here with Core2Duo on Windows, between about 0 and ~15ms actually nothing can be calculated.在 Windows 上使用 Core2Duo,在大约 0 到 ~15 毫秒之间实际上无法计算任何内容。

A more advanced tool is a profiler .一个更高级的工具是分析器

You get the current system time, in milliseconds:您获得当前系统时间,以毫秒为单位:

final long startTime = System.currentTimeMillis();

Then you do what you're going to do:然后你做你要做的事情:

for (int i = 0; i < length; i++) {
  // Do something
}

Then you see how long it took:然后你会看到花了多长时间:

final long elapsedTimeMillis = System.currentTimeMillis() - startTime;

Here are a few ways to find the execution time in Java:以下是在 Java 中查找执行时间的几种方法:

1) System.nanoTime() 1) System.nanoTime()

long startTime = System.nanoTime();
.....your code....
long endTime   = System.nanoTime();
long totalTime = endTime - startTime;
System.out.println("Execution time in nanoseconds  : " + totalTime);
System.out.println("Execution time in milliseconds : " + totalTime / 1000000);

2) System.currentTimeMillis() 2) System.currentTimeMillis()

long startTime = System.currentTimeMillis();
.....your code....
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds  : " + totalTime);

3) Instant.now() 3) Instant.now()

long startTime = Instant.now().toEpochMilli();
.....your code....
long endTime = Instant.now().toEpochMilli();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds: " + totalTime);

or或者

Instant start = Instant.now();
.....your code....
Instant end = Instant.now();
Duration interval = Duration.between(start, end);
System.out.println("Execution time in seconds: " +interval.getSeconds());

4) Date.getTime() 4) 日期.getTime()

long startTime = new Date().getTime();
.....your code....
long endTime = new Date().getTime();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds: " + totalTime);

For simple stuff, System.currentTimeMillis() can work.对于简单的东西, System.currentTimeMillis()可以工作。

It's actually so common that my IDE is setup so that upon entering "t0" it generates me the following line:实际上,我的 IDE 设置如此普遍,因此在输入“t0”时,它会生成以下行:

final long t0 = System.currentTimeMillis()

But for more complicated things, you'll probably want to use statistical time measurements, like here (scroll down a bit and look at the time measurements expressed including standard deviations etc.):但是对于更复杂的事情,您可能希望使用统计时间测量,如下所示(向下滚动并查看表示的时间测量,包括标准偏差等):

http://perf4j.codehaus.org/devguide.html http://perf4j.codehaus.org/devguide.html

Using AOP/AspectJ and @Loggable annotation from jcabi-aspects you can do it easy and compact:使用来自jcabi-aspects 的AOP/AspectJ 和@Loggable注释,您可以轻松紧凑地完成:

@Loggable(Loggable.DEBUG)
public String getSomeResult() {
  // return some value
}

Every call to this method will be sent to SLF4J logging facility with DEBUG logging level.对此方法的每次调用都将发送到具有DEBUG日志级别的 SLF4J 日志记录工具。 And every log message will include execution time.每条日志消息都将包含执行时间。

use long startTime=System.currentTimeMillis() for start time, at the top of the loop使用 long startTime=System.currentTimeMillis()作为开始时间,在循环的顶部

put long endTime= System.currentTimeMillis(); put long endTime= System.currentTimeMillis(); outside the end of the loop.在循环结束之外。 You'll have to subtract the values to get the runtime in milliseconds.您必须减去这些值才能获得以毫秒为单位的运行时间。

If you want time in nanoseconds, check out System.nanoTime()如果您想要以纳秒为单位的时间,请查看System.nanoTime()

I created a higher order function which takes the code you want to measure in/as a lambda:我创建了一个高阶函数,它将您要在/作为 lambda 测量的代码:

class Utils {

    public static <T> T timeIt(String msg, Supplier<T> s) {
        long startTime = System.nanoTime();
        T t = s.get();
        long endTime = System.nanoTime();
        System.out.println(msg + ": " + (endTime - startTime) + " ns");
        return t;
    }

    public static void timeIt(String msg, Runnable r) {
       timeIt(msg, () -> {r.run(); return null; });
    }
}

Call it like that:这样称呼它:

Utils.timeIt("code 0", () ->
        System.out.println("Hallo")
);

// in case you need the result of the lambda
int i = Utils.timeIt("code 1", () ->
        5 * 5
);

Output:输出:

code 0: 180528 ns代码 0:180528 纳秒
code 1: 12003 ns代码 1:12003 纳秒

Special thanks to Andy Turner who helped me cut down the redundancy.特别感谢安迪·特纳( Andy Turner) ,他帮助我减少了冗余。 See here .这里

You can use Stopwatch您可以使用秒表

import com.google.common.base.Stopwatch;

Stopwatch timer = Stopwatch.createStarted();
//lines to be executed
System.out.println("Execution time= " + timer.stop());

You may also try Perf4J.您也可以尝试 Perf4J。 Its a neat way of doing what you are looking for, and helps in aggregated performance statistics like mean, minimum, maximum, standard deviation and transactions per second over a set time span.它是做您正在寻找的事情的一种简洁方式,并有助于汇总性能统计数据,例如平均值、最小值、最大值、标准偏差和设定时间跨度内的每秒事务数。 An extract from http://perf4j.codehaus.org/devguide.html :摘自http://perf4j.codehaus.org/devguide.html

StopWatch stopWatch = new LoggingStopWatch();

try {
    // the code block being timed - this is just a dummy example
    long sleepTime = (long)(Math.random() * 1000L);
    Thread.sleep(sleepTime);
    if (sleepTime > 500L) {
        throw new Exception("Throwing exception");
    }

    stopWatch.stop("codeBlock2.success", "Sleep time was < 500 ms");
} catch (Exception e) {
    stopWatch.stop("codeBlock2.failure", "Exception was: " + e);
}

Output:输出:

INFO: start[1230493236109] time[447] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493236719] time[567] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493237286] time[986] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493238273] time[194] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493238467] time[463] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493238930] time[310] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239241] time[610] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493239852] time[84] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239937] time[30] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239968] time[852] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
public class someClass
{
   public static void main(String[] args) // your app start point
   {
       long start = java.util.Calendar.getInstance().getTimeInMillis();

       ... your stuff ...

       long end = java.util.Calendar.getInstance().getTimeInMillis();
       System.out.println("it took this long to complete this stuff: " + (end - start) + "ms");
   }
}

Using System.currentTimeMillis() is the proper way of doing this.使用 System.currentTimeMillis() 是正确的方法。 But, if you use command line, and you want to time the whole program approximately and quickly, think about:但是,如果您使用命令行,并且想要大致快速地对整个程序计时,请考虑:

time java App

which allows you not to modify the code and time your App.这允许您不修改代码和时间您的应用程序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM