On Thu, 30 Mar 2023 19:20:11 GMT, Markus Grönlund <mgron...@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/instrument/package-summary.html)
>> 
>> 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

Reply via email to