56

跟踪任务在 gradle 构建脚本中花费多长时间的执行时间的最优雅方法是什么?在最佳情况下,将时间直接记录到任务名称的同一行或下一行:

:buildSrc:testClasses (0.518 secs)
:fooBar (28.652 secs)
4

9 回答 9

97

只是为了详细说明Peter Niederwieser 的回答:我们想做同样的事情,以及在构建结束时报告时间,所以缓慢的步骤是显而易见的(当他们放慢速度时,适当的各方会感到一点点但健康的耻辱构建!)。

BUILD SUCCESSFUL

Total time: 1 mins 37.973 secs
Task timings:
    579ms  :myproject-foo:clean
  15184ms  :myproject-bar:clean
   2839ms  :myproject-bar:compileJava
  10157ms  :myproject-bar:jar
    456ms  :myproject-foo:compileJava
    391ms  :myproject-foo:libs
    101ms  :myproject-foo:jar
    316ms  :myproject-bar:compileTestJava
    364ms  :myproject-foo:compileTestJava
  53353ms  :myproject-foo:test
   2146ms  :myproject-bar:test
   8348ms  :www/node:npmInstall
    687ms  :www/node:npmTest

可以将类似下面的代码放入顶层build.gradle以报告执行期间或完成后的时间。

// Log timings per task.
class TimingsListener implements TaskExecutionListener, BuildListener {
    private Clock clock
    private timings = []

    @Override
    void beforeExecute(Task task) {
        clock = new org.gradle.util.Clock()
    }

    @Override
    void afterExecute(Task task, TaskState taskState) {
        def ms = clock.timeInMs
        timings.add([ms, task.path])
        task.project.logger.warn "${task.path} took ${ms}ms"
    }

    @Override
    void buildFinished(BuildResult result) {
        println "Task timings:"
        for (timing in timings) {
            if (timing[0] >= 50) {
                printf "%7sms  %s\n", timing
            }
        }
    }

    @Override
    void buildStarted(Gradle gradle) {}

    @Override
    void projectsEvaluated(Gradle gradle) {}

    @Override
    void projectsLoaded(Gradle gradle) {}

    @Override
    void settingsEvaluated(Settings settings) {}
}

gradle.addListener new TimingsListener()
于 2013-10-17T22:47:15.043 回答
26

这是jlevy 答案的变体,它已被修改以删除已弃用的可公开访问的 gradleClock类的使用。

BUILD SUCCESSFUL

Total time: 1 mins 37.973 secs
Task timings:
    579ms  :myproject-foo:clean
  15184ms  :myproject-bar:clean
   2839ms  :myproject-bar:compileJava
  10157ms  :myproject-bar:jar
    456ms  :myproject-foo:compileJava
    391ms  :myproject-foo:libs
    101ms  :myproject-foo:jar
    316ms  :myproject-bar:compileTestJava
    364ms  :myproject-foo:compileTestJava
  53353ms  :myproject-foo:test
   2146ms  :myproject-bar:test
   8348ms  :www/node:npmInstall
    687ms  :www/node:npmTest

可以将类似下面的代码放入顶层build.gradle以报告执行期间或完成后的时间。

import java.util.concurrent.TimeUnit
// Log timings per task.
class TimingsListener implements TaskExecutionListener, BuildListener {
    private long startTime
    private timings = []

    @Override
    void beforeExecute(Task task) {
        startTime = System.nanoTime()
    }

    @Override
    void afterExecute(Task task, TaskState taskState) {
        def ms = TimeUnit.MILLISECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS);
        timings.add([ms, task.path])
        task.project.logger.warn "${task.path} took ${ms}ms"
    }

    @Override
    void buildFinished(BuildResult result) {
        println "Task timings:"
        for (timing in timings) {
            if (timing[0] >= 50) {
                printf "%7sms  %s\n", timing
            }
        }
    }

    @Override
    void projectsEvaluated(Gradle gradle) {}

    @Override
    void projectsLoaded(Gradle gradle) {}

    @Override
    void settingsEvaluated(Settings settings) {}
}

gradle.addListener new TimingsListener()
于 2017-03-14T18:02:46.443 回答
22

最干净的解决方案是实现一个TaskExecutionListener(我相信你可以处理那部分)并将其注册到gradle.taskGraph.addTaskExecutionListener.

于 2012-10-23T13:54:04.733 回答
22

我知道这是一个老问题,但我找到了一个很酷的插件来执行任务计时。这就像@jlevy 的答案,但有更多可用选项:https ://github.com/passy/build-time-tracker-plugin

Pascal Hartig 的这个插件持续记录你的构建时间并提供 CSV 和条形图摘要。开发人员建议使用它来监控您的构建时间,而不是--profile为您提供当前构建的快照。

这就是我目前使用它的方式:

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath "net.rdrei.android.buildtimetracker:gradle-plugin:0.7.+"
    }
}

apply plugin: "build-time-tracker"

buildtimetracker {
    reporters {
        summary {
            ordered false
            threshold 50
            barstyle 'unicode'
        }
    }
}
于 2015-10-06T21:09:00.713 回答
4

我创建了一个插件,因为passy/build-time-tracker-plugin不再被积极维护。我的也打印 ASCII 条形图,并带有自定义选项。

https://github.com/asarkar/build-time-tracker

== Build time summary ==
 :commons:extractIncludeProto | 4.000s | 14% | ████
       :commons:compileKotlin | 2.000s |  7% | ██
         :commons:compileJava | 6.000s | 21% | ██████
:service-client:compileKotlin | 1.000s |  4% | █
        :webapp:compileKotlin | 1.000s |  4% | █
     :webapp:dockerBuildImage | 4.000s | 14% | ████
      :webapp:dockerPushImage | 4.000s | 14% | ████
于 2020-07-23T09:35:35.547 回答
2

简单的排序将使@jlevy 的解决方案更好。
另外,对于典型的生产应用程序,我认为 50ms 的阈值太低了。
我们通常关心耗时超过 X 秒的任务。
项目/build.gradle

import java.util.concurrent.TimeUnit

// Log timings per task.
class TimingsListener implements TaskExecutionListener, BuildListener {
    private long startTime
    private timings = []

    @Override
    void beforeExecute(Task task) {
        startTime = System.nanoTime()
    }

    @Override
    void afterExecute(Task task, TaskState taskState) {
        def ms = TimeUnit.MILLISECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS)
        timings.add(new Tuple2<Integer, String>(ms, task.path))
        task.project.logger.warn "${task.path} took ${ms}ms"
    }

    @Override
    void buildFinished(BuildResult result) {
        println "Task timings:"
        def tmp = timings.toSorted(new Comparator<Tuple2<Integer, String>>() {
            @Override
            int compare(Tuple2<Integer, String> o, Tuple2<Integer, String> t1) {
                return o.first - t1.first
            }
        })
        for (timing in tmp) {
            if (timing.first >= 1000) {
                printf "%ss  %s\n", timing.first / 1000, timing.second
            }
        }
    }

    @Override
    void buildStarted(Gradle gradle) {}

    @Override
    void projectsEvaluated(Gradle gradle) {}

    @Override
    void projectsLoaded(Gradle gradle) {}

    @Override
    void settingsEvaluated(Settings settings) {}
}

gradle.addListener new TimingsListener()

终端输出:

BUILD SUCCESSFUL in 14m 33s
948 actionable tasks: 419 executed, 476 from cache, 53 up-to-date
Task timings:
1.036s  :cbl-config:mergeMyAppDebugResources
1.187s  :express:bundleMyAppDebug
1.199s  :country:testMyAppDebugUnitTest
1.214s  :core-for-test:extractMyAppDebugAnnotations
1.242s  :analytics:testMyAppDebugUnitTest
1.308s  :express:extractMyAppDebugAnnotations
1.33s  :availability:dataBindingExportBuildInfoMyAppDebug
1.357s  :app:transformNativeLibsWithStripDebugSymbolForMyAppDebug
1.405s  :hermes:generateMyAppDebugBuildConfig
1.56s  :availability:testMyAppDebugUnitTest
1.65s  :app:javaPreCompileMyAppDebugUnitTest
1.749s  :chat:compileMyAppDebugJavaWithJavac
1.858s  :cbl-config-for-test:compileMyAppDebugJavaWithJavac
2.027s  :cbl-config:compileMyAppDebugJavaWithJavac
2.056s  :analytics-for-test:compileMyAppDebugJavaWithJavac
2.447s  :crypto:compileMyAppDebugJavaWithJavac
2.45s  :crypto:testMyAppDebugUnitTest
2.47s  :chat:javaPreCompileMyAppDebugUnitTest
2.639s  :crypto-for-test:dataBindingExportBuildInfoMyAppDebug
2.683s  :test-utils:compileMyAppDebugJavaWithJavac
3.056s  :crypto:lintMyAppDebug
3.227s  :app:transformNativeLibsWithMergeJniLibsForMyAppDebug
3.272s  :express:testMyAppDebugUnitTest
3.394s  :crypto:mergeMyAppDebugResources
3.426s  :core:testMyAppDebugUnitTest
4.299s  :multicity:testMyAppDebugUnitTest
4.333s  :app:packageMyAppDebug
4.584s  :availability-for-test:compileMyAppDebugJavaWithJavac
4.672s  :app:transformResourcesWithMergeJavaResForMyAppDebug
4.786s  :map:lintMyAppDebug
5.309s  :country:lintMyAppDebug
5.332s  :job:lintMyAppDebug
5.389s  :map:testMyAppDebugUnitTest
6.04s  :express:lintMyAppDebug
6.584s  :hermes:lintMyAppDebug
6.707s  :app:transformClassesWithMultidexlistForMyAppDebug
7.052s  :multicity:lintMyAppDebug
8.044s  :multicity:compileMyAppDebugJavaWithJavac
8.87s  :app:transformDexArchiveWithDexMergerForMyAppDebug
9.371s  :uikit:testMyAppDebugUnitTest
9.429s  :availability:lintMyAppDebug
13.12s  :app:compileMyAppDebugUnitTestKotlin
16.276s  :hermes:testMyAppDebugUnitTest
16.898s  :chat:testMyAppDebugUnitTest
17.174s  :job:testMyAppDebugUnitTest
36.008s  :aaefawef:testMyAppDebugUnitTest
96.88s  :app:compileMyAppDebugJavaWithJavac
125.693s  :app:lintMyAppDebug
145.538s  :app:transformClassesWithDexBuilderForMyAppDebug
182.752s  :app:testMyAppDebugUnitTest
于 2018-05-29T02:53:13.673 回答
1

--profile标志将生成一个配置文件报告。生成的 HTML 文件包括一个“任务执行”选项卡,其中包含每个任务的计时。

$ gradle build --profile

BUILD SUCCESSFUL in 21s
6 actionable tasks: 6 executed

See the profiling report at: file:///path/to/gs-spring-boot/complete/build/reports/profile/profile-2021-08-09-16-22-40.html
A fine-grained performance profile is available: use the --scan option.

这记录在在线命令行界面文档中

$buildDir/reports/profile在目录中生成高级性能报告。--scan是首选。

任务执行输出

任务 期间 结果
20.046s (全部的)
:编译Java 9.221s
:测试 6.492s
:compileTestJava 3.161s
:bootJarMainClassName 0.813s
:bootJar 0.338s
:罐 0.017s
:进程资源 0.003s 无源
:类 0.001s 没有工作
:集合 0s 没有工作
:建造 0s 没有工作
:查看 0s 没有工作
:processTestResources 0s 无源
:testClasses 0s 没有工作

Gradle 构建扫描

--profile选项及其文档都建议使用该--scan选项来生成构建扫描。这会生成一个扫描并将其发布到scans.gradle.com。除了将您的构建详细信息传输到 Gradle 构建扫描外部服务之外,这还需要接受Gradle 服务条款

$ gradle build --scan

BUILD SUCCESSFUL in 0s
7 actionable tasks: 7 executed

Publishing a build scan to scans.gradle.com requires accepting the Gradle Terms of Service defined at https://gradle.com/terms-of-service.
Do you accept these terms? [yes, no] yes

Gradle Terms of Service accepted.

Publishing build scan...
https://gradle.com/s/5u4w3gxeurtd2

扫描输出

4个项目61个任务7s执行,10个回避任务节省4.231s

:buildSrc:compileKotlin 3.584s
:app:test 0.745s
:列表:测试 0.742s
:list:compileJava 0.062s
:utilities:compileJava 0.054s
:app:startScripts 0.049s
于 2021-08-09T21:58:55.173 回答
0

我曾尝试使用@Jilevys 解决方案,但在查找类org.gradle.util.Clock()时出错

我已将其修改为使用 Java8 类。将以下代码放在 build.gradle 之上

    import java.time.LocalDateTime

class TimingsListener implements TaskExecutionListener, BuildListener {
    private LocalDateTime taskStartTime

    @Override
    void beforeExecute(Task task) {
        taskStartTime = LocalDateTime.now();
    }

    @Override
    void afterExecute(Task task, TaskState taskState) {
        LocalDateTime taskEndTime = LocalDateTime.now();
        def seconds = Duration.between(taskStartTime, taskEndTime).toSeconds();
        task.project.logger.warn "${task.path} took ${seconds} seconds."
    }

    @Override
    void buildStarted(Gradle gradle) {
        project.logger.warn "Build started on "+LocalDateTime.now()
    }

    @Override
    void settingsEvaluated(Settings settings) {

    }

    @Override
    void projectsLoaded(Gradle gradle) {

    }

    @Override
    void projectsEvaluated(Gradle gradle) {

    }

    @Override
    void buildFinished(BuildResult result) {
        project.logger.warn "Build finished on "+LocalDateTime.now()

    }
}
gradle.addListener new TimingsListener()

它产生类似于下面给出的输出。

<projectname>:<taskName> took 10 seconds.
于 2020-12-15T12:22:30.767 回答
-1

在 Android Studio 版本 >= 4.0 中添加了构建分析器,它在 gradle 中跟踪每个任务的执行时间。

成功构建后在这里找到:

  1. 在此处输入图像描述

  2. 在此处输入图像描述

于 2020-08-18T12:36:05.027 回答