Java性能测试
我想对 Java 应用程序进行一些计时测试。 这就是我目前正在做的事情:
long startTime = System.currentTimeMillis();
doSomething();
long finishTime = System.currentTimeMillis();
System.out.println("That took: " + (finishTime - startTime) + " ms");
像这样的性能测试有什么“错误”吗? 有什么更好的办法呢?
重复:秒表基准测试可以接受吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
该方法的一个缺陷是执行 doSomething() 所需的“实时”时间可能会根据系统上正在运行的其他程序及其负载的不同而有很大差异。 这使得性能测量有些不精确。
假设代码是单线程的,跟踪执行代码所需时间的一种更准确的方法是查看线程在调用期间消耗的 CPU 时间。 您可以使用 JMX 类来做到这一点; 特别是使用
ThreadMXBean
。 您可以从 ThreadMXBean 的实例“nofollow noreferrer”>java.lang.management.ManagementFactory
,如果您的平台支持(大多数),请使用getCurrentThreadCpuTime
方法代替System.currentTimeMillis
进行类似的测试。 请记住,getCurrentThreadCpuTime
报告的时间以纳秒为单位,而不是毫秒。下面是一个可用于执行测量的示例 (Scala) 方法:(
请随意将上述内容转换为 Java!)
此策略并不完美,但它不太受系统负载变化的影响。
The one flaw in that approach is that the "real" time
doSomething()
takes to execute can vary wildly depending on what other programs are running on the system and what its load is. This makes the performance measurement somewhat imprecise.One more accurate way of tracking the time it takes to execute code, assuming the code is single-threaded, is to look at the CPU time consumed by the thread during the call. You can do this with the JMX classes; in particular, with
ThreadMXBean
. You can retrieve an instance ofThreadMXBean
fromjava.lang.management.ManagementFactory
, and, if your platform supports it (most do), use thegetCurrentThreadCpuTime
method in place ofSystem.currentTimeMillis
to do a similar test. Bear in mind thatgetCurrentThreadCpuTime
reports time in nanoseconds, not milliseconds.Here's a sample (Scala) method that could be used to perform a measurement:
(Feel free to translate the above to Java!)
This strategy isn't perfect, but it's less subject to variations in system load.
问题中显示的代码不是一个好的性能测量代码:
编译器可能会选择通过重新排序语句来优化您的代码。 是的,它可以做到这一点。 这意味着您的整个测试可能会失败。 它甚至可以选择内联被测方法,并将测量语句重新排序到现在内联的代码中。
热点可能会选择重新排序您的语句、内联代码、缓存结果、延迟执行...
即使假设编译器/热点没有欺骗您,您测量的也是“挂机时间”。 您应该测量的是 CPU 时间(除非您使用操作系统资源并且也希望包括这些资源,或者您在多线程环境中测量锁竞争)。
解决方案? 使用真正的分析器。 周围有很多,包括免费的分析器和商业广告强度的演示/限时试用。
The code shown in the question is not a good performance measuring code:
The compiler might choose to optimize your code by reordering statements. Yes, it can do that. That means your entire test might fail. It can even choose to inline the method under test and reorder the measuring statements into the now-inlined code.
The hotspot might choose to reorder your statements, inline code, cache results, delay execution...
Even assuming the compiler/hotspot didn't trick you, what you measure is "wall time". What you should be measuring is CPU time (unless you use OS resources and want to include these as well or you measure lock contestation in a multi-threaded environment).
The solution? Use a real profiler. There are plenty around, both free profilers and demos / time-locked trials of commercials strength ones.
使用 Java Profiler 是最好的选择,它将为您提供对代码所需的所有洞察。 即响应时间、线程调用跟踪、内存利用率等
我建议您JENSOR,一个开源 Java Profiler,易于使用并且不会占用 CPU 资源。 您可以下载它、检测代码并获取有关代码所需的所有信息。
您可以从以下位置下载:http://jensor.sourceforge.net/
Using a Java Profiler is the best option and it will give you all the insight that you need into the code. viz Response Times, Thread CallTraces, Memory Utilisations, etc
I will suggest you JENSOR, an open source Java Profiler, for its ease-of-use and no overheads on CPU. You can download it, instrument the code and will get all the info you need about your code.
You can download it from: http://jensor.sourceforge.net/
请记住,
System.currentTimeMillis()
的分辨率因不同操作系统而异。 我相信 Windows 大约是 15 毫秒。 因此,如果您的doSomething()
运行速度快于时间分辨率,您将得到 0 的增量。您可以在循环中多次运行doSomething()
,但随后JVM 可能会对其进行优化。Keep in mind that the resolution of
System.currentTimeMillis()
varies between different operating systems. I believe Windows is around 15 msec. So if yourdoSomething()
runs faster than the time resolution, you'll get a delta of 0. You could rundoSomething()
in a loop multiple times, but then the JVM may optimize it.您是否看过 netbeans 和 netbeans 中的分析工具。 net/index_profiler.html" rel="nofollow noreferrer">eclipse。 这些工具可以让您更好地掌握代码中真正占用时间的内容。 通过使用这些工具,我发现了一些我没有意识到的问题。
Have you looked at the profiling tools in netbeans and eclipse. These tools give you a better handle on what is REALLY taking up all the time in your code. I have found problems that I did not realize by using these tools.
嗯,这只是性能测试的一部分。 根据您正在测试的内容,您可能需要查看堆大小、线程数、网络流量或一大堆其他内容。 否则,我将这种技术用于简单的事情,我只想看看它们需要多长时间才能运行。
Well that is just one part of performance testing. Depending on the thing you are testing you may have to look at heap size, thread count, network traffic or a whole host of other things. Otherwise I use that technique for simple things that I just want to see how long they take to run.
当您将一种实现与另一种实现进行比较或尝试在代码中查找速度较慢的部分时(尽管这可能很乏味),这很好。 这是一项非常值得了解的技术,您可能会比其他任何技术都更频繁地使用它,但也要熟悉分析工具。
That's good when you are comparing one implementation to another or trying to find a slow part in your code (although it can be tedious). It's a really good technique to know and you'll probably use it more than any other, but be familiar with a profiling tool as well.
我想您也想在开始计时之前执行 doSomething() ,以便代码被即时编译并“预热”。
I'd imagine you'd want to doSomething() before you start timing too, so that the code is JITted and "warmed up".
Japex 可能对您有用,既可以作为快速创建基准的方法,也可以作为研究基准的方法Java中的问题可以通过源代码来解决。
Japex may be useful to you, either as a way to quickly create benchmarks, or as a way to study benchmarking issues in Java through the source code.