All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oracle.truffle.tools.profiler.ProfilerNode Maven / Gradle / Ivy

/*
 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.oracle.truffle.tools.profiler;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;

import com.oracle.truffle.api.instrumentation.StandardTags.ExpressionTag;
import com.oracle.truffle.api.instrumentation.StandardTags.RootTag;
import com.oracle.truffle.api.instrumentation.StandardTags.StatementTag;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.SourceSection;

/**
 * Represents a node in the call tree built up by sampling the stack. Additional data can be
 * attached to this class through the template parameter, allowing individual tools to attach needed
 * data to the call tree.
 *
 * @param  The type of data that should be associated with this node.
 * @since 0.30
 */
public final class ProfilerNode {

    ProfilerNode(ProfilerNode parent, StackTraceEntry sourceLocation, T payload) {
        this.parent = parent;
        this.sourceLocation = sourceLocation;
        this.payload = payload;
    }

    ProfilerNode() {
        this.parent = null;
        this.sourceLocation = null;
        this.payload = null;
    }

    private final T payload;
    private final ProfilerNode parent;
    private final StackTraceEntry sourceLocation;
    Map> children;

    /**
     * @return the children of this {@link ProfilerNode}
     * @since 0.30
     */
    public Collection> getChildren() {
        if (children == null) {
            return Collections.emptyList();
        }
        return Collections.unmodifiableCollection(children.values());
    }

    /**
     * @return the parent of this {@link ProfilerNode}
     * @since 0.30
     */
    public ProfilerNode getParent() {
        return parent;
    }

    /**
     * @return true if the parent chain contains a {@link ProfilerNode} with the same
     *         {@link StackTraceEntry}, otherwise false
     * @since 0.30
     */
    public boolean isRecursive() {
        return isRecursiveImpl(this);
    }

    private boolean isRecursiveImpl(ProfilerNode source) {
        if (parent.sourceLocation == null) {
            return false;
        }
        if (parent.sourceLocation.equals(source.sourceLocation)) {
            return true;
        }
        return parent.isRecursiveImpl(source);
    }

    /**
     * @return the {@link SourceSection} associated with this {@link ProfilerNode}
     * @since 0.30
     */
    public SourceSection getSourceSection() {
        return sourceLocation.getSourceSection();
    }

    /**
     * @return The name of the {@linkplain RootNode root node} in which this {@link ProfilerNode}
     *         appears.
     * @since 0.30
     */
    public String getRootName() {
        return sourceLocation.getRootName();
    }

    /**
     * Returns a set tags a stack location marked with. Common tags are {@link RootTag root},
     * {@link StatementTag statement} and {@link ExpressionTag expression}. Whether statement or
     * expression stack trace entries appear depends on the configured
     * {@link CPUSampler#setFilter(com.oracle.truffle.api.instrumentation.SourceSectionFilter)
     * filter}.
     *
     * @since 0.30
     */
    public Set> getTags() {
        return sourceLocation.getTags();
    }

    /**
     * @return The additional information attached to this node through the template parameter
     * @since 0.30
     */
    public T getPayload() {
        return payload;
    }

    ProfilerNode findChild(StackTraceEntry childLocation) {
        if (children != null) {
            return children.get(childLocation);
        }
        return null;
    }

    void addChild(StackTraceEntry childLocation, ProfilerNode child) {
        if (children == null) {
            children = new HashMap<>();
        }
        children.put(childLocation, child);
    }

    StackTraceEntry getSourceLocation() {
        return sourceLocation;
    }

    void deepCopyChildrenFrom(ProfilerNode node, Function copyPayload) {
        for (ProfilerNode child : node.getChildren()) {
            final StackTraceEntry childSourceLocation = child.getSourceLocation();
            T childPayload = child.getPayload();
            T destinationPayload = copyPayload.apply(childPayload);
            ProfilerNode destinationChild = new ProfilerNode<>(this, childSourceLocation, destinationPayload);
            if (children == null) {
                children = new HashMap<>();
            }
            children.put(childSourceLocation, destinationChild);
            destinationChild.deepCopyChildrenFrom(child, copyPayload);
        }
    }

    void deepMergeChildrenFrom(ProfilerNode node, BiConsumer mergePayload, Supplier payloadFactory) {
        for (ProfilerNode child : node.getChildren()) {
            final StackTraceEntry childSourceLocation = child.getSourceLocation();
            final T childPayload = child.getPayload();
            ProfilerNode destinationChild = findBySourceLocation(childSourceLocation);
            if (destinationChild == null) {
                T destinationPayload = payloadFactory.get();
                mergePayload.accept(childPayload, destinationPayload);
                destinationChild = new ProfilerNode<>(this, childSourceLocation, destinationPayload);
                if (children == null) {
                    children = new HashMap<>();
                }
                children.put(childSourceLocation, destinationChild);
            } else {
                mergePayload.accept(childPayload, destinationChild.getPayload());
            }
            destinationChild.deepMergeChildrenFrom(child, mergePayload, payloadFactory);
        }
    }

    void deepMergeNodeToChildren(ProfilerNode node, BiConsumer mergePayload, Supplier payloadFactory) {
        final StackTraceEntry childSourceLocation = node.getSourceLocation();
        final T childPayload = node.getPayload();
        ProfilerNode destinationChild = findBySourceLocation(childSourceLocation);
        if (destinationChild == null) {
            T destinationPayload = payloadFactory.get();
            mergePayload.accept(childPayload, destinationPayload);
            destinationChild = new ProfilerNode<>(this, childSourceLocation, destinationPayload);
            if (children == null) {
                children = new HashMap<>();
            }
            children.put(childSourceLocation, destinationChild);
        } else {
            mergePayload.accept(childPayload, destinationChild.getPayload());
        }
        destinationChild.deepMergeChildrenFrom(node, mergePayload, payloadFactory);
    }

    private ProfilerNode findBySourceLocation(StackTraceEntry targetSourceLocation) {
        if (children != null) {
            for (ProfilerNode child : children.values()) {
                if (child.getSourceLocation().equals(targetSourceLocation)) {
                    return child;
                }
            }
        }
        return null;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy