在Android中测量执行时间的最佳方法是什么?

51

什么是测量Android代码段执行时间的最佳方法?

我有一段代码,在其中我想放置时间戳以查找它的执行时间(例如在活动的onCreate()onDestroy()方法中)。

我尝试过Time.toMillies(false),但它只返回给我秒数(以常量末尾的000)。我还尝试了两个java函数:System.currentTimeMillis()System.nanoTime()。 第一个返回历元时间的毫秒数,第二个不返回。

什么是测量执行时间和获得良好精度的最佳方式?

7个回答

99

那么TimingLogger怎么样呢?

根据TimingLogger的文档:

TimingLogger timings = new TimingLogger(YOUR_TAG, "methodA");
// ... do some work A ... 
timings.addSplit("work A");
// ... do some work B ... 
timings.addSplit("work B");
// ... do some work C ... 
timings.addSplit("work C");
timings.dumpToLog();

转储将如下所示:

     D/TAG     (3459): methodA: begin
     D/TAG     (3459): methodA:      9 ms, work A
     D/TAG     (3459): methodA:      1 ms, work B
     D/TAG     (3459): methodA:      6 ms, work C
     D/TAG     (3459): methodA: end, 16 ms

不要忘记通过运行以下命令启用您的标签:adb shell setprop log.tag.YOUR_TAG VERBOSE


1
谢谢你提供setprop的提示。我不明白为什么dumpToLog()使用Log.d()时需要VERBOSE,但显然是必要的。 - LarsH
1
YOUR_TAG in the example should be whatever string you used to initialize the TimingLogger. Example: new TimingLogger("MyApp", "methodA"); use adb shell setprop log.tag.MyApp VERBOSE - friederbluemle
3
VERBOSEзә§еҲ«зҡ„ж—Ҙеҝ—жҳҜеҝ…иҰҒзҡ„пјҢеӣ дёәеҪ“еҲқе§ӢеҢ–TimingLoggerж—¶пјҢreset()ж–№жі•еҸӘжңүеңЁLog.isLoggable(mTag, Log.VERBOSE)зҡ„иҝ”еӣһеҖјдёәtrueж—¶жүҚдјҡеҗҜз”Ёж—Ҙеҝ—и®°еҪ•еҷЁгҖӮ - friederbluemle
3
我的技巧是克隆TimingLogger类,并使其不检查VERBOSE。这可能有所帮助。 - ปรีดา ตั้งนภากร
4
占卜师TimingLogger自API级别30开始已被“弃用”。 - Muhammad Saqib
显示剩余5条评论

27
以下是翻译内容:

什么是衡量执行时间的最佳方式?

System.nanoTime()可能是一个不错的选择。例如,Jake Wharton在Hugo中使用它。

如何获得良好的精度?

这是不严格可能的,因为在您的方法执行时设备上可能会发生任何事情。这些外部因素将影响您的时间测量,通过夺取CPU时间、占用I/O通道等方式。您需要在几次运行中平均测试结果以尝试平均掉这些外部因素,并且由此准确性/精度将会受到影响。

正如Marcin Orlowski所指出的那样,要实际确定您消耗某些时间的原因,请使用Traceview。


5
技术上只有“准确性”受到影响,精度始终为纳秒。 - Wyck

19

Kotlin 开发者

要获取以毫秒为单位的经过时间:

val elapsedTime= measureTimeMillis {
            // call you method from here or add any other statements
} 

获取纳秒时间:

val elapsedTime= measureNanoTime {
            // call you method from here or add any other statements
}

11

我通常使用System.nanoTime()来进行快速的测量。

一个简单的设置就像这样

   val startTime =   System.nanoTime()

    //DO SOMETHING

   Log.e("Measure", TASK took : " +  ((System.nanoTime()-startTime)/1000000)+ "mS\n")

8

1
完全同意,尽管在分析模式下应用程序会变慢,但线程、方法和所花费时间百分比的信息是值得的。 否则,我会说System.currentTimeMillis()是他想要的。 - shalafi

0
除了以上的答案之外,还有一个名为Snippet的库可以用来测量执行时间。它还负责记录和将所有相关的执行内容放在日志中。它还负责测量非连续的代码段,这些代码段可能跨越多个方法甚至文件。下面是它如何处理连续的代码。我们也可以在一个测量中添加分割点。
@Override  
protected void onCreate(@Nullable Bundle savedInstanceState) {  
    // The capture API can be used to measure the code that can be passed as a lambda.  
    // Adding this lambda captures the class, line, thread etc automatically into the logcat.
    // This cannot be use for code that returns a value as the lambda declared for closure is 
    // is a non returning lambda. For the case that could return a value and are a little complex // use the log-token based API demonstrated below.  
    
    // Captures the code as a lambda.  
    Snippet.capture(()-> super.onCreate(savedInstanceState)); 
}

在发布版本中,该代码也将成为无操作。

要配置它,只需尽早在应用程序 onCreate() 中添加以下代码即可。

if(BuildConfig.DEBUG) {             
        Snippet.install(new Snippet.MeasuredExecutionPath());      
        Snippet.newFilter("SampleFilter");      
        Snippet.addFlag(Snippet.FLAG_METADATA_LINE | Snippet.FLAG_METADATA_THREAD_INFO);      
} 

https://github.com/microsoft/snippet-timekeeper


0

为那些使用 Kotlin 开发 Android 应用程序的人提供答案;同时,这也是在搜索中作为第一个主要结果出现的关于 Kotlin 在 Android 中代码性能的唯一答案。

这个线程上已经有一个简单的 Kotlin 答案来测量毫秒和纳秒级别的性能 - 但我的解决方案将帮助那些想要在执行完成后同时记录和执行函数的人,当涉及到不同函数的多个性能测量时,这也是一种更清晰的方法。

创建以下函数:

//the inline performance measurement method
private inline fun <T> measurePerformanceInMS(
        logger: (Long) -> Unit,
        function: () -> T)
: T {
    val startTime = System.currentTimeMillis()
    val result: T = function.invoke()
    val endTime = System.currentTimeMillis()
    logger.invoke( endTime - startTime)
    return result
}

//the logger function
fun logPerf(time: Long){
    Log.d("TAG","PERFORMANCE IN MS: $time ms ")
}

//the function whose performance needs to be checked
fun longRunningFunction() : Int{
    var x = 0
    for (i in 1..20000) x++
    return x
}

通过这种方式,您可以在单个函数调用下保持日志记录、性能计算和函数执行,并且无需复制代码。

如果您需要纳秒级别的测量,则使用System.nanoTime()

用法

val endResult = measurePerformanceInMS({time -> logPerf(time)}){
            longRunningFunction()
        }

注意:这里的'endResult'将携带被测量函数的结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接