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-50840] Try to use calltree for call traces. #8082

Merged
merged 1 commit into from
Dec 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ public final class CallTreeInfo {
private final Map<AnalysisMethod, RuntimeCompiledMethod> runtimeCompilations;
private Map<RuntimeCompilationCandidate, InvokeNode> runtimeCandidateMap;
private Map<AnalysisMethod, MethodNode> analysisMethodMap;
private boolean callTreeInitialized = false;
private boolean callTraceInitialized = false;
private boolean initialized = false;

private CallTreeInfo(Map<AnalysisMethod, RuntimeCompiledMethod> runtimeCompilations) {
this.runtimeCompilations = runtimeCompilations;
Expand Down Expand Up @@ -82,12 +81,7 @@ public static CallTreeInfo create(AnalysisUniverse aUniverse, Map<AnalysisMethod
return new CallTreeInfo(runtimeCompilations);
}

private void initializeCallTraceInfo() {
if (callTraceInitialized) {
return;
}

callTraceInitialized = true;
private void initializeCallerInfo() {
analysisMethodMap = new HashMap<>();
runtimeCandidateMap = new HashMap<>();

Expand Down Expand Up @@ -131,22 +125,22 @@ private void initializeCallTraceInfo() {
}
}

public void initializeCallTreeInfo(Set<AnalysisMethod> registeredRoots) {
if (callTreeInitialized) {
public void initialize(Set<AnalysisMethod> registeredRoots) {
if (initialized) {
return;
}

initializeCallTraceInfo();
callTreeInitialized = true;
initializeCallerInfo();
initialized = true;

// ensure invokeInfo calculated

Queue<MethodNode> worklist = new LinkedList<>();
/*
* First initialize all nodes with no callers.
* First initialize all nodes which are registered roots
*/
for (var methodNode : analysisMethodMap.values()) {
if (methodNode.getCallers().isEmpty() || registeredRoots.contains(methodNode.method.getMultiMethod(ORIGINAL_METHOD))) {
if (registeredRoots.contains(methodNode.method.getMultiMethod(ORIGINAL_METHOD))) {
worklist.add(methodNode);
methodNode.trace = new TraceInfo(0, new BytecodePosition(null, methodNode.method, BytecodeFrame.UNKNOWN_BCI), null);
}
Expand Down Expand Up @@ -189,8 +183,8 @@ public void initializeCallTreeInfo(Set<AnalysisMethod> registeredRoots) {
private static final String[] UNKNOWN_TRACE = new String[]{"Unknown"};
private static final String[] EMPTY_STRING = new String[0];

public static String[] getCallTrace(CallTreeInfo callTreeInfo, AnalysisMethod method) {
callTreeInfo.initializeCallTraceInfo();
static String[] getCallTrace(CallTreeInfo callTreeInfo, AnalysisMethod method, Set<AnalysisMethod> registeredRuntimeCompilations) {
callTreeInfo.initialize(registeredRuntimeCompilations);
MethodNode methodNode = callTreeInfo.analysisMethodMap.get(method);
if (methodNode == null) {
return UNKNOWN_TRACE;
Expand All @@ -201,8 +195,8 @@ public static String[] getCallTrace(CallTreeInfo callTreeInfo, AnalysisMethod me
return trace.toArray(EMPTY_STRING);
}

public static String[] getCallTrace(CallTreeInfo callTreeInfo, RuntimeCompilationCandidate candidate) {
callTreeInfo.initializeCallTraceInfo();
static String[] getCallTrace(CallTreeInfo callTreeInfo, RuntimeCompilationCandidate candidate, Set<AnalysisMethod> registeredRuntimeCompilations) {
callTreeInfo.initialize(registeredRuntimeCompilations);
InvokeNode invokeNode = callTreeInfo.runtimeCandidateMap.get(candidate);
if (invokeNode == null) {
return UNKNOWN_TRACE;
Expand All @@ -214,26 +208,48 @@ public static String[] getCallTrace(CallTreeInfo callTreeInfo, RuntimeCompilatio
}

private static void findCallTraceHelper(ArrayList<String> trace, MethodNode first) {
Set<MethodNode> covered = new HashSet<>();
MethodNode current = first;
covered.add(current);

while (current != null) {
// find parent
MethodNode parent = null;
for (InvokeNode caller : current.getCallers()) {
if (covered.add(caller.method)) {
if (first.trace != null) {
/*
* If there is a known trace from root, then we can return this
*/
MethodNode current = first;
while (current != null) {
MethodNode parent = null;
InvokeNode caller = current.trace.invokeParent;
if (caller != null) {
parent = caller.method;
trace.add(caller.position.toString());
break;
}
current = parent;
}
trace.add("[Root]");

} else {
/*
* Otherwise we will walk an arbitrary caller until there is not a caller or we
* encounter a cycle.
*/
Set<MethodNode> covered = new HashSet<>();
MethodNode current = first;
covered.add(current);

while (current != null) {
// find parent
MethodNode parent = null;
for (InvokeNode caller : current.getCallers()) {
if (covered.add(caller.method)) {
parent = caller.method;
trace.add(caller.position.toString());
break;
}
}
current = parent;
}
current = parent;
}
}

public static void printCallTree(CallTreeInfo info, Set<AnalysisMethod> registeredRuntimeCompilations) {
info.initializeCallTreeInfo(registeredRuntimeCompilations);
info.initialize(registeredRuntimeCompilations);

System.out.println("depth;method;invoke position");
for (MethodNode methodNode : info.analysisMethodMap.values()) {
Expand All @@ -255,7 +271,7 @@ private static void printCallTreeNode(MethodNode node) {
}

public static void printDeepestPath(CallTreeInfo info, Set<AnalysisMethod> registeredRuntimeCompilations) {
info.initializeCallTreeInfo(registeredRuntimeCompilations);
info.initialize(registeredRuntimeCompilations);

Optional<MethodNode> deepestNode = info.analysisMethodMap.values().stream().max(Comparator.comparingInt(t -> t.trace == null ? -1 : t.trace.level));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,14 @@ public void initializeAnalysisProviders(BigBang bb, Function<ConstantFieldProvid
analysisProviders = customHostedProviders;
}

public String[] getCallTrace(CallTreeInfo callTreeInfo, AnalysisMethod method) {
return CallTreeInfo.getCallTrace(callTreeInfo, method, registeredRuntimeCompilations);
}

public String[] getCallTrace(CallTreeInfo callTreeInfo, RuntimeCompilationCandidate candidate) {
return CallTreeInfo.getCallTrace(callTreeInfo, candidate, registeredRuntimeCompilations);
}

public CallTreeInfo getCallTreeInfo() {
VMError.guarantee(callTreeMetadata != null);
return callTreeMetadata;
Expand Down Expand Up @@ -577,7 +585,7 @@ public void reportAnalysisError(AnalysisUniverse aUniverse, Throwable t) {
System.out.println("Parsing failed on a special method version: " + errorMethod.format("%H.%n"));
System.out.println("Method reachability trace");
if (failingRuntimeMethod != null) {
Arrays.stream(CallTreeInfo.getCallTrace(treeInfo, failingRuntimeMethod)).forEach(System.out::println);
Arrays.stream(CallTreeInfo.getCallTrace(treeInfo, failingRuntimeMethod, registeredRuntimeCompilations)).forEach(System.out::println);
} else {
System.out.println("trace unavailable");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,7 @@ private void checkBlockList(CallTreeInfo treeInfo) {
tempTargetAllowlistMethods.contains(candidate.getTargetMethod()) &&
!isBlocklisted(candidate.getImplementationMethod());
if (!tempAllow) {
BlocklistViolationInfo violation = new BlocklistViolationInfo(candidate, CallTreeInfo.getCallTrace(treeInfo, candidate));
BlocklistViolationInfo violation = new BlocklistViolationInfo(candidate, runtimeCompilation.getCallTrace(treeInfo, candidate));
blocklistViolations.add(violation);
}
}
Expand Down Expand Up @@ -846,7 +846,7 @@ private void checkBlockList(CallTreeInfo treeInfo) {
for (RuntimeCompilationCandidate violation : warnViolations) {
System.out.println("Suspicious method: " + violation.getImplementationMethod().format("%H.%n(%p)"));
System.out.println("trace:");
for (String item : CallTreeInfo.getCallTrace(treeInfo, violation)) {
for (String item : runtimeCompilation.getCallTrace(treeInfo, violation)) {
System.out.println(" " + item);
}
}
Expand All @@ -857,7 +857,7 @@ private void checkBlockList(CallTreeInfo treeInfo) {
for (Pair<ResolvedJavaMethod, String> violation : neverPartOfCompilationViolations) {
System.out.println("called from");
System.out.println("(inlined call path): " + violation.getRight());
for (String item : CallTreeInfo.getCallTrace(treeInfo, (AnalysisMethod) violation.getLeft())) {
for (String item : runtimeCompilation.getCallTrace(treeInfo, (AnalysisMethod) violation.getLeft())) {
System.out.println(" " + item);
}
}
Expand Down