123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- /*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
- package io.opentelemetry.javaagent.benchmark.jfr;
- import java.io.File;
- import java.util.Comparator;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.Objects;
- import java.util.Set;
- import java.util.stream.Collectors;
- import javax.annotation.Nullable;
- import jdk.jfr.consumer.RecordedEvent;
- import jdk.jfr.consumer.RecordedFrame;
- import jdk.jfr.consumer.RecordedMethod;
- import jdk.jfr.consumer.RecordedStackTrace;
- import jdk.jfr.consumer.RecordingFile;
- @SuppressWarnings("SystemOut")
- public class Analyzer {
- private static final Node syntheticRootNode = new Node("");
- private static int totalSamples = 0;
- public static void main(String[] args) throws Exception {
- File jfrFile = new File(args[0]);
- List<RecordedEvent> events =
- RecordingFile.readAllEvents(jfrFile.toPath()).stream()
- .filter(e -> e.getEventType().getName().equals("jdk.ExecutionSample"))
- .collect(Collectors.toList());
- Set<String> agentCallers = getAgentCallers(events);
- for (RecordedEvent event : events) {
- totalSamples++;
- processStackTrace(event.getStackTrace(), agentCallers);
- }
- int totalAgentSamples = 0;
- for (Node rootNode : syntheticRootNode.getOrderedChildNodes()) {
- totalAgentSamples += rootNode.count;
- }
- System.out.println("Total samples: " + totalSamples);
- System.out.print("Total agent samples: " + totalAgentSamples);
- System.out.format(" (%.2f%%)%n", 100 * totalAgentSamples / (double) totalSamples);
- System.out.println();
- for (Node rootNode : syntheticRootNode.getOrderedChildNodes()) {
- printNode(rootNode, 0);
- }
- }
- // getting direct callers since those are likely the instrumented methods
- private static Set<String> getAgentCallers(List<RecordedEvent> events) {
- return events.stream()
- .map(e -> getAgentCaller(e.getStackTrace()))
- .filter(Objects::nonNull)
- .collect(Collectors.toSet());
- }
- @Nullable
- private static String getAgentCaller(RecordedStackTrace stackTrace) {
- List<RecordedFrame> frames = stackTrace.getFrames();
- for (int i = frames.size() - 1; i >= 0; i--) {
- RecordedFrame frame = frames.get(i);
- RecordedMethod method = frame.getMethod();
- if (isAgentMethod(method)) {
- RecordedFrame callerFrame = frames.get(i + 1);
- RecordedMethod callerMethod = callerFrame.getMethod();
- return getStackTraceElement(callerMethod, callerFrame);
- }
- }
- return null;
- }
- private static void printNode(Node node, int indent) {
- for (int i = 0; i < indent; i++) {
- System.out.print(" ");
- }
- System.out.format("%3d %s%n", node.count, node.frame);
- for (Node childNode : node.getOrderedChildNodes()) {
- printNode(childNode, indent + 1);
- }
- }
- private static void processStackTrace(RecordedStackTrace stackTrace, Set<String> agentCallers) {
- boolean analyze = false;
- int analyzeFromIndex = 0;
- List<RecordedFrame> frames = stackTrace.getFrames();
- for (int i = frames.size() - 1; i >= 0; i--) {
- RecordedFrame frame = frames.get(i);
- RecordedMethod method = frame.getMethod();
- String stackTraceElement = getStackTraceElement(method, frame);
- if (agentCallers.contains(stackTraceElement)) {
- if (i == 0) {
- analyze = true;
- analyzeFromIndex = i;
- break;
- }
- RecordedMethod nextMethod = frames.get(i - 1).getMethod();
- String nextClassName = nextMethod.getType().getName();
- // calls to java.* inside of the agent caller (likely an instrumented method) are
- // potentially part of the injected agent code
- if (nextClassName.startsWith("java.") || isAgentMethod(nextMethod)) {
- analyze = true;
- analyzeFromIndex = Math.min(i + 2, frames.size() - 1);
- break;
- }
- }
- if (isAgentMethod(method)) {
- analyze = true;
- analyzeFromIndex = Math.min(i + 1, frames.size() - 1);
- break;
- }
- }
- if (!analyze) {
- return;
- }
- Node node = syntheticRootNode;
- for (int i = analyzeFromIndex; i >= 0; i--) {
- RecordedFrame frame = frames.get(i);
- RecordedMethod method = frame.getMethod();
- String stackTraceElement = getStackTraceElement(method, frame);
- node = node.recordChildSample(stackTraceElement);
- }
- }
- private static boolean isAgentMethod(RecordedMethod method) {
- String className = method.getType().getName();
- String methodName = method.getName();
- return className.startsWith("io.opentelemetry.javaagent.")
- && !className.startsWith("io.opentelemetry.javaagent.benchmark.")
- // this shows up in stack traces because it's part of the filter chain
- && !(className.equals(
- "io.opentelemetry.javaagent.instrumentation.springwebmvc.HandlerMappingResourceNameFilter")
- && methodName.equals("doFilter"));
- }
- private static String getStackTraceElement(RecordedMethod method, RecordedFrame frame) {
- return method.getType().getName()
- + "."
- + method.getName()
- + "() line: "
- + frame.getLineNumber();
- }
- private static class Node {
- private final String frame;
- private final Map<String, Node> childNodes = new HashMap<>();
- private int count;
- private Node(String frame) {
- this.frame = frame;
- }
- private Node recordChildSample(String stackTraceElement) {
- Node childNode = childNodes.get(stackTraceElement);
- if (childNode == null) {
- childNode = new Node(stackTraceElement);
- childNodes.put(stackTraceElement, childNode);
- }
- childNode.count++;
- return childNode;
- }
- private List<Node> getOrderedChildNodes() {
- return childNodes.values().stream()
- .sorted(Comparator.comparingInt(Node::getCount).reversed())
- .collect(Collectors.toList());
- }
- private int getCount() {
- return count;
- }
- }
- private Analyzer() {}
- }
|