如何准确测量Java方法的运行时间?

时间:2014-03-24 16:37:51

标签: java time

我必须报告java方法的平均运行时间。我是按照以下方式做的

//method start
long startTime = System.nanoTime();
//method body here ...
long estimationTime = System.nanoTime() - startTime; 
//method end

我多次运行该方法,记录结果,然后以微秒为单位报告运行时间的均值和方差。

这是问题我得到了以下值(存在非常大的峰值) enter image description here

请注意,其他值不是零(放大显示它) enter image description here

我的问题:

  1. 这些异常值(尖峰)的主要原因是什么?
  2. 如何在这种情况下准确报告运行时间?
  3. 看一下方法体(对于好奇的)

    TraceRecord resultRecord = new TraceRecord();
        resultRecord.setTimeStamp(timeStamp);
        resultRecord.setUserID(userID);
    
        if (sensorValue.getSensorType() == SensorType.WIFI) {
            ArrayList<WifiBaseStation> wifiAPsInRange = new ArrayList<WifiBaseStation>();
    
            for (int i = 0; i < sensorValue.getBaseStationsIdentifiers().length; i++) {
    
                WifiBaseStation wifiAP = new WifiBaseStation(sensorValue.getRepresentativeName(i),
                        sensorValue.getBaseStationsIdentifier(i));
                wifiAP.getSignalStrengthsList().add(sensorValue.getSignalValue(i));
                wifiAPsInRange.add(wifiAP);
            }
            if (wifiAPsInRange.size() > 0) {
    
                double averageLong = 0;
                double averageLat = 0;
                int matchedCount = 0;
    
                for (WifiBaseStation bs : wifiAPsInRange) {
                    WifiBaseStation bsFromTable = WiFiUniqueWarDrivingTable.Get(bs.getMacAddress());
                    if (bsFromTable != null) {
                        GPSLocation locationFromTable = bsFromTable.getBaseStationLocationUsingAverage();
                        if (locationFromTable != null) {
                            averageLong += locationFromTable.getLongitude();
                            averageLat += locationFromTable.getLatitude();
                            matchedCount++;
                        }else{
                            averageLong++;
                            averageLong--;
                        }
                    }else{
                        averageLong++;
                        averageLong--;
                    }
    
                }
    
                if (averageLong != 0) {
                    averageLong /= matchedCount;
                }
                if (averageLat != 0) {
                    averageLat /= matchedCount;
                }
    
                if (averageLat != 0 && averageLong != 0) {
                    resultRecord.setLocationPoint(new GPSLocation(averageLong, averageLat, 0));
                } else {
                    return null;
                }
            }
    
        }
    

4 个答案:

答案 0 :(得分:0)

这些峰值最有可能的原因是“停止世界”#34;由GC引起的休息。你无法阻止这种情况的发生。最好的尝试是在进行第一次测量之前调用System.gc()一次。

答案 1 :(得分:0)

您需要在这些时间跟踪程序正在执行的操作。例如,您的代码中有一些行可以调用另一个服务(可能不受您控制)。您还需要对此服务进行分析。

您可以通过自己添加大量此时控制测量值,或使用 jVisualVM 新Relic 等配置文件工具来完成此操作。

最后一个,您可以在在线平台上分析图形并接收反馈。

分析完所有数据后,您可以开始更改程序中的某些功能,甚至可以在必要时更新JVM中的功能。例如,如果问题与完整GC 过程有关,则可以更改JVM在启动时使用的GC 算法

答案 2 :(得分:0)

对于非常快速的操作,有很大的机会&#34;某些事情&#34;发生。它可以是GC,它可以是另一个处理时间的过程(就像你的antivir决定立即检查一些东西)。

但是有一个简单的解决方案。如果你想知道&#34; true&#34;处理时间,您只需要多次运行方法体并计算平均时间。它确保即使&#34;东西&#34;碰巧,它对你的结果影响很小。

这是一个非常简单的例子:

    int count = 0;
    long start = System.nanoTime();
    for (int i = 0; i < 1000000; i++) {
        count++;
    }
    long end = System.nanoTime();
    long totalTime = end - start;
    System.out.println("Incrementing int variable cost you + " + (totalTime/(double) 1000000) + " nanoseconds");

您可以尝试运行此功能,如您所见,如果您反复运行它,则totalTime几乎相同。

答案 3 :(得分:0)

尝试测量微秒范围内的时间跨度很难(或几乎不可能)。 System.nanoTime()调用中使用的计时器的分辨率是有限的,取决于操作系统(可以轻松找到更多详细信息,例如System.currentTimeMillis vs System.nanoTime

此外,可能存在任意干扰,包括绑定到JVM的那些(即垃圾收集运行),而不是用户生成的干扰(您在程序中的其他位置运行的一些其他线程) ,对于“外部”的,如你的邮件客户端弹出“你有邮件”窗口,或者是在无聊的,无聊的基准测试运行期间由后台运行的MP3播放器引起的延迟; )

分析器显然是识别复杂系统瓶颈的首选。在这种情况下,分析器可能有助于“缩放”到方法中:从此方法完成的任何方法调用都可能是“尖峰”的原因。例如,像sensorValue.getSignalValue(i)bs.getMacAddress()之类的调用可以通过本机库进行一些奇怪的硬件中断访问...或者可能在后台随机启动“MineSweeper”,谁知道。

一个有趣的问题也是你真正想要衡量的。鉴于这个问题,它可能听起来很幼稚,但是:为什么尖峰很重要? spike本身真的是一个问题,还是只是一个吸引你好奇心的神器?我无法想象这种方法对100次调用的执行时间是100x1ms还是99x1ms + 1x2ms是否与实践相关。如果这是用于某种“微基准测试”,你至少应该计算超过100次调用的平均时间(并且最好使用微基准测试框架)。