Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GR-58656] Streamline Native Image Agent Output #9812

Open
vjovanov opened this issue Oct 3, 2024 · 0 comments
Open

[GR-58656] Streamline Native Image Agent Output #9812

vjovanov opened this issue Oct 3, 2024 · 0 comments
Assignees
Labels

Comments

@vjovanov
Copy link
Member

vjovanov commented Oct 3, 2024

TL;DR

The Native Image Agent produces superfluous reachability metadata entries. Superfluous entries come from the following sources:

  1. The agent outputs entries that were already registered in META-INF/native-image/**/reachability-metadata.json.
  2. The agent outputs entries for metadata that is inferred by Native Image. For example, the entry for Class.forName("Foo") is produced although Native Image requires no entry to execute the given code.
  3. The agent outputs some of the entries from the JDK itself that are not needed by Native Image.

Superfluous metadata entries are making it difficult to understand and integrate agent output into existing metadata. On the example of Spring PetClinic, if the end user adds one reflective call, the metadata agent will output more than 10000 entries. This will make it very hard to find the new entry that is actually required.

This ticket aims to modify the agent to output only non-existing entries (1) only for entries that are not needed by Native Image (2), while ignoring parts of the JDK that are not used by Native Image.

Goals

  1. Make the agent output directly applicable to existing projects.
  2. Make it easy to see the entries needed for a given application.
  3. Avoid including unnecessary classes and methods that were seen by the agent that are not needed by Natve Image.

Non-goals

  1. Make the agent slower.
  2. Make the agent non-functional for some projects.

Implementation

Differential Agent Output

At startup, the agent needs to load all metadata from the classpath and store it internally into com.oracle.svm.configure.config.ConfigurationSet.

Then, when printing the output all of the collected metadata should be subtracted from the initial metadata. Note that metadata as a whole supports the subtraction operation.

Dynamic Scope For Disabling Agent Functionality

Before startup, the agent should define a class that allows to open a dynamic scope during execution. This class should be defined in java.base and exported to every possible class. The class should look like:

package java.nativeimage.internal.agent;

public class NativeImageAgentDisable implements AutoClosable {
    private static ThreadLocal<Integer> depth;

    public static boolean isScopeOpen() {
        return depth.get() != null && depth.get() > 0;
    }

    public static NativeImageAgentDisable openScope() {
        var current = depth.get();
        if (current == null) {
            current = 0;
        }
        current += 1;
        depth.set(current);
        return new NativeImageAgentDisable();
    }

    public void close() {
        var current = depth.get();
        if (current != null) {
            if (current <= 1) {
                depth.remove();
            } else {
                depth.set(current - 1);
            }
        }
    }
}

The agent will have to check for each entry if NativeImageAgentDisable.isScopeOpen() returns true. If this turns out to be too slow, the thread local will have to moved into the agent implementation.

The example usage of the scoping mechanism would look like:

try (var scope = NativeImageAgentDisable.openScope()) {
  // part of the code for which we don't want to track reflection 
}

Unified Metadata Inference Across Native Image and the Agent

Native Image metadata inference is performed based on an unknown set of rules in the Graal compiler. The general rule is that if a compiler can make reflective operation's arguments constant then we don't need metadata for that operation.

There is an effort to make the set of rules for metadata inference explicit and implemented with a Java agent that transforms bytecode.

We need to adopt that Java agent that works together with the Native Image agent such that the Java agent opens a scope for every operation that is inferred in the bytecode. By opening scopes around inferred operations the agent will not output entries that are inferred in the bytecode.

An example of a transformation would be to transform

Class.forName("AClass").getMethod("aMethod")

into the following:

try (var scope = NativeImageAgentDisable.openScope()) {
    AClass.class.getMethod("aMethod")
}

Access Filters for the JDK

The agent currently uses access filters to filter out entries from the JDK. These filters are incomplete and in many cases don't catch some entries that are necessary.

We need to minimize those filters by using the above-described mechanisms:

  1. We need to introduce dynamic scopes for operations on method handles, on LambdaMetaFactory, etc.
  2. By providing metadata for the JDK so that existing entries don't show up with the differential mode.

In addition, the whole process of recording the metadata entries should only start with the main function. We can do that by opening a scope in the main thread and closing it right before the main starts.

@vjovanov vjovanov self-assigned this Oct 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: No status
Development

No branches or pull requests

1 participant