Why does the HotSpot ExecutionSample event always return STATE_RUNNABLE?

Curious Java Guy :

I'm using the ExecutionSample event from HotSpot in OpenJDK11.

It has a field for thread state, but I only ever see one value for the field: STATE_RUNNABLE

How does HotSpot choose which threads to sample? Why are they always runnable?

Simple reproduction code in Kotlin:

import jdk.jfr.Recording
import jdk.jfr.consumer.RecordingFile
import java.nio.file.Path

object ExecutionSampleTest {

    private const val EXECUTION_SAMPLE = "jdk.ExecutionSample"
    private val RECORDING_PATH = Path.of("/tmp/recording.jfr")

    @JvmStatic
    fun main(args: Array<String>) {
        Recording().use { recording ->
            recording.enable(EXECUTION_SAMPLE)
            recording.settings = recording.settings.plus("$EXECUTION_SAMPLE#period" to "1 ms")

            recording.start()
            repeat(100) {
                // start some sleeping threads, just so we've got something to sample
                Thread { Thread.sleep(20_000) }.start()
            }
            Thread.sleep(20_000)
            recording.stop()
            recording.dump(RECORDING_PATH)

            RecordingFile.readAllEvents(RECORDING_PATH).forEach {
                println("Thread state: ${it.getString("state")}")
            }
        }
    }
}

Only ever prints: Thread state: STATE_RUNNABLE

apangin :

Why does the HotSpot ExecutionSample event always return STATE_RUNNABLE?

By design.

JFR method profiler periodically samples Java threads and produces two types of events:

  • ExecutionSample, when a thread state is in_java
  • NativeMethodSample, when a thread state is in_native

See jfrThreadSampler.cpp source code:

  if (JAVA_SAMPLE == type) {
    if (thread_state_in_java(thread)) {
      ret = sample_thread_in_java(thread, frames, max_frames);
    }
  } else {
    assert(NATIVE_SAMPLE == type, "invariant");
    if (thread_state_in_native(thread)) {
      ret = sample_thread_in_native(thread, frames, max_frames);
    }
  }

Both in_java and in_native correspond to STATE_RUNNABLE in JFR format.

When a thread is not runnable for either reason (STATE_SLEEPING, STATE_PARKED etc.), its JVM state is thread_blocked. However, JFR method profiler does not sample blocked threads at all.


If you are interested in wall clock profiling (i.e. sampling all threads, whether they run on CPU or sleep), you may want to look at async-profiler. Async-profiler can also produce output in JFR compatible format, but unlike JFR, it generates ExecutionSample events both for RUNNABLE and IDLE threads.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=4427&siteId=1