diff --git a/fireplace-app/src/main/java/io/github/bric3/fireplace/jfr/tree/Node.java b/fireplace-app/src/main/java/io/github/bric3/fireplace/jfr/tree/Node.java index 1c198397..05f561b6 100644 --- a/fireplace-app/src/main/java/io/github/bric3/fireplace/jfr/tree/Node.java +++ b/fireplace-app/src/main/java/io/github/bric3/fireplace/jfr/tree/Node.java @@ -1,3 +1,36 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Datadog, Inc. All rights reserved. + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The contents of this file are subject to the terms of either the Universal Permissive License + * v 1.0 as shown at http://oss.oracle.com/licenses/upl + * + * or the following license: + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided with + * the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.github.bric3.fireplace.jfr.tree; import org.openjdk.jmc.flightrecorder.stacktrace.tree.AggregatableFrame; diff --git a/fireplace-app/src/main/java/io/github/bric3/fireplace/jfr/tree/StacktraceButterflyModel.java b/fireplace-app/src/main/java/io/github/bric3/fireplace/jfr/tree/StacktraceButterflyModel.java index 424f28b7..2fbcdbf5 100644 --- a/fireplace-app/src/main/java/io/github/bric3/fireplace/jfr/tree/StacktraceButterflyModel.java +++ b/fireplace-app/src/main/java/io/github/bric3/fireplace/jfr/tree/StacktraceButterflyModel.java @@ -106,26 +106,27 @@ private static void findPredecessors( ) { // if there's a match add children nodes if (nodeSelector.test(node.getFrame())) { - Node predecessorsRootNode = getOrCreateFocusedMethodNode(predecessorsRoot, node.getFrame()); + Node focusedFrame = getOrCreateFocusedMethodNode(predecessorsRoot, node.getFrame()); - predecessorsRootNode.weight += node.getWeight(); - predecessorsRootNode.cumulativeWeight += node.getCumulativeWeight(); + // Only capturing the total of the focused frame (cumulative weight) to + // compute the impact on the predecssors + double focusedFrameCumulativeWeight = node.getCumulativeWeight(); + focusedFrame.weight += focusedFrameCumulativeWeight; + focusedFrame.cumulativeWeight += focusedFrameCumulativeWeight; // Adds and merge predecessors in the callers tree - Node predecessorNode = predecessorsRootNode; + Node currentPredecessor = focusedFrame; for ( org.openjdk.jmc.flightrecorder.stacktrace.tree.Node currentNode = node.getParent(); - currentNode != null && currentNode.getParent() != null; + currentNode != null && !currentNode.isRoot(); currentNode = currentNode.getParent() ) { - if (currentNode.getParent().isRoot()) { - continue; - } - - Node child = getOrCreateNode(predecessorNode, currentNode.getFrame()); - child.weight += currentNode.getWeight(); - child.cumulativeWeight += currentNode.getCumulativeWeight(); - predecessorNode = child; + Node predecessor = getOrCreateNode(currentPredecessor, currentNode.getFrame()); + // The amount of weight the focused frame has on predecessors in the back trace + predecessor.weight += focusedFrameCumulativeWeight; + // The total amount of work done by the predecessors + predecessor.cumulativeWeight += currentNode.getCumulativeWeight(); + currentPredecessor = predecessor; } } @@ -161,10 +162,10 @@ private static void findSuccessors( ) { // if there's a match add children nodes if (nodeSelector.test(node.getFrame())) { - Node successorsRootNode = getOrCreateFocusedMethodNode(successorsRoot, node.getFrame()); - successorsRootNode.weight += node.getWeight(); - successorsRootNode.cumulativeWeight += node.getCumulativeWeight(); - convertAndAddChildren(successorsRootNode, node); + Node focusedFrame = getOrCreateFocusedMethodNode(successorsRoot, node.getFrame()); + focusedFrame.weight += node.getWeight(); + focusedFrame.cumulativeWeight += node.getCumulativeWeight(); + convertAndAddChildren(focusedFrame, node); } // regardless look for matching nodes in children for (org.openjdk.jmc.flightrecorder.stacktrace.tree.Node child : node.getChildren()) { @@ -217,15 +218,18 @@ private static void mergeChildren(Node node) { node.children.addAll(childrenMap.values()); } - private static void convertAndAddChildren(Node successorsRootNode, org.openjdk.jmc.flightrecorder.stacktrace.tree.Node node) { + private static void convertAndAddChildren(Node successorsParentNode, org.openjdk.jmc.flightrecorder.stacktrace.tree.Node node) { List list = new ArrayList<>(); for (org.openjdk.jmc.flightrecorder.stacktrace.tree.Node child : node.getChildren()) { - Node jmcTreeNode = toJmcTreeNode(successorsRootNode, child); + Node jmcTreeNode = toJmcTreeNode(successorsParentNode, child); list.add(jmcTreeNode); } - successorsRootNode.children.addAll(list); + successorsParentNode.children.addAll(list); } + /* + * Unfortunately it is required to convert the nodes since this class live in a different package. + */ private static Node toJmcTreeNode(Node convertedParent, org.openjdk.jmc.flightrecorder.stacktrace.tree.Node node) { Node converted = new Node( convertedParent, @@ -238,10 +242,31 @@ private static Node toJmcTreeNode(Node convertedParent, org.openjdk.jmc.flightre return converted; } + /** + * Returns the root node of the successors tree. + * The successors tree is a regular flamegraph whose root is the focused frame. + *