RFR: 8257967: JFR: Event for loaded agents
Greetings, We are adding support to let JFR report on Agents. #### Design An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize. A JavaAgent is an agent written in the Java programming language, using the APIs in the package [[ava.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...) A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services. To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples: // Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms initializationMethod = "premain" } // Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms initializationMethod = "agentmain" } The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents. For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar The event will also detail which initialization method was invoked by the JVM, "premain" for command line agents, and "agentmain" for agents loaded dynamically. "initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method. "startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime". An agent can also be written in a native programming language, using either the JVM Tools Interface (JVMTI) or JVM Profiling Interface (JVMPI). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file. JVMTI standard spec:ification is [here](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html) JVMPI is an older interface, not a standard and is considered superseded by JVMTI, but the support is still in the JVM for agents started on the command line: -XRunMyAgent.jar To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example: jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms } The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported, and there is also a denotation if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true). The initialization of a native agent is performed by invoking an agent-specified callback routine which is not detailed in the event (for now). The "initialization" is the time the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0. #### Implementation There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before. Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping and use it to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize. In order to implement this capability, it was necessary to refactor the code used to represent agents, called AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp. The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp. The previous lists used to maintain the agents (JVMTI) and libraries (JVMPI) is not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced. Testing: jdk_jfr, tier 1 - 6 Thanks Markus ------------- Commit messages: - event_names - adjustment - 8257967 Changes: https://git.openjdk.org/jdk/pull/12923/files Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=00 Issue: https://bugs.openjdk.org/browse/JDK-8257967 Stats: 1862 lines in 22 files changed: 1353 ins; 485 del; 24 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [[ava.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms initializationMethod = "premain" } // Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms initializationMethod = "agentmain" }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar
The event will also detail which initialization method was invoked by the JVM, "premain" for command line agents, and "agentmain" for agents loaded dynamically.
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language, using either the JVM Tools Interface (JVMTI) or JVM Profiling Interface (JVMPI). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
JVMTI standard spec:ification is [here](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html)
JVMPI is an older interface, not a standard and is considered superseded by JVMTI, but the support is still in the JVM for agents started on the command line: -XRunMyAgent.jar
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported, and there is also a denotation if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true).
The initialization of a native agent is performed by invoking an agent-specified callback routine which is not detailed in the event (for now). The "initialization" is the time the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
To implement this capability, it was necessary to refactor the code used to represent agents, called AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous lists that maintain the agents (JVMTI) and libraries (JVMPI) are not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision: razor ------------- Changes: - all: https://git.openjdk.org/jdk/pull/12923/files - new: https://git.openjdk.org/jdk/pull/12923/files/c50cca53..ed1ea797 Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=01 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=00-01 Stats: 114 lines in 3 files changed: 33 ins; 74 del; 7 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms initializationMethod = "premain" } // Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms initializationMethod = "agentmain" }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar
The event will also detail which initialization method was invoked by the JVM, "premain" for command line agents, and "agentmain" for agents loaded dynamically.
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language, using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported, and there is also a denotation if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true).
The initialization of a native agent is performed by invoking an agent-specified callback routine which is not detailed in the event (for now). The "initialization" is the time the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
To implement this capability, it was necessary to refactor the code used to represent agents, called AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous lists that maintain the agents (JVMTI) and libraries (JVMPI) are not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision: update ------------- Changes: - all: https://git.openjdk.org/jdk/pull/12923/files - new: https://git.openjdk.org/jdk/pull/12923/files/ed1ea797..26172f0e Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=02 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=01-02 Stats: 13 lines in 2 files changed: 5 ins; 1 del; 7 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
The message from this sender included one or more files which could not be scanned for virus detection; do not open these files unless you are certain of the sender's intent. ----------------------------------------------------------------------
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms initializationMethod = "premain" } // Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms initializationMethod = "agentmain" }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar
The event will also detail which initialization method was invoked by the JVM, "premain" for command line agents, and "agentmain" for agents loaded dynamically.
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language, using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported, and there is also a denotation if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true).
The initialization of a native agent is performed by invoking an agent-specified callback routine which is not detailed in the event (for now). The "initialization" is the time the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
To implement this capability, it was necessary to refactor the code used to represent agents, called AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous lists that maintain the agents (JVMTI) and libraries (JVMPI) are not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with two additional commits since the last revision: - remove JVMPI - cleanup ------------- Changes: - all: https://git.openjdk.org/jdk/pull/12923/files - new: https://git.openjdk.org/jdk/pull/12923/files/26172f0e..355d307c Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=03 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=02-03 Stats: 2 lines in 2 files changed: 0 ins; 0 del; 2 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
On Wed, 8 Mar 2023 18:56:55 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms initializationMethod = "premain" } // Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms initializationMethod = "agentmain" }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar
The event will also detail which initialization method was invoked by the JVM, "premain" for command line agents, and "agentmain" for agents loaded dynamically.
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language, using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported, and there is also a denotation if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true).
The initialization of a native agent is performed by invoking an agent-specified callback routine which is not detailed in the event (for now). The "initialization" is the time the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
To implement this capability, it was necessary to refactor the code used to represent agents, called AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous lists that maintain the agents (JVMTI) and libraries (JVMPI) are not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with two additional commits since the last revision:
- remove JVMPI - cleanup
This seems a very large and intrusive change just to give some data about agents (sorry if that sounds flippant). IIUC you are generating events for stuff that (used to?) happens very early in the initialization process and for which you now need to load a whole heap of JFR classes - which could themselves be subject to the actions of the agent. The impact of this on the overall initialization process is very hard to gauge. src/hotspot/share/runtime/threads.cpp line 338:
336: if (EagerXrunInit && Arguments::init_libraries_at_startup()) { 337: create_vm_init_libraries(); 338: }
Not obvious where this went. Changes to the initialization order can be very problematic. ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Wed, 8 Mar 2023 22:56:31 GMT, David Holmes <dholmes@openjdk.org> wrote:
Markus Grönlund has updated the pull request incrementally with two additional commits since the last revision:
- remove JVMPI - cleanup
src/hotspot/share/runtime/threads.cpp line 338:
336: if (EagerXrunInit && Arguments::init_libraries_at_startup()) { 337: create_vm_init_libraries(); 338: }
Not obvious where this went. Changes to the initialization order can be very problematic.
Thanks, David. Two calls to launch XRun agents are invoked during startup, and they depend on the EagerXrunInit option. The !EagerXrunInit case is already located in create_vm(), but the EagerXrunInit was located as the first entry in initialize_java_lang_classes(), which I thought was tucked away a bit unnecessarily. I hoisted the EagerXrunInit from initialize_java_lang_classes() into to create_vm(). It's now the call just before initialize_java_lang_classes(). This made it clearer, i.e. to have both calls located directly in create_vm(). ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Thu, 9 Mar 2023 09:29:41 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
src/hotspot/share/runtime/threads.cpp line 338:
336: if (EagerXrunInit && Arguments::init_libraries_at_startup()) { 337: create_vm_init_libraries(); 338: }
Not obvious where this went. Changes to the initialization order can be very problematic.
Thanks, David. Two calls to launch XRun agents are invoked during startup, and they depend on the EagerXrunInit option. The !EagerXrunInit case is already located in create_vm(), but the EagerXrunInit was located as the first entry in initialize_java_lang_classes(), which I thought was tucked away a bit unnecessarily.
I hoisted the EagerXrunInit case from initialize_java_lang_classes() up to create_vm(). It's now the call just before initialize_java_lang_classes().
This made it clearer, i.e. to have both calls located directly in create_vm().
Thanks for clarifying. That makes sense. ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Wed, 8 Mar 2023 18:56:55 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms initializationMethod = "premain" } // Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms initializationMethod = "agentmain" }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar
The event will also detail which initialization method was invoked by the JVM, "premain" for command line agents, and "agentmain" for agents loaded dynamically.
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language, using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported, and there is also a denotation if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true).
The initialization of a native agent is performed by invoking an agent-specified callback routine which is not detailed in the event (for now). The "initialization" is the time the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
To implement this capability, it was necessary to refactor the code used to represent agents, called AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous lists that maintain the agents (JVMTI) and libraries (JVMPI) are not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with two additional commits since the last revision:
- remove JVMPI - cleanup
No need to load any JFR classes. No change to startup logic. ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Wed, 8 Mar 2023 23:28:52 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
No need to load any JFR classes.
I thought JFR was all Java-based these days. But if no Java involved then that is good.
No change to startup logic.
I flagged a change in my comment above. ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Thu, 9 Mar 2023 00:23:39 GMT, David Holmes <dholmes@openjdk.org> wrote:
No need to load any JFR classes.
I thought JFR was all Java-based these days. But if no Java involved then that is good.
Ehh, no. Far from it.
No change to startup logic.
I flagged a change in my comment above.
Thanks, pls see my reply. ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Thu, 9 Mar 2023 00:23:39 GMT, David Holmes <dholmes@openjdk.org> wrote:
No need to load any JFR classes. No change to startup logic.
No need to load any JFR classes.
I thought JFR was all Java-based these days. But if no Java involved then that is good.
No change to startup logic.
I flagged a change in my comment above.
Thank you @dholmes-ora, @sspitsyn and @adinn for your reviews and sticking with this one for quite some time. ------------- PR Comment: https://git.openjdk.org/jdk/pull/12923#issuecomment-1511011114
On Wed, 8 Mar 2023 23:28:52 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Markus Grönlund has updated the pull request incrementally with two additional commits since the last revision:
- remove JVMPI - cleanup
No need to load any JFR classes. No change to startup logic.
@mgronlun Why mark Java agents as command-line or dynamic using `initializationMethod = "premain"/"agentMain"` and mark native agents using `dynamic = true/false`? Why not use `dynamic` for both? ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Wed, 8 Mar 2023 23:28:52 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Markus Grönlund has updated the pull request incrementally with two additional commits since the last revision:
- remove JVMPI - cleanup
No need to load any JFR classes. No change to startup logic.
@mgronlun Why mark Java agents as command-line or dynamic using `initializationMethod = "premain"/"agentMain"` and mark native agents using `dynamic = true/false`? Why not use `dynamic` for both?
Hi Andrew, that's a good question. I thought it could be derived in the JavaAgent case, because there are only two entry points, "premain" implies static and "agentmain" implies dynamic. For the native case, there is no information about the callback (I had it, but it depends on symbols), so the dynamic field is made explicit. It can also be added to the JavaAgent if that makes it clearer. ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Wed, 8 Mar 2023 18:56:55 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms initializationMethod = "premain" } // Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms initializationMethod = "agentmain" }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar
The event will also detail which initialization method was invoked by the JVM, "premain" for command line agents, and "agentmain" for agents loaded dynamically.
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported, and there is also a denotation if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true).
The initialization of a native agent is performed by invoking an agent-specified callback routine which is not detailed in the event (for now). The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with two additional commits since the last revision:
- remove JVMPI - cleanup
Yes, I appreciate that `dynamic` can be derived from `initializationMethod` -- and vice versa. However, I was approaching this semantically from the opposite end. To me the primary characteristic that the user would be interested in is whether the agent was loaded dynamically or on the command line (whatever the type of agent). The corresponding fact, for a Java agent, that it is entered, respectively, via method agentMain or preMain is a derived (implementation) detail. Is there a reason to mention that detail? ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Thu, 9 Mar 2023 09:36:28 GMT, Andrew Dinn <adinn@openjdk.org> wrote:
Yes, I appreciate that `dynamic` can be derived from `initializationMethod` -- and vice versa. However, I was approaching this semantically from the opposite end. To me the primary characteristic that the user would be interested in is whether the agent was loaded dynamically or on the command line (whatever the type of agent). The corresponding fact, for a Java agent, that it is entered, respectively, via method agentMain or preMain is a derived (implementation) detail. Is there a reason to mention that detail?
That's a good point. The overall intent was to map what method was measured during initialization. That included native agent callbacks as well. It may be an unnecessary implementation detail and may restrict the possibility of growth. It is probably a better design abstraction to leave out the specific method. I dropped the callback function for the native agent, but we should also do the same for JavaAgents. ------------- PR: https://git.openjdk.org/jdk/pull/12923
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision: remove implementation details ------------- Changes: - all: https://git.openjdk.org/jdk/pull/12923/files - new: https://git.openjdk.org/jdk/pull/12923/files/355d307c..f0c04055 Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=04 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=03-04 Stats: 16 lines in 3 files changed: 9 ins; 6 del; 1 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision: fixes ------------- Changes: - all: https://git.openjdk.org/jdk/pull/12923/files - new: https://git.openjdk.org/jdk/pull/12923/files/f0c04055..80f22257 Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=05 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=04-05 Stats: 5 lines in 2 files changed: 1 ins; 2 del; 2 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision: cleanup ------------- Changes: - all: https://git.openjdk.org/jdk/pull/12923/files - new: https://git.openjdk.org/jdk/pull/12923/files/80f22257..d0609bfb Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=06 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=05-06 Stats: 15 lines in 3 files changed: 1 ins; 3 del; 11 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision: more cleanup ------------- Changes: - all: https://git.openjdk.org/jdk/pull/12923/files - new: https://git.openjdk.org/jdk/pull/12923/files/d0609bfb..db48fe8d Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=07 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=06-07 Stats: 4 lines in 3 files changed: 1 ins; 1 del; 2 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision: handle multiple envs with same VMInit callback ------------- Changes: - all: https://git.openjdk.org/jdk/pull/12923/files - new: https://git.openjdk.org/jdk/pull/12923/files/db48fe8d..abeaa324 Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=08 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=07-08 Stats: 8 lines in 2 files changed: 5 ins; 0 del; 3 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
On Thu, 9 Mar 2023 16:58:42 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
handle multiple envs with same VMInit callback
src/hotspot/share/prims/agent.cpp line 41:
39: char* copy = AllocateHeap(length + 1, mtInternal); 40: strncpy(copy, str, length + 1); 41: assert(strncmp(copy, str, length + 1) == 0, "invariant");
Unclear what you are checking here. Don't you trust strncpy? ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Fri, 10 Mar 2023 06:57:46 GMT, David Holmes <dholmes@openjdk.org> wrote:
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
handle multiple envs with same VMInit callback
src/hotspot/share/prims/agent.cpp line 41:
39: char* copy = AllocateHeap(length + 1, mtInternal); 40: strncpy(copy, str, length + 1); 41: assert(strncmp(copy, str, length + 1) == 0, "invariant");
Unclear what you are checking here. Don't you trust strncpy?
Maybe a bit paranoid, yes. I can clean up. ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Tue, 14 Mar 2023 12:19:50 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
src/hotspot/share/prims/agent.cpp line 41:
39: char* copy = AllocateHeap(length + 1, mtInternal); 40: strncpy(copy, str, length + 1); 41: assert(strncmp(copy, str, length + 1) == 0, "invariant");
Unclear what you are checking here. Don't you trust strncpy?
Maybe a bit paranoid, yes. I can clean up.
updated to use os:::strdup - cheers. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1153702643
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision: more cleanup ------------- Changes: - all: https://git.openjdk.org/jdk/pull/12923/files - new: https://git.openjdk.org/jdk/pull/12923/files/abeaa324..741b8686 Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=09 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=08-09 Stats: 12 lines in 3 files changed: 1 ins; 10 del; 1 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
On Fri, 10 Mar 2023 10:43:23 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
more cleanup
Still working through this. A few minor comments below. src/hotspot/share/prims/agent.cpp line 34:
32: } 33: 34: static const char* allocate_copy(const char* str) {
Why not just use `os::strdup`? src/hotspot/share/prims/agentList.cpp line 64:
62: void AgentList::add_xrun(const char* name, char* options, bool absolute_path) { 63: Agent* agent = new Agent(name, options, absolute_path); 64: agent->_is_xrun = true;
Why direct access of private field instead of having a setter like other parts of the Agent API? src/hotspot/share/prims/agentList.cpp line 227:
225: * store data in their JvmtiEnv local storage. 226: * 227: * Please see JPLISAgent.c in module java.instrument, see JPLISAgent.h and JPLISAgent.c.
No need to mention the .c file twice. src/hotspot/share/prims/agentList.cpp line 419:
417: const jint err = (*on_load_entry)(&main_vm, const_cast<char*>(agent->options()), NULL); 418: if (err != JNI_OK) { 419: vm_exit_during_initialization("-Xrun library failed to init", agent->name());
Do you need to be back in `_thread_in_vm` before exiting? src/hotspot/share/prims/agentList.cpp line 542:
540: 541: // Invoke the Agent_OnAttach function 542: JavaThread* THREAD = JavaThread::current(); // For exception macros.
Nit: just use `current` rather than `THREAD` and don't use the exception macros. ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Mon, 13 Mar 2023 06:29:11 GMT, David Holmes <dholmes@openjdk.org> wrote:
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
more cleanup
src/hotspot/share/prims/agentList.cpp line 64:
62: void AgentList::add_xrun(const char* name, char* options, bool absolute_path) { 63: Agent* agent = new Agent(name, options, absolute_path); 64: agent->_is_xrun = true;
Why direct access of private field instead of having a setter like other parts of the Agent API?
n.b. that also applies for accesses/updates to field _next. ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Mon, 13 Mar 2023 09:49:39 GMT, Andrew Dinn <adinn@openjdk.org> wrote:
src/hotspot/share/prims/agentList.cpp line 64:
62: void AgentList::add_xrun(const char* name, char* options, bool absolute_path) { 63: Agent* agent = new Agent(name, options, absolute_path); 64: agent->_is_xrun = true;
Why direct access of private field instead of having a setter like other parts of the Agent API?
n.b. that also applies for accesses/updates to field _next.
I wanted all accesses to use the iterator. The only access is given to the iterator and AgentList by way of being friends. No need to expose more. ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Tue, 14 Mar 2023 12:22:16 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
n.b. that also applies for accesses/updates to field _next.
I wanted all accesses to use the iterator. The only access is given to the iterator and AgentList by way of being friends. No need to expose more.
I updated all external access to use getters/setters. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1153703241
On Mon, 13 Mar 2023 06:22:21 GMT, David Holmes <dholmes@openjdk.org> wrote:
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
more cleanup
src/hotspot/share/prims/agent.cpp line 34:
32: } 33: 34: static const char* allocate_copy(const char* str) {
Why not just use `os::strdup`?
Better alternative, thanks David.
src/hotspot/share/prims/agentList.cpp line 227:
225: * store data in their JvmtiEnv local storage. 226: * 227: * Please see JPLISAgent.c in module java.instrument, see JPLISAgent.h and JPLISAgent.c.
No need to mention the .c file twice.
Good point.
src/hotspot/share/prims/agentList.cpp line 419:
417: const jint err = (*on_load_entry)(&main_vm, const_cast<char*>(agent->options()), NULL); 418: if (err != JNI_OK) { 419: vm_exit_during_initialization("-Xrun library failed to init", agent->name());
Do you need to be back in `_thread_in_vm` before exiting?
Hmm. This was ported as is. I will double-check.
src/hotspot/share/prims/agentList.cpp line 542:
540: 541: // Invoke the Agent_OnAttach function 542: JavaThread* THREAD = JavaThread::current(); // For exception macros.
Nit: just use `current` rather than `THREAD` and don't use the exception macros.
Ported as is but good point, will update. ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Tue, 14 Mar 2023 12:23:08 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
src/hotspot/share/prims/agentList.cpp line 419:
417: const jint err = (*on_load_entry)(&main_vm, const_cast<char*>(agent->options()), NULL); 418: if (err != JNI_OK) { 419: vm_exit_during_initialization("-Xrun library failed to init", agent->name());
Do you need to be back in `_thread_in_vm` before exiting?
Hmm. This was ported as is. I will double-check.
Looks like there is no requirement to be in _thread_in_vm before invoking vm_exit_during_initialization(). vm_perform_shutdown_actions() will forcibly set the thread state to _thread_in_native (no transition). ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1153243069
On Fri, 10 Mar 2023 10:43:23 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
more cleanup
src/hotspot/share/jfr/metadata/metadata.xml line 1182:
1180: <Field type="Ticks" name="initialization" label="Initialization" description="The time the JVM initialized the agent" /> 1181: <Field type="Tickspan" name="initializationTime" label="Initialization Time" description="The duration of executing the initialization method exported by the agent" /> 1182: </Event>
@mgronlun A somewhat drive-by comment. It might be clearer if you renamed these event fields and accessors, plus also the corresponding fields and accessors in class Agent, as `initializationTime` and `initializationDuration`. ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Mon, 13 Mar 2023 09:46:04 GMT, Andrew Dinn <adinn@openjdk.org> wrote:
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
more cleanup
src/hotspot/share/jfr/metadata/metadata.xml line 1182:
1180: <Field type="Ticks" name="initialization" label="Initialization" description="The time the JVM initialized the agent" /> 1181: <Field type="Tickspan" name="initializationTime" label="Initialization Time" description="The duration of executing the initialization method exported by the agent" /> 1182: </Event>
@mgronlun A somewhat drive-by comment. It might be clearer if you renamed these event fields and accessors, plus also the corresponding fields and accessors in class Agent, as `initializationTime` and `initializationDuration`.
Makes sense. ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Fri, 10 Mar 2023 10:43:23 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
more cleanup
I've had a good look through now and have a better sense of the refactoring. Seems good. I'll wait for any tweaks before hitting the approve button though. Thanks ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Tue, 14 Mar 2023 06:01:05 GMT, David Holmes <dholmes@openjdk.org> wrote:
I've had a good look through now and have a better sense of the refactoring. Seems good.
I'll wait for any tweaks before hitting the approve button though.
Thanks
Thanks so much for taking a look. I realized that implementation details of loading should probably reside in agent.cpp, not agentList.cpp. I am currently off on vacation and will update when back. Thanks also to Andrew Dinn for comments. ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Tue, 14 Mar 2023 12:26:16 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
I've had a good look through now and have a better sense of the refactoring. Seems good.
I'll wait for any tweaks before hitting the approve button though.
Thanks
I've had a good look through now and have a better sense of the refactoring. Seems good.
I'll wait for any tweaks before hitting the approve button though.
Thanks
Thanks so much for taking a look. I realized that implementation details of loading should probably reside in agent.cpp, not agentList.cpp.
I am currently off on vacation and will update when back. Thanks also to Andrew Dinn for comments.
@mgronlun I'm looking at the fixes but it will take some time. ------------- PR: https://git.openjdk.org/jdk/pull/12923
On Tue, 14 Mar 2023 12:26:16 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
I've had a good look through now and have a better sense of the refactoring. Seems good.
I'll wait for any tweaks before hitting the approve button though.
Thanks
Moving the loading logic to the agent.cpp module was a bit harder than I initially thought. It also exposed a bug in how statically linked libraries were loaded - now fixed. Sorry for the large update. Thanks again for having a look.
src/hotspot/share/prims/agentList.cpp line 542:
540: 541: // Invoke the Agent_OnAttach function 542: JavaThread* THREAD = JavaThread::current(); // For exception macros.
Nit: just use `current` rather than `THREAD` and don't use the exception macros.
Ported as is but good point, will update.
Updated - cheers. ------------- PR Comment: https://git.openjdk.org/jdk/pull/12923#issuecomment-1490828465 PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1153703484
On Fri, 10 Mar 2023 10:43:23 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
more cleanup
src/hotspot/share/prims/jvmtiEnvBase.hpp line 166:
164: 165: const void* get_env_local_storage() { return _env_local_storage; } 166:
Why was this change/move necessary? Do I miss anything? ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1142804605
On Tue, 21 Mar 2023 00:53:31 GMT, Serguei Spitsyn <sspitsyn@openjdk.org> wrote:
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
more cleanup
src/hotspot/share/prims/jvmtiEnvBase.hpp line 166:
164: 165: const void* get_env_local_storage() { return _env_local_storage; } 166:
Why was this change/move necessary? Do I miss anything?
It is now public, not protected. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1144458026
On Wed, 22 Mar 2023 09:18:51 GMT, David Holmes <dholmes@openjdk.org> wrote:
src/hotspot/share/prims/jvmtiEnvBase.hpp line 166:
164: 165: const void* get_env_local_storage() { return _env_local_storage; } 166:
Why was this change/move necessary? Do I miss anything?
It is now public, not protected.
I see, thanks. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1155048753
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision: reviewer feedback, loading to agent.cpp, bugfix loading statically linked agent ------------- Changes: - all: https://git.openjdk.org/jdk/pull/12923/files - new: https://git.openjdk.org/jdk/pull/12923/files/741b8686..0b10773f Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=10 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=09-10 Stats: 1079 lines in 9 files changed: 481 ins; 426 del; 172 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk.git pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request with a new target base due to a merge or a rebase. The pull request now contains 15 commits: - Merge branch 'master' into agents - reviewer feedback, loading to agent.cpp, bugfix loading statically linked agent - more cleanup - handle multiple envs with same VMInit callback - more cleanup - cleanup - fixes - remove implementation details - remove JVMPI - cleanup - ... and 5 more: https://git.openjdk.org/jdk/compare/83cf28f9...659e6f3d ------------- Changes: https://git.openjdk.org/jdk/pull/12923/files Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=11 Stats: 1889 lines in 22 files changed: 1368 ins; 490 del; 31 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk.git pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
On Thu, 30 Mar 2023 18:59:30 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request with a new target base due to a merge or a rebase. The pull request now contains 15 commits:
- Merge branch 'master' into agents - reviewer feedback, loading to agent.cpp, bugfix loading statically linked agent - more cleanup - handle multiple envs with same VMInit callback - more cleanup - cleanup - fixes - remove implementation details - remove JVMPI - cleanup - ... and 5 more: https://git.openjdk.org/jdk/compare/83cf28f9...659e6f3d
Hm, not sure how helpful the events are, but if you really want them to be informative, how about adding the path of the jar file or maybe the class names? ------------- PR Comment: https://git.openjdk.org/jdk/pull/12923#issuecomment-1490802537
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision: remove whitespace ------------- Changes: - all: https://git.openjdk.org/jdk/pull/12923/files - new: https://git.openjdk.org/jdk/pull/12923/files/659e6f3d..c024fac5 Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=12 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=11-12 Stats: 1 line in 1 file changed: 0 ins; 0 del; 1 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk.git pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision: restore misssing frees ------------- Changes: - all: https://git.openjdk.org/jdk/pull/12923/files - new: https://git.openjdk.org/jdk/pull/12923/files/c024fac5..ab74621b Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=13 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=12-13 Stats: 4 lines in 1 file changed: 4 ins; 0 del; 0 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk.git pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
On Thu, 30 Mar 2023 19:20:11 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initialization = 12:31:15.574 (2023-03-08) initializationTime = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initialization = 12:31:31.037 (2023-03-08) initializationTime = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initialization" is the timestamp the JVM invoked the initialization method, and "initializationTime" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initialization" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initialization = 12:31:36.142 (2023-03-08) initializationTime = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initialization" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationTime" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationTime" will be 0.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
restore misssing frees
Hm, not sure how helpful the events are, but if you want them to be informative, how about adding the path of the jar file or maybe the class names?
It has been considered. The full path of the Java .jar might not be that interesting, and it adds much more complexity to resolve it, as most are relative to the classpath. ClassName will be whatever class exports the prremain or agentmain. We discussed this internally and decided that if there is an actual demand for it, we can add a "path" field to the JavaAgent event type. ------------- PR Comment: https://git.openjdk.org/jdk/pull/12923#issuecomment-1490811900
On Thu, 30 Mar 2023 19:20:11 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
restore misssing frees
src/hotspot/share/jfr/metadata/metadata.xml line 1190:
1188: <Field type="boolean" name="dynamic" label="Dynamic" description="If the library attached to the JVM dynamically during runtime, i.e. not at startup" /> 1189: <Field type="Ticks" name="initializationTime" label="Initialization Time" description="The time the JVM initialized the agent" /> 1190: <Field type="Tickspan" name="initializationDuration" label="Initialization Duration" description="The duration of executing the JVMTI VMInit event callback. If no VMInit callback is specified, the duration is 0. For a dynamically loaded agent, the duration of executing the call to Agent_OnAttach." />
Nit: In the last sentence I suggest s/the duration/it is the duration/ src/hotspot/share/prims/agent.cpp line 533:
531: if (thread->is_pending_jni_exception_check()) { 532: thread->clear_pending_jni_exception_check(); 533: }
Unsure why we pretend the agent checked this - don't we want -Xcheck:jni to report a bug in the agent? src/hotspot/share/prims/agent.cpp line 536:
534: } 535: 536: // Agent_OnAttach may have used JNI
Copied from above? ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1153965163 PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1153967066 PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1153966809
On Fri, 31 Mar 2023 03:05:31 GMT, David Holmes <dholmes@openjdk.org> wrote:
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
restore misssing frees
src/hotspot/share/prims/agent.cpp line 533:
531: if (thread->is_pending_jni_exception_check()) { 532: thread->clear_pending_jni_exception_check(); 533: }
Unsure why we pretend the agent checked this - don't we want -Xcheck:jni to report a bug in the agent?
Good question - I don't know. For dynamically loaded agents, there seems to be quite a lot of handling to return a JNI_OK, even though the agent failed to load or returned failure from the Agent_OnAttach. e.g. // Agent_OnAttach executed so completion status is JNI_OK return JNI_OK; ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1154346856
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision: fixes ------------- Changes: - all: https://git.openjdk.org/jdk/pull/12923/files - new: https://git.openjdk.org/jdk/pull/12923/files/ab74621b..07407a82 Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=14 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=13-14 Stats: 5 lines in 2 files changed: 2 ins; 0 del; 3 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk.git pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
On Fri, 31 Mar 2023 11:18:23 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
fixes
src/hotspot/share/prims/agent.hpp line 1:
1: /*
The name for class and file is too general. I'm thinking if renaming the files to jvmtiAgent and the class to JvmtiAgent would work. In general, there exists a convention to name JVMTI file with the "jvmti" prefix. It is a gray zone between Runtime and JVMTI but seems to belong more to JVMTI. The same about the AgentList class and file. Also, these new files are good candidates to add here: make/hotspot/lib/JvmFeatures.gmk: ifneq ($(call check-jvm-feature, jvmti), true) JVM_CFLAGS_FEATURES += -DINCLUDE_JVMTI=0 JVM_EXCLUDE_FILES += jvmtiGetLoadedClasses.cpp jvmtiThreadState.cpp jvmtiExtensions.cpp \ jvmtiImpl.cpp jvmtiManageCapabilities.cpp jvmtiRawMonitor.cpp jvmtiUtil.cpp jvmtiTrace.cpp \ jvmtiCodeBlobEvents.cpp jvmtiEnv.cpp jvmtiRedefineClasses.cpp jvmtiEnvBase.cpp jvmtiEnvThreadState.cpp \ jvmtiTagMap.cpp jvmtiEventController.cpp evmCompat.cpp jvmtiEnter.xsl jvmtiExport.cpp \ jvmtiClassFileReconstituter.cpp jvmtiTagMapTable.cpp endif ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1155049911
On Sat, 1 Apr 2023 03:31:48 GMT, Serguei Spitsyn <sspitsyn@openjdk.org> wrote:
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
fixes
src/hotspot/share/prims/agent.hpp line 1:
1: /*
The name for class and file is too general. I'm thinking if renaming the files to jvmtiAgent and the class to JvmtiAgent would work. In general, there exists a convention to name JVMTI file with the "jvmti" prefix. It is a gray zone between Runtime and JVMTI but seems to belong more to JVMTI. The same about the AgentList class and file. Also, these new files are good candidates to add here:
make/hotspot/lib/JvmFeatures.gmk: ifneq ($(call check-jvm-feature, jvmti), true) JVM_CFLAGS_FEATURES += -DINCLUDE_JVMTI=0 JVM_EXCLUDE_FILES += jvmtiGetLoadedClasses.cpp jvmtiThreadState.cpp jvmtiExtensions.cpp \ jvmtiImpl.cpp jvmtiManageCapabilities.cpp jvmtiRawMonitor.cpp jvmtiUtil.cpp jvmtiTrace.cpp \ jvmtiCodeBlobEvents.cpp jvmtiEnv.cpp jvmtiRedefineClasses.cpp jvmtiEnvBase.cpp jvmtiEnvThreadState.cpp \ jvmtiTagMap.cpp jvmtiEventController.cpp evmCompat.cpp jvmtiEnter.xsl jvmtiExport.cpp \ jvmtiClassFileReconstituter.cpp jvmtiTagMapTable.cpp endif
Hi Sergui, thanks for taking a look. I have updated with the names you suggested. Thanks. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1157362083
On Tue, 4 Apr 2023 14:41:13 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
src/hotspot/share/prims/agent.hpp line 1:
1: /*
The name for class and file is too general. I'm thinking if renaming the files to jvmtiAgent and the class to JvmtiAgent would work. In general, there exists a convention to name JVMTI file with the "jvmti" prefix. It is a gray zone between Runtime and JVMTI but seems to belong more to JVMTI. The same about the AgentList class and file. Also, these new files are good candidates to add here:
make/hotspot/lib/JvmFeatures.gmk: ifneq ($(call check-jvm-feature, jvmti), true) JVM_CFLAGS_FEATURES += -DINCLUDE_JVMTI=0 JVM_EXCLUDE_FILES += jvmtiGetLoadedClasses.cpp jvmtiThreadState.cpp jvmtiExtensions.cpp \ jvmtiImpl.cpp jvmtiManageCapabilities.cpp jvmtiRawMonitor.cpp jvmtiUtil.cpp jvmtiTrace.cpp \ jvmtiCodeBlobEvents.cpp jvmtiEnv.cpp jvmtiRedefineClasses.cpp jvmtiEnvBase.cpp jvmtiEnvThreadState.cpp \ jvmtiTagMap.cpp jvmtiEventController.cpp evmCompat.cpp jvmtiEnter.xsl jvmtiExport.cpp \ jvmtiClassFileReconstituter.cpp jvmtiTagMapTable.cpp endif
Hi Serguei, thanks for taking a look.
I have updated with the names you suggested. Thanks.
Thank you for the update. It looks good to me. I still need to finish my review. Sorry for the latency. It is is a busy time now. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1158087046
On Fri, 31 Mar 2023 11:18:23 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
fixes
src/hotspot/share/prims/agentList.cpp line 204:
202: 203: // Invokes Agent_OnAttach for agents loaded dynamically during runtime. 204: jint AgentList::load_agent(const char* agent_name, const char* absParam,
I feel that it is better to keep the original function name "load_agent_library". As you listed there two kinds of agents: Java and Native. The function name give a hint it is native agent. Also, it is better to avoid changes that aren't really necessary. src/hotspot/share/prims/jvmtiExport.cpp line 694:
692: } 693: 694: // Lookup an agent from an JvmtiEnv.Return agent only if it is not yet initialized.
A space is missed after the first dot. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1155051226 PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1155050084
On Sat, 1 Apr 2023 03:47:26 GMT, Serguei Spitsyn <sspitsyn@openjdk.org> wrote:
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
fixes
src/hotspot/share/prims/agentList.cpp line 204:
202: 203: // Invokes Agent_OnAttach for agents loaded dynamically during runtime. 204: jint AgentList::load_agent(const char* agent_name, const char* absParam,
I feel that it is better to keep the original function name "load_agent_library". As you listed there two kinds of agents: Java and Native. The function name give a hint it is native agent. Also, it is better to avoid changes that aren't really necessary.
I changed the names because I found it very hard to understand what the old names represented: "AgentLibrary" vs "Library"? "add_init_agent" vs "add_instrumentation_agent", or even "add_loaded_agent"? Also a bit confusing that "load_agent_library" would also include statically linked agents - no library is loaded there. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1155930115
On Mon, 3 Apr 2023 12:59:12 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
src/hotspot/share/prims/agentList.cpp line 204:
202: 203: // Invokes Agent_OnAttach for agents loaded dynamically during runtime. 204: jint AgentList::load_agent(const char* agent_name, const char* absParam,
I feel that it is better to keep the original function name "load_agent_library". As you listed there two kinds of agents: Java and Native. The function name give a hint it is native agent. Also, it is better to avoid changes that aren't really necessary.
I changed the names because I found it very hard to understand what the old names represented: "AgentLibrary" vs "Library"? "add_init_agent" vs "add_instrumentation_agent", or even "add_loaded_agent"? Also a bit confusing that "load_agent_library" would also include statically linked agents - no library is loaded there.
Okay. Refactoring is usually not easy to review. With a renaming it becomes harder, so it is better to be conservative. There are other side effects to consider: - back porting also becomes harder - developers have to learn new names instead of already known The good side is that your refactoring consolidates this code in a well known locations. :-) ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1158094815
On Wed, 5 Apr 2023 06:55:16 GMT, Serguei Spitsyn <sspitsyn@openjdk.org> wrote:
I changed the names because I found it very hard to understand what the old names represented: "AgentLibrary" vs "Library"? "add_init_agent" vs "add_instrumentation_agent", or even "add_loaded_agent"? Also a bit confusing that "load_agent_library" would also include statically linked agents - no library is loaded there.
Okay. Refactoring is usually not easy to review. With a renaming it becomes harder, so it is better to be conservative.
There are other side effects to consider:
- back porting also becomes harder - developers have to learn new names instead of already known
The good side is that your refactoring consolidates this code in a well known locations. :-)
Of course, I would not have changed this unless I believe it improves things. The abstraction is now better from the perspective of the rest of the VM. There are now only JVMTI agents, and they are kept in a list. Arguments.cpp adds agents to the list. The same thing for the diagnosticCommand.cpp for dynamically loaded agents. Threads.cpp loads the JVMTI agents, java.cpp unloads agents. All other sites take out an iterator of the subtypes they want to iterate. There is no longer any separation between "agent" and "library"; the subtypes of the agents are now abstracted away. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1158282424
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision: renames ------------- Changes: - all: https://git.openjdk.org/jdk/pull/12923/files - new: https://git.openjdk.org/jdk/pull/12923/files/07407a82..d0fd9e97 Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=15 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=14-15 Stats: 2158 lines in 19 files changed: 1059 ins; 1059 del; 40 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk.git pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
On Tue, 4 Apr 2023 14:39:19 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
renames
Renamings look good to me. ------------- Marked as reviewed by dholmes (Reviewer). PR Review: https://git.openjdk.org/jdk/pull/12923#pullrequestreview-1372019560
On Wed, 5 Apr 2023 01:48:19 GMT, David Holmes <dholmes@openjdk.org> wrote:
Renamings look good to me.
Thank you for your review! ------------- PR Comment: https://git.openjdk.org/jdk/pull/12923#issuecomment-1497209787
On Tue, 4 Apr 2023 14:39:19 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
renames
Can I please get a second review to close this one out? Thanks Markus ------------- PR Comment: https://git.openjdk.org/jdk/pull/12923#issuecomment-1503245005
On Tue, 11 Apr 2023 12:33:32 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Can I please get a second review to close this one out?
Markus, I'm still working on it and close to finish. I have some questions to ask. In fact, I gave up to prove this refactoring does not break anything. So, we should rely on testing. ------------- PR Comment: https://git.openjdk.org/jdk/pull/12923#issuecomment-1503774347
On Tue, 11 Apr 2023 16:56:49 GMT, Serguei Spitsyn <sspitsyn@openjdk.org> wrote:
Can I please get a second review to close this one out?
Markus, I'm still working on it and close to finish. I have some questions to ask. In fact, I gave up to prove this refactoring does not break anything. So, we should rely on testing.
No worries, Serguei. Thank you for taking a look, please take your time. I have run tiers 1-6. ------------- PR Comment: https://git.openjdk.org/jdk/pull/12923#issuecomment-1503779085
On Tue, 4 Apr 2023 14:39:19 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
renames
src/hotspot/share/prims/jvmtiAgent.cpp line 265:
263: // For statically linked agents we cant't rely on os_lib == nullptr because 264: // statically linked agents could have a handle of RTLD_DEFAULT which == 0 on some platforms. 265: // If this function returns true, then agent->is_static_lib().&& agent->is_loaded().
Nit: replace : ".&&" => "&&" ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1163921271
On Tue, 4 Apr 2023 14:39:19 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
renames
src/hotspot/share/prims/jvmtiAgent.cpp line 323:
321: assert(agent != nullptr, "invariant"); 322: if (!agent->is_loaded()) { 323: if (!load_agent_from_executable(agent, on_load_symbols, num_symbol_entries)) {
It feels like I'm missing something. We already checked and found at line 322 that `agent->is_loaded() == false`. Also, we have the comment at line 265: 265 // If this function returns true, then agent->is_static_lib().&& agent->is_loaded(). 266 static bool load_agent_from_executable(Agent* agent, const char* on_load_symbols[], size_t num_symbol_entries) { As the `agent->is_loaded() == false` then t he condition `agent->is_static_lib() && agent->is_loaded()` has to be `false` and can not be `true`. Then the if-check at line 323 is not needed and can be removed. Is it right? Otherwise, the comment at line 265 can be incorrect. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1163943712
On Wed, 12 Apr 2023 10:31:37 GMT, Serguei Spitsyn <sspitsyn@openjdk.org> wrote:
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
renames
src/hotspot/share/prims/jvmtiAgent.cpp line 323:
321: assert(agent != nullptr, "invariant"); 322: if (!agent->is_loaded()) { 323: if (!load_agent_from_executable(agent, on_load_symbols, num_symbol_entries)) {
It feels like I'm missing something. We already checked and found at line 322 that `agent->is_loaded() == false`. Also, we have the comment at line 265:
265 // If this function returns true, then agent->is_static_lib().&& agent->is_loaded(). 266 static bool load_agent_from_executable(Agent* agent, const char* on_load_symbols[], size_t num_symbol_entries) {
As the `agent->is_loaded() == false` then t he condition `agent->is_static_lib() && agent->is_loaded()` has to be `false` and can not be `true`. Then one of the if-checks at lines 322 and 323 is not needed and can be removed. Is it right? Otherwise, the comment at line 265 can be incorrect.
Good observation, Serguei. It is because some paths call into lookup_On_load_Entry_point() twice. It is primarily the attempted conversion of xrun agents, the first invocation comes from JvmtiAgent::convert_xrun_agent(). This will have the agent "loaded". If there is an Agent_OnLoad function, the agent is converted (i.e. xrun removed). Then when the agent is to invoke the Agent_OnLoad function, there is a second invocation. Here a converted xrun library is already loaded, so I bypass attempting to load it again by checking the is_loaded() property. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1163954754
On Wed, 12 Apr 2023 10:43:31 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
src/hotspot/share/prims/jvmtiAgent.cpp line 323:
321: assert(agent != nullptr, "invariant"); 322: if (!agent->is_loaded()) { 323: if (!load_agent_from_executable(agent, on_load_symbols, num_symbol_entries)) {
It feels like I'm missing something. We already checked and found at line 322 that `agent->is_loaded() == false`. Also, we have the comment at line 265:
265 // If this function returns true, then agent->is_static_lib().&& agent->is_loaded(). 266 static bool load_agent_from_executable(Agent* agent, const char* on_load_symbols[], size_t num_symbol_entries) {
As the `agent->is_loaded() == false` then t he condition `agent->is_static_lib() && agent->is_loaded()` has to be `false` and can not be `true`. Then one of the if-checks at lines 322 and 323 is not needed and can be removed. Is it right? Otherwise, the comment at line 265 can be incorrect.
Good observation, Serguei.
It is because some paths call into lookup_On_load_Entry_point() twice.
It is primarily the attempted conversion of xrun agents, the first invocation comes from JvmtiAgent::convert_xrun_agent(). This will have the agent "loaded". If there is an Agent_OnLoad function, the agent is converted (i.e. xrun removed).
Then when the agent is to invoke the Agent_OnLoad function, there is a second invocation. Here a converted xrun library is already loaded, so I bypass attempting to load it again by checking the is_loaded() property.
Thanks.
src/hotspot/share/prims/jvmtiAgent.cpp line 357:
355: vm_exit_during_initialization("Could not find JVM_OnLoad or Agent_OnLoad function in the library", name()); 356: } 357: _xrun = false; // converted
Just questions to understand it better. Neither `JVM_Onload` nor `Agent_Onload` entry points are stored after these lookups. It means that in order to be called later (as the comment at line 350 says) they have to be looked up again. Is it right? Was it the same originally?
The entry points are not saved and so have to be looked up again. It was the same originally.
That is why there is a check and branch on agent->is_loaded().
Thank you. I'm okay with it. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1165306181 PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1165307170
On Tue, 4 Apr 2023 14:39:19 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
renames
I've posted a couple of questions now. There can be more later. Sorry for the latency again. src/hotspot/share/prims/jvmtiAgent.cpp line 357:
355: vm_exit_during_initialization("Could not find JVM_OnLoad or Agent_OnLoad function in the library", name()); 356: } 357: _xrun = false; // converted
Just questions to understand it better. Neither `JVM_Onload` nor `Agent_Onload` entry points are stored after these lookups. It means that in order to be called later (as the comment at line 350 says) they have to be looked up again. Is it right? Was it the same originally? ------------- PR Review: https://git.openjdk.org/jdk/pull/12923#pullrequestreview-1381065121 PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1163972452
On Wed, 12 Apr 2023 11:01:43 GMT, Serguei Spitsyn <sspitsyn@openjdk.org> wrote:
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
renames
src/hotspot/share/prims/jvmtiAgent.cpp line 357:
355: vm_exit_during_initialization("Could not find JVM_OnLoad or Agent_OnLoad function in the library", name()); 356: } 357: _xrun = false; // converted
Just questions to understand it better. Neither `JVM_Onload` nor `Agent_Onload` entry points are stored after these lookups. It means that in order to be called later (as the comment at line 350 says) they have to be looked up again. Is it right? Was it the same originally?
The entry points are not saved and so have to be looked up again. It was the same originally. That is why there is a check and branch on agent->is_loaded(). ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1163979282
On Tue, 4 Apr 2023 14:39:19 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
renames
Thank you for having a look. I think I have answered them. ------------- PR Comment: https://git.openjdk.org/jdk/pull/12923#issuecomment-1505086800
On Tue, 4 Apr 2023 14:39:19 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
renames
What was the reason to clone the classes below ?: `JvmtiJavaThreadEventTransition` => `AgentJavaThreadEventTransition` `JvmtiThreadEventMark` => `AgentThreadEventMark` `JvmtiEventMark` => `AgentEventMark` ------------- PR Comment: https://git.openjdk.org/jdk/pull/12923#issuecomment-1506701619
On Thu, 13 Apr 2023 10:07:50 GMT, Serguei Spitsyn <sspitsyn@openjdk.org> wrote:
What was the reason to clone the classes below ?: `JvmtiJavaThreadEventTransition` => `AgentJavaThreadEventTransition` `JvmtiThreadEventMark` => `AgentThreadEventMark` `JvmtiEventMark` => `AgentEventMark`
The reason is they are used when invoking Agent_OnAttach. Those classes are defined in jvmtiExport.cpp, so not reachable. I considered exporting them, but it would require additional headers to be included. I opted for just replicating them, also with static linkage. ------------- PR Comment: https://git.openjdk.org/jdk/pull/12923#issuecomment-1506825122
On Tue, 4 Apr 2023 14:39:19 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
renames
Your fix introduced a hidden dependency of this new structure on the JPLISEnvironment structure and some Java agents implementation details: 202 struct JPLISEnvironmentMirror { 203 jvmtiEnv* mJVMTIEnv; // the JVMTI environment 204 const void* mAgent; // corresponding agent 205 jboolean mIsRetransformer; // indicates if special environment 206 }; It does not look good to me but I can't suggest any other approach at the moment. How important is this part? Have you considered other ways to achieve what is needed? ------------- PR Comment: https://git.openjdk.org/jdk/pull/12923#issuecomment-1506711461
On Thu, 13 Apr 2023 10:15:02 GMT, Serguei Spitsyn <sspitsyn@openjdk.org> wrote:
Your fix introduced a hidden dependency of this new structure on the JPLISEnvironment structure and some Java agents implementation details:
``` 202 struct JPLISEnvironmentMirror { 203 jvmtiEnv* mJVMTIEnv; // the JVMTI environment 204 const void* mAgent; // corresponding agent 205 jboolean mIsRetransformer; // indicates if special environment 206 }; ```
It does not look good to me but I can't suggest any other approach at the moment. How important is this part? Have you considered other ways to achieve what is needed?
Yes. It is the key to locating which JavaAgent maps to which JvmtiEnv. I tried some other variants, but those would change the layout of the exported structs in jplisAgent.h, and I don't know if people depend on that layout, implicitly or explicitly. So I choose not go down that route. This seemed the best alternative since we own jdk.instrument and the implementation on the JDK side is unlikely to change very much. ------------- PR Comment: https://git.openjdk.org/jdk/pull/12923#issuecomment-1506830279
On Tue, 4 Apr 2023 14:39:19 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
renames
src/hotspot/share/prims/jvmtiAgentList.cpp line 72:
70: // there exist an order requirement to iterate oldest -> newest. Our concurrent storage linked-list is newest -> oldest. 71: // The correct order is preserved by the iterator, by storing a filtered set of entries in a stack. 72: JvmtiAgentList::Iterator::Iterator(JvmtiAgent** list, Filter filter) : _stack(new GrowableArrayCHeap<JvmtiAgent*, mtServiceability>(16)), _filter(filter) {
Nit: It'd be nice to make the lines 69-72 shorter. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1165328661
On Thu, 13 Apr 2023 10:24:55 GMT, Serguei Spitsyn <sspitsyn@openjdk.org> wrote:
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
renames
src/hotspot/share/prims/jvmtiAgentList.cpp line 72:
70: // there exist an order requirement to iterate oldest -> newest. Our concurrent storage linked-list is newest -> oldest. 71: // The correct order is preserved by the iterator, by storing a filtered set of entries in a stack. 72: JvmtiAgentList::Iterator::Iterator(JvmtiAgent** list, Filter filter) : _stack(new GrowableArrayCHeap<JvmtiAgent*, mtServiceability>(16)), _filter(filter) {
Nit: It'd be nice to make the lines 69-72 shorter.
Ok. Fixed. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1165429976
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision: line breaks ------------- Changes: - all: https://git.openjdk.org/jdk/pull/12923/files - new: https://git.openjdk.org/jdk/pull/12923/files/d0fd9e97..85f06038 Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=16 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=15-16 Stats: 5 lines in 1 file changed: 2 ins; 0 del; 3 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk.git pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
On Thu, 13 Apr 2023 12:16:16 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
line breaks
Markus, thank you for your answers. I'm okay with it as I can't suggest anything better. These issues are local and spots are pretty small, so it is not that bad and look like reasonable compromise. ------------- PR Comment: https://git.openjdk.org/jdk/pull/12923#issuecomment-1508063709
On Thu, 13 Apr 2023 12:16:16 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
line breaks
src/hotspot/share/prims/jvmtiExport.cpp line 717:
715: jvmtiEventVMInit callback = env->callbacks()->VMInit; 716: if (callback != nullptr) { 717: JvmtiAgent* const agent = lookup_uninitialized_agent(env, reinterpret_cast<void*>(callback));
It was a surprise to me to discover this code in your changes. How can it be possible that some agents are left uninitialized at the time of VMInit event? Have you really observed this? If so, then can you add a comment explaining the need of this initialization? Is it needed for JFR purposes only? ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1166421178
On Fri, 14 Apr 2023 07:43:23 GMT, Serguei Spitsyn <sspitsyn@openjdk.org> wrote:
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
line breaks
src/hotspot/share/prims/jvmtiExport.cpp line 717:
715: jvmtiEventVMInit callback = env->callbacks()->VMInit; 716: if (callback != nullptr) { 717: JvmtiAgent* const agent = lookup_uninitialized_agent(env, reinterpret_cast<void*>(callback));
It was a surprise to me to discover this code in your changes. How can it be possible that some agents are left uninitialized at the time of VMInit event? Have you really observed this? If so, then can you add a comment explaining the need of this initialization? Is it needed for JFR purposes only?
Ok. the terminology here might be confusing. The concept of an agent being "initialized" is introduced and reported by JFR. For example, here is the JFR event type definition for a NativeAgent: ``` <Event name="NativeAgent" category="Java Virtual Machine, Diagnostics" label="Native Agent" description="A native programming language agent making use of the JVMTI interface used by development, profiling and monitoring tools" thread="false" startTime="false" period="endChunk" stackTrace="false"> <Field type="string" name="name" label="Name" /> <Field type="string" name="options" label="Options" /> <Field type="boolean" name="dynamic" label="Dynamic" description="If the library attached to the JVM dynamically during runtime, i.e. not at startup" /> <Field type="Ticks" name="initializationTime" label="Initialization Time" description="The time the JVM initialized the agent" /> <Field type="Tickspan" name="initializationDuration" label="Initialization Duration" description="The duration of executing the JVMTI VMInit event callback. If no VMInit callback is specified, the duration is 0. For a dynamically loaded agent, it is the duration of executing the call to Agent_OnAttach." /> <Field type="string" name="path" label="Path" description="The path of the library" /> </Event> As you can see, there are two fields: initializationTime and IntializationDuration. We report these to let users understand when an agent was initialized (VMInit or Agent_OnAttach), together with the duration it took to execute either. For JavaAgents, it measures the invocation and duration of the premain or agentmain methods. "Initialized" does not mean "loaded" (at this point, all agents are loaded), but rather it means the agent has received a timestamp set as a function of VMInit. This timestamp and duration are what we will report in JFR as part of the event. An "uninitialized" agent is an agent who has not yet been timestamped, as part of VMInit, for example. Since an agent can create multiple JvmtiEnvs, the function is called lookup_unitialized_agent(), because we can only have a single timestamp for an agent, but it can, in turn, have multiple JvmtiEnvs. When looking up an agent again, using a second JvmtiEnv created by it, the agent is already "initialized", so no agent is returned. We cannot have the timestamping logic as part of the call out to Agent_OnLoad, because that call happens very early during VM bootstrap, so the Ticks support structures are not yet in place. But, timing the Agent_OnLoad call would be rather meaningless because the agent cannot do much except construct a JvmtiEnv and setting capabilities and callbacks. VMInit is where most of the invocation logic, at least for JavaAgents happens, so the measurements are placed there. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1166568901
On Fri, 14 Apr 2023 09:20:18 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
src/hotspot/share/prims/jvmtiExport.cpp line 717:
715: jvmtiEventVMInit callback = env->callbacks()->VMInit; 716: if (callback != nullptr) { 717: JvmtiAgent* const agent = lookup_uninitialized_agent(env, reinterpret_cast<void*>(callback));
It was a surprise to me to discover this code in your changes. How can it be possible that some agents are left uninitialized at the time of VMInit event? Have you really observed this? If so, then can you add a comment explaining the need of this initialization? Is it needed for JFR purposes only?
Ok. the terminology here might be confusing. The concept of an agent being "initialized" is introduced and reported by JFR. For example, here is the JFR event type definition for a NativeAgent: ``` <Event name="NativeAgent" category="Java Virtual Machine, Diagnostics" label="Native Agent" description="A native programming language agent making use of the JVMTI interface used by development, profiling and monitoring tools" thread="false" startTime="false" period="endChunk" stackTrace="false"> <Field type="string" name="name" label="Name" /> <Field type="string" name="options" label="Options" /> <Field type="boolean" name="dynamic" label="Dynamic" description="If the library attached to the JVM dynamically during runtime, i.e. not at startup" /> <Field type="Ticks" name="initializationTime" label="Initialization Time" description="The time the JVM initialized the agent" /> <Field type="Tickspan" name="initializationDuration" label="Initialization Duration" description="The duration of executing the JVMTI VMInit event callback. If no VMInit callback is specified, the duration is 0. For a dynamically loaded agent, it is the duration of executing the call to Agent_OnAttach." /> <Field type="string" name="path" label="Path" description="The path of the library" /> </Event>
As you can see, there are two fields: initializationTime and IntializationDuration.
We report these to let users understand when an agent was initialized (VMInit or Agent_OnAttach), together with the duration it took to execute either. For JavaAgents, it measures the invocation and duration of the premain or agentmain methods.
"Initialized" does not mean "loaded" (at this point, all agents are loaded), but rather it means the agent has received a timestamp set as a function of VMInit. This timestamp and duration are what we will report in JFR as part of the event.
An "uninitialized" agent is an agent who has not yet been timestamped, as part of VMInit, for example. Since an agent can create multiple JvmtiEnvs, the function is called lookup_uninitialized_agent() because we can only have a single timestamp for an agent, but it can, in turn, have multiple JvmtiEnvs. When looking up an agent again, using a second JvmtiEnv created by it, the agent is already "initialized", so no agent is returned.
We cannot have the timestamping logic as part of the call out to Agent_OnLoad, because that call happens very early during VM bootstrap, so the Ticks support structures are not yet in place. But, timing the Agent_OnLoad call would be rather meaningless because the agent cannot do much except construct a JvmtiEnv and setting capabilities and callbacks.
VMInit is where most of the invocation logic, at least for JavaAgents happens, so the measurements are placed there.
Thank you for explaining it. Could you, please, add small comment explaining that it is for JFR purposes? ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1167310779
On Fri, 14 Apr 2023 22:22:13 GMT, Serguei Spitsyn <sspitsyn@openjdk.org> wrote:
Ok. the terminology here might be confusing. The concept of an agent being "initialized" is introduced and reported by JFR. For example, here is the JFR event type definition for a NativeAgent: ``` <Event name="NativeAgent" category="Java Virtual Machine, Diagnostics" label="Native Agent" description="A native programming language agent making use of the JVMTI interface used by development, profiling and monitoring tools" thread="false" startTime="false" period="endChunk" stackTrace="false"> <Field type="string" name="name" label="Name" /> <Field type="string" name="options" label="Options" /> <Field type="boolean" name="dynamic" label="Dynamic" description="If the library attached to the JVM dynamically during runtime, i.e. not at startup" /> <Field type="Ticks" name="initializationTime" label="Initialization Time" description="The time the JVM initialized the agent" /> <Field type="Tickspan" name="initializationDuration" label="Initialization Duration" description="The duration of executing the JVMTI VMInit event callback. If no VMInit callback is specified, the duration is 0. For a dynamically loaded agent, it is the duration of executing the call to Agent_OnAttach." /> <Field type="string" name="path" label="Path" description="The path of the library" /> </Event>
As you can see, there are two fields: initializationTime and IntializationDuration.
We report these to let users understand when an agent was initialized (VMInit or Agent_OnAttach), together with the duration it took to execute either. For JavaAgents, it measures the invocation and duration of the premain or agentmain methods.
"Initialized" does not mean "loaded" (at this point, all agents are loaded), but rather it means the agent has received a timestamp set as a function of VMInit. This timestamp and duration are what we will report in JFR as part of the event.
An "uninitialized" agent is an agent who has not yet been timestamped, as part of VMInit, for example. Since an agent can create multiple JvmtiEnvs, the function is called lookup_uninitialized_agent() because we can only have a single timestamp for an agent, but it can, in turn, have multiple JvmtiEnvs. When looking up an agent again, using a second JvmtiEnv created by it, the agent is already "initialized", so no agent is returned.
We cannot have the timestamping logic as part of the call out to Agent_OnLoad, because that call happens very early during VM bootstrap, so the Ticks support structures are not yet in place. But, timing the Agent_OnLoad call would be rather meaningless because the agent cannot do much except construct a JvmtiEnv and setting capabilities and callbacks.
VMInit is where most of the invocation logic, at least for JavaAgents happens, so the measurements are placed there.
Thank you for explaining it. Could you, please, add small comment explaining that it is for JFR purposes?
Will do. Thank you, Serguei. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/12923#discussion_r1168407443
On Thu, 13 Apr 2023 12:16:16 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with one additional commit since the last revision:
line breaks
Markus, It looks good to me. Overall, it is a nice consolidation of the agent code, good move in general! Thank you for your patience. I've posted one minor request though. Thanks, Serguei ------------- Marked as reviewed by sspitsyn (Reviewer). PR Review: https://git.openjdk.org/jdk/pull/12923#pullrequestreview-1384843610
On Fri, 14 Apr 2023 07:50:39 GMT, Serguei Spitsyn <sspitsyn@openjdk.org> wrote:
Markus, It looks good to me. Overall, it is a nice consolidation of the agent code, good move in general! Thank you for your patience. I've posted one minor request though. Thanks, Serguei
Thanks for taking a look Serguei, appreciate it! ------------- PR Comment: https://git.openjdk.org/jdk/pull/12923#issuecomment-1508680453
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
Markus Grönlund has updated the pull request incrementally with two additional commits since the last revision: - capital letter - explanatory comment in jvmtiExport.cpp ------------- Changes: - all: https://git.openjdk.org/jdk/pull/12923/files - new: https://git.openjdk.org/jdk/pull/12923/files/85f06038..140079c7 Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=17 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=12923&range=16-17 Stats: 2 lines in 1 file changed: 2 ins; 0 del; 0 mod Patch: https://git.openjdk.org/jdk/pull/12923.diff Fetch: git fetch https://git.openjdk.org/jdk.git pull/12923/head:pull/12923 PR: https://git.openjdk.org/jdk/pull/12923
On Wed, 8 Mar 2023 12:41:15 GMT, Markus Grönlund <mgronlun@openjdk.org> wrote:
Greetings,
We are adding support to let JFR report on Agents.
#### Design
An Agent is a library that uses any instrumentation or profiling APIs. Most agents are started and initialized on the command line, but agents can also be loaded dynamically during runtime. Because command line agents initialize during the VM startup sequence, they add to the overall startup time latency in getting the VM ready. The events will report on the time the agent took to initialize.
A JavaAgent is an agent written in the Java programming language, using the APIs in the package [java.lang.instrument](https://docs.oracle.com/en/java/javase/19/docs/api/java.instrument/java/lang...)
A JavaAgent is sometimes called a JPLIS agent, where the acronym JPLIS stands for Java Programming Language Instrumentation Services.
To report on JavaAgents, JFR will add the new event type jdk.JavaAgent and events will look similar to these two examples:
// Command line jdk.JavaAgent { startTime = 12:31:19.789 (2023-03-08) name = "JavaAgent.jar" options = "foo=bar" dynamic = false initializationTime = 12:31:15.574 (2023-03-08) initializationDuration = 172 ms }
// Dynamic load jdk.JavaAgent { startTime = 12:31:31.158 (2023-03-08) name = "JavaAgent.jar" options = "bar=baz" dynamic = true initializationTime = 12:31:31.037 (2023-03-08) initializationDuration = 64,1 ms }
The jdk.JavaAgent event type is a JFR periodic event that iterates over running Java agents.
For a JavaAgent event, the agent's name will be the specific .jar file containing the instrumentation code. The options will be the specific options passed to the .jar file as part of launching the agent, for example, on the command line: -javaagent: JavaAgent.jar=foo=bar.
The "dynamic" field denotes if the agent was loaded via the command line (dynamic = false) or dynamically (dynamic = true)
"initializationTime" is the timestamp the JVM invoked the initialization method, and "initializationDuration" is the duration of executing the initialization method.
"startTime" represents the time the JFR framework issued the periodic event; hence "initializationTime" will be earlier than "startTime".
An agent can also be written in a native programming language using the [JVM Tools Interface (JVMTI)](https://docs.oracle.com/en/java/javase/19/docs/specs/jvmti.html). This kind of agent, sometimes called a native agent, is a platform-specific binary, sometimes referred to as a library, but here it means a .so or .dll file.
To report on native agents, JFR will add the new event type jdk.NativeAgent and events will look similar to this example:
jdk.NativeAgent { startTime = 12:31:40.398 (2023-03-08) name = "jdwp" options = "transport=dt_socket,server=y,address=any,onjcmd=y" dynamic = false initializationTime = 12:31:36.142 (2023-03-08) initializationDuration = 0,00184 ms path = "c:\ade\github\openjdk\jdk\build\windows-x86_64-server-slowdebug\jdk\bin\jdwp.dll" }
The layout of the event type is very similar to the jdk.JavaAgent event, but here the path to the native library is reported.
The initialization of a native agent is performed by invoking an agent-specified callback routine. The "initializationTime" is when the JVM sent or would have sent the JVMTI VMInit event to a specified callback. "initializationDuration" is the duration to execute that specific callback. If no callback is specified for the JVMTI VMInit event, the "initializationDuration" will be 0. If the agent is loaded dynamically, "initializationDuration" is the time taken to execute the Agent_OnAttach callback.
#### Implementation
There has not existed a reification of a JavaAgent directly in the JVM, as these are built on top of the JDK native library, "instrument", using a many-to-one mapping. At the level of the JVM, the only representation of agents after startup is through JvmtiEnv's, which agents request from the JVM during startup and initialization — as such, mapping which JvmtiEnv belongs to what JavaAgent was not possible before.
Using implementation details of how the JDK native library "instrument" interacts with the JVM, we can build this mapping to track what JvmtiEnv's "belong" to what JavaAgent. This mapping now lets us report the Java-relevant context (name, options) and measure the time it takes for the JavaAgent to initialize.
When implementing this capability, it was necessary to refactor the code used to represent agents, AgentLibrary. The previous implementation was located primarily in arguments.cpp, and threads.cpp but also jvmtiExport.cpp.
The refactoring isolates the relevant logic into two new modules, prims/agent.hpp and prims/agentList.hpp. Breaking out this code from their older places will help reduce the sizes of oversized arguments.cpp and threads.cpp.
The previous two lists that maintained "agents" (JVMTI) and "libraries" (Xrun) were not thread-safe for concurrent iterations. A single list that allows for concurrent iterations is therefore introduced.
Testing: jdk_jfr, tier 1 - 6
Thanks Markus
This pull request has now been integrated. Changeset: 5c95bb1c Author: Markus Grönlund <mgronlun@openjdk.org> URL: https://git.openjdk.org/jdk/commit/5c95bb1c5146e13dd213d5ca6e02e2a02ca0323e Stats: 1893 lines in 23 files changed: 1375 ins; 487 del; 31 mod 8257967: JFR: Events for loaded agents Reviewed-by: dholmes, sspitsyn ------------- PR: https://git.openjdk.org/jdk/pull/12923
participants (5)
-
Andrew Dinn
-
Bernd
-
David Holmes
-
Markus Grönlund
-
Serguei Spitsyn