Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8211238

@Deprecated JFR event

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Fixed
    • Icon: P3 P3
    • 22
    • 12, 22
    • hotspot
    • jfr
    • b27

      We should add an event to help users detect their use of deprecated methods.

      To keep the overhead low, we could detect the use when methods are linked in the JVM. The default configuration should include events for methods with @Deprecated(forRemoval=true). Including methods that are declared Deprecated but not yet forRemoval, can be turned on by the user.

      JMC could have rules that warn users if they use methods targeted for removal.

      The event layout:

        <Event name="DeprecatedInvocation" description= "A unique invocation of a method that is annotated with @Deprecated. Packages and modules that are deprecated are ignored. At most 10 000 invocation sites and only the first invocation from a class is guaranteed to be included."
         category="Java Application, Statistics" label="Deprecated Method Invocation" thread="false" stackTrace="true" startTime="false" level="forRemoval,all">
          <Field type="Method" name="method" label="Deprecated Method" />
          <Field type="Ticks" name="invocationTime" label="Invocation Time" description="The time the deprecated method was invoked for the first time" />
          <Field type="boolean" name="forRemoval" label="For Removal" />
        </Event>

      The event will have a stack trace but will be truncated to the immediate caller. Take note JMC, as the existing heuristics about reporting truncated stack traces will need to be updated.

      The event essentially represents a unique edge in the call graph. In the future, we could try to find ways to report the entire call stack. It would involve a mechanism to transfer the ljf to the compiler threads in some way.

      The event is not declared periodic, but it will be emitted at the end of a chunk/recording

      To begin tracing methods that are deprecated, a user will have to specify a recording on the command line, like -XX:StartFlightRecording. The reason for only tracking deprecated invocation edges when -XX:StartFlightRecording is specified on the command line is to avoid adding overhead when JFR is unused. Starting a recording during runtime, for example, using JCMD, will not have these events reported unless -XX:StartFlightRecording was specified on the command-line.

      An example event would be rendered like this using the JFR tool:

      bin/jfr print <recording.jfr>

      jdk.DeprecatedInvocation {
        startTime = 23:31:28.431 (2023-12-04)
        method = jdk.jfr.internal.test.DeprecatedThing.foo()
        invocationTime = 23:31:25.954 (2023-12-04)
        forRemoval = true
        stackTrace = [
          jdk.jfr.event.runtime.TestDeprecatedEvent.testLevelAll() line: 96
          ...
        ]
      }

      The current design will only report direct invocations where the caller resides outside the JDK. Intra-JDK invocations will not be reported. The main reason is to keep the data points relevant to what the typical user can do something about.

      Additionally, invoking methods declared deprecated but outside of the JDK, for example, in a third-party library, will not be reported, at least not during this first implementation. The main reason is the uncertainty of how much data that would imply. After more investigations, we might want to consider removing this restriction.

      There exists a small restriction in the reporting of invocations from the Interpreter. In the situation where two caller methods are members of the same class, and they invoke the same deprecated method, for example:

      public class InterpreterRestriction {
          public static void main(String[] args) {
              invoke1();
              invoke2();
          }
          private static void invoke1() {
              System.getSecurityManager();
          }
          private static void invoke2() {
              System.getSecurityManager();
          }
      }

      In this situation, only <InterpreterRestriction.invoke1, System.getSecurityManager> will be reported because the Interpreter implementation will consider System.getSecurityManager() to be resolved and linked after the first call. When invoke2() is called, no slow path will be taken for the resolution of the System.getSecurityManager() method because it is already resolved as part of the cpCache. This restriction does not exist in C1 or C2 but only in the Interpreter.

      When analysing the reported events, checking all methods in the reported class is recommended. This slight restriction can be resolved using an iterative process; if one call site is fixed, the other will be reported in the next run.

            mgronlun Markus Grönlund
            egahlin Erik Gahlin
            Votes:
            0 Vote for this issue
            Watchers:
            8 Start watching this issue

              Created:
              Updated:
              Resolved: