【问题标题】:Is there a way to track java compilation time by class?有没有办法按类跟踪java编译时间?
【发布时间】:2018-01-04 19:39:51
【问题描述】:

我为一个包含多个 java gradle 模块的项目做出贡献。其中两个最近被合并,大大增加了编译时间。我读过使用推断的泛型和重载方法会增加编译时间。

是否有任何工具可以帮助查找 Java 中编译时间慢的类?还是指出潜在速度缺陷的 linter?

【问题讨论】:

  • 我会使用增量构建,这样编译时间就不那么重要了,即只有更改的类会被重新编译。

标签: java performance compilation


【解决方案1】:

我一直在寻找一种方法来做同样的事情,并且不得不想出我自己的方法,我将在下面描述。

首先,请注意,当您使用 javac 编译类时,您可以传递 -verbose 标志,以便编译器记录正在发生的所有事情(它将输出发送到 stderr)。

在 Gradle 中,您可以将该选项传递给编译器,如下所示:

compileJava {
    options.verbose = true
}

对于我的 hello world 类来说,这看起来像这样(隐藏了很多不相关的东西):

[parsing started SimpleFileObject[/Users/renato/programming/experiments/java/Main.java]]
[parsing completed 21ms]
[loading /modules/jdk.jsobject/module-info.class]
[loading /modules/jdk.management/module-info.class]

...

[checking Main]
[loading /modules/java.base/java/io/Serializable.class]
[loading /modules/java.base/java/lang/AutoCloseable.class]
[loading /modules/java.base/java/lang/Class.class]
[loading /modules/java.base/java/lang/System.class]
[loading /modules/java.base/java/io/PrintStream.class]
[loading /modules/java.base/java/lang/Appendable.class]
[loading /modules/java.base/java/io/Closeable.class]
[loading /modules/java.base/java/io/FilterOutputStream.class]
[loading /modules/java.base/java/io/OutputStream.class]
[loading /modules/java.base/java/io/Flushable.class]
[wrote Main.class]
[total 229ms]

如您所见,您可以捕获 stderr,然后计算 parsing started ...Main.javawrote Main.class 之间的时间。

如果您跟踪每个源文件和等效类文件的消息,您应该能够获得有关编译每个类所用时间的准确信息。

不幸的是,我认为 Gradle 不允许我们使用 Java 编译器的输出,因此我们需要使用其他东西来为我们运行 Gradle 并解析该输出。

这是一个使用 Groovy 脚本执行此操作的示例(即使在 Windows 中,您也应该进行少量编辑,或者仅使用 javacmvn 进行编译):

def projectDir = new File(System.getProperty('user.home') + '/programming/experiments/gradle')
def javaSourcesRoot = new File(projectDir, 'src/main/java').absolutePath
def classFilesRoot = new File(projectDir, 'build/classes/java/main').absolutePath
def sourcesPrefix = "[parsing started SimpleFileObject[$javaSourcesRoot/"
def donePrefix = "[wrote $classFilesRoot/"

log "Starting Gradle"
def gradle = ['gradle', 'compileJava'].execute((List) null, projectDir)

def stdout = new StringBuilder()
def stderr = new StringBuilder()


gradle.consumeProcessOutput(stdout, stderr)

assert gradle.waitFor() == 0: "$stdout\n$stderr"

def classInfo = [:]

stderr.eachLine { line ->
    if (line.startsWith(sourcesPrefix)) {
        def className = (line - sourcesPrefix - '.java]]').replaceAll(File.separator, '.')
        log "Started compiling class $className"
        classInfo[className] = [startTime: System.currentTimeMillis()]
    }
    if (line.startsWith(donePrefix)) {
        def className = (line - donePrefix - '.class]').replaceAll('/', '.')
        log "Done compiling class $className"
        classInfo[className].endTime = System.currentTimeMillis()
    }
}

def results = classInfo.collect { String className, Map info ->
    "${className.padRight(20)} ${info.endTime - info.startTime}"
}.join('\n')

log "Results:\n$results"

void log(msg) {
    println "${new Date()} - $msg"
}

我的小示例项目的结果:

Fri Jul 23 16:39:18 CEST 2021 - Starting Gradle
Fri Jul 23 16:39:20 CEST 2021 - Started compiling class other.JavaType
Fri Jul 23 16:39:20 CEST 2021 - Started compiling class my.Main
Fri Jul 23 16:39:20 CEST 2021 - Done compiling class other.JavaType
Fri Jul 23 16:39:20 CEST 2021 - Done compiling class my.Main
Fri Jul 23 16:39:20 CEST 2021 - Results:
other.JavaType       9
my.Main              4

时间以毫秒为单位,所以 my.Main,一个 hello world 类,用了 9 毫秒编译...other.JavaType 是一个空类,用了 4 毫秒。

【讨论】:

    猜你喜欢
    • 2010-12-24
    • 2011-07-04
    • 2011-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-14
    • 1970-01-01
    相关资源
    最近更新 更多