melix / jmh-gradle-plugin

Integrates the JMH benchmarking framework with Gradle
Apache License 2.0
666 stars 88 forks source link

Not exiting JVM and keeping a lock on file after benchmarking is over, Windows 10 #134

Closed kmecpp closed 5 years ago

kmecpp commented 6 years ago

Every time I run gradle with gradle jmh, the first time it will run successfully and then the next time it will fail with this exception

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':jmh'.
> A failure occurred while executing me.champeau.gradle.IsolatedRunner
   > ERROR: Unable to find the resource: /META-INF/BenchmarkList

* Try:
Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':jmh'.
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:110)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:77)
    at org.gradle.api.internal.tasks.execution.OutputDirectoryCreatingTaskExecuter.execute(OutputDirectoryCreatingTaskExecuter.java:51)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:59)
    at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:59)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:101)
    at org.gradle.api.internal.tasks.execution.FinalizeInputFilePropertiesTaskExecuter.execute(FinalizeInputFilePropertiesTaskExecuter.java:44)
    at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:91)
    at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:62)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:59)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
    at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.run(EventFiringTaskExecuter.java:51)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:300)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:292)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:174)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:90)
    at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:46)
    at org.gradle.execution.taskgraph.LocalTaskInfoExecutor.execute(LocalTaskInfoExecutor.java:42)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareWorkItemExecutor.execute(DefaultTaskExecutionGraph.java:273)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareWorkItemExecutor.execute(DefaultTaskExecutionGraph.java:258)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:135)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:130)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker.execute(DefaultTaskPlanExecutor.java:200)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker.executeWithWork(DefaultTaskPlanExecutor.java:191)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker.run(DefaultTaskPlanExecutor.java:130)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
Caused by: org.gradle.workers.internal.DefaultWorkerExecutor$WorkExecutionException: A failure occurred while executing me.champeau.gradle.IsolatedRunner
    at org.gradle.workers.internal.DefaultWorkerExecutor$WorkerExecution.waitForCompletion(DefaultWorkerExecutor.java:272)
    at org.gradle.internal.work.DefaultAsyncWorkTracker.waitForItemsAndGatherFailures(DefaultAsyncWorkTracker.java:99)
    at org.gradle.internal.work.DefaultAsyncWorkTracker.access$000(DefaultAsyncWorkTracker.java:34)
    at org.gradle.internal.work.DefaultAsyncWorkTracker$2.run(DefaultAsyncWorkTracker.java:83)
    at org.gradle.internal.work.DefaultWorkerLeaseService.withoutLocks(DefaultWorkerLeaseService.java:196)
    at org.gradle.internal.work.DefaultWorkerLeaseService.withoutProjectLock(DefaultWorkerLeaseService.java:145)
    at org.gradle.internal.work.StopShieldingWorkerLeaseService.withoutProjectLock(StopShieldingWorkerLeaseService.java:83)
    at org.gradle.internal.work.DefaultAsyncWorkTracker.waitForCompletion(DefaultAsyncWorkTracker.java:79)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.run(ExecuteActionsTaskExecuter.java:139)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:300)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:292)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:174)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:90)
    at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:120)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:99)
    ... 31 more
Caused by: java.lang.RuntimeException: ERROR: Unable to find the resource: /META-INF/BenchmarkList
    at org.openjdk.jmh.runner.AbstractResourceReader.getReaders(AbstractResourceReader.java:98)
    at org.openjdk.jmh.runner.BenchmarkList.find(BenchmarkList.java:122)
    at org.openjdk.jmh.runner.Runner.internalRun(Runner.java:263)
    at org.openjdk.jmh.runner.Runner.run(Runner.java:209)
    at me.champeau.gradle.IsolatedRunner.run(IsolatedRunner.java:38)
    at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:39)
    at org.gradle.workers.internal.WorkerDaemonServer.execute(WorkerDaemonServer.java:46)
    at org.gradle.workers.internal.WorkerDaemonServer.execute(WorkerDaemonServer.java:30)
    at org.gradle.process.internal.worker.request.WorkerAction.run(WorkerAction.java:101)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:155)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:137)
    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
    ... 3 more

Here is my build.gradle

plugins {
    id "me.champeau.gradle.jmh" version "0.4.7"
    id "java"
    id "eclipse"
    id "idea"
}

apply plugin: 'java-library'
apply plugin: 'eclipse'
apply plugin: 'me.champeau.gradle.jmh'

sourceCompatibility = '1.8'
targetCompatibility = '1.8'

group = "com.kmecpp"

configurations {
    shade
    compile.extendsFrom shade
}

repositories {
    jcenter()
    maven {
        url "https://plugins.gradle.org/m2/"
    }
}

sourceSets {
    jmh
}

eclipse {
   classpath {
       plusConfigurations.add(configurations.jmhCompile)
       defaultOutputDir = file('build/classes-jmh-ide')
   }
}

dependencies {
    // This dependency is exported to consumers, that is to say found on their compile classpath.
    api 'org.apache.commons:commons-math3:3.6.1'

    // This dependency is used internally, and not exposed to consumers on their own compile classpath.
    implementation 'com.google.guava:guava:23.0'

    shade "com.esotericsoftware:reflectasm:1.11.7"
    compile "com.eclipsesource.minimal-json:minimal-json:0.9.5"
    jmhCompile project
    jmhCompile "org.openjdk.jmh:jmh-core:1.21"
    jmhCompile "org.openjdk.jmh:jmh-generator-annprocess:1.21"

    // Use JUnit test framework
    testImplementation 'junit:junit:4.12'
}

jar {
    manifest.mainAttributes(
        "Built-By": "kmecpp",
        "Implementation-Title": archivesBaseName,
        "Implementation-Version": project.version)

    configurations.shade.each { dep ->
        print dep
        from(project.zipTree(dep)){
            exclude 'META-INF', 'META-INF/**'
        }
    }
}

jmh {
    include = '.*ParseBenchmark.*'
    humanOutputFile = null
    warmupIterations = 1
    iterations = 1
    fork = 3
    jmhVersion = '1.21' // Specifies JMH version
    duplicateClassesStrategy = 'warn'
}

I realized after a while that the reason why it was failing was because it was unable to overwrite the previous jmh jar file that was created, and the reason for that is that Java processes were still running even after the gradle build finishes.

Each time I run the jmh gradle task, the plugin starts 5 new processes: 3 JVMs and two command lines. I have to restart task manager, delete all the new processes and then I am able to run another gradle build.

Screenshot of after gradle exits, and the processes using the JMH jar are still running

image


image


image

uwemaurer commented 5 years ago

I had the same problem, it worked then when I ran gradle with the --no-daemon flag.

grv87 commented 5 years ago

I have the same issue, also under Windows.

I figured out that the cause is in ShutdownTimeoutThread class in JMH sources. Basically, it waits for some time after the last benchmark was finished. According to its javadoc, this should happen in two cases only. I couldn't figure out which one happens here, but it doesn't really matter. By default, timeout is 30 seconds, and this could be changed with jmh.shutdownTimeout property. So, one workaround is to just wait. I tested it with default timeout, after ~30 seconds jar file really becomes unlocked. Another workaround is to change this property.

Third workaround is to:

  1. Apply patch proposed in #145
  2. Set forceGC option to true