com.griddynamics.jagger.diagnostics.thread.sampling.RuntimeGraph.java Source code

Java tutorial

Introduction

Here is the source code for com.griddynamics.jagger.diagnostics.thread.sampling.RuntimeGraph.java

Source

/*
 * Copyright (c) 2010-2012 Grid Dynamics Consulting Services, Inc, All Rights Reserved
 * http://www.griddynamics.com
 *
 * This library is free software; you can redistribute it and/or modify it under the terms of
 * the GNU Lesser General Public License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * 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 OWNER 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 com.griddynamics.jagger.diagnostics.thread.sampling;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.MinMaxPriorityQueue;
import com.google.common.primitives.Longs;
import edu.uci.ics.jung.graph.DirectedGraph;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.Graph;

import java.io.Serializable;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

public class RuntimeGraph implements Serializable {

    private static final Method pseudoRoot = new Method("#", "#");

    private long observations = 0;

    private DirectedGraph<MethodStatistics, Invocation> graph = new DirectedSparseGraph<MethodStatistics, Invocation>();
    private Map<Method, MethodStatistics> methodIndex = Maps.newHashMap();

    private List<Pattern> includePatterns;
    private List<Pattern> excludePatterns;

    private static Comparator<MethodStatistics> selfTimeMethodSelector = new Comparator<MethodStatistics>() {
        public int compare(MethodStatistics s1, MethodStatistics s2) {
            return -Longs.compare(s1.getOnTopObservations(), s2.getOnTopObservations());
        }
    };

    private static Comparator<MethodStatistics> frequencyMethodSelector = new Comparator<MethodStatistics>() {
        public int compare(MethodStatistics s1, MethodStatistics s2) {
            return -Longs.compare(s1.getObservations(), s2.getObservations());
        }
    };

    public synchronized void clean() {
        this.methodIndex.clear();
        locateMethodStatistics(pseudoRoot);
    }

    public RuntimeGraph() {
        clean();
    }

    public void registerSnapshot(List<Method> callTree) {

        if (callTree == null || callTree.size() == 0) {
            return;
        }

        Method caller = pseudoRoot;
        MethodStatistics method = null;
        for (Method methodId : callTree) {
            if (isAppropriate(methodId)) {
                method = locateMethodStatistics(methodId);
                method.registerObservation();

                Invocation invocation = locateInvocation(caller, methodId);
                invocation.registerObservation();

                caller = methodId;
            }
        }
        if (method != null) {
            method.registerOnTopObservation();
        }
        observations++;
    }

    private boolean isAppropriate(Method method) {
        boolean excluded = false;
        boolean included = false;

        if (excludePatterns != null) {
            for (Pattern pattern : excludePatterns) {
                if (method.matches(pattern)) {
                    excluded = true;
                    break;
                }
            }
        }

        if (includePatterns != null) {
            for (Pattern pattern : includePatterns) {
                if (method.matches(pattern)) {
                    included = true;
                    break;
                }
            }
        }

        if (includePatterns == null) {
            return !excluded;
        } else {
            return included || !excluded;
        }
    }

    public List<MethodProfile> getSelfTimeHotSpots(int maxSpots) {
        return getHotSpots(maxSpots, selfTimeMethodSelector);
    }

    public List<MethodProfile> getFrequentHotSpots(int maxSpots) {
        return getHotSpots(maxSpots, frequencyMethodSelector);
    }

    public Graph<MethodProfile, InvocationProfile> getNeighborhood(Method root, int maxCallDepth, int maxCallers) {
        DirectedGraph<MethodProfile, InvocationProfile> neighborhood = new DirectedSparseGraph<MethodProfile, InvocationProfile>();

        MethodStatistics rootStatistics = methodIndex.get(root);

        if (rootStatistics != null) {
            collectCallers(rootStatistics, maxCallDepth, maxCallers, neighborhood);
        }

        return neighborhood;
    }

    private void collectCallers(MethodStatistics root, int maxCallDepth, int maxCallers,
            Graph<MethodProfile, InvocationProfile> neighborhood) {
        if (maxCallDepth > 0) {
            Collection<MethodStatistics> callers = selectMethodStatistics(graph.getPredecessors(root), maxCallers,
                    frequencyMethodSelector);

            MethodProfile rootProfile = assembleProfile(root);
            for (MethodStatistics caller : callers) {
                if (!caller.getMethod().equals(pseudoRoot)) {
                    MethodProfile callerProfile = assembleProfile(caller);
                    neighborhood.addEdge(assembleProfile(graph.findEdge(caller, root)), callerProfile, rootProfile);
                }
            }

            for (MethodStatistics caller : callers) {
                collectCallers(caller, maxCallDepth - 1, maxCallers, neighborhood);
            }
        }
    }

    private List<MethodProfile> getHotSpots(int maxSpots, Comparator<MethodStatistics> comparator) {
        List<MethodProfile> result = Lists.newArrayList();

        MinMaxPriorityQueue<MethodStatistics> hotSpots = MinMaxPriorityQueue.orderedBy(comparator)
                .maximumSize(maxSpots).create(graph.getVertices());

        int queueSize = hotSpots.size();
        for (int i = 0; i < queueSize; i++) {
            result.add(assembleProfile(hotSpots.removeFirst()));
        }

        return result;
    }

    private List<MethodStatistics> selectMethodStatistics(Collection<MethodStatistics> statistics,
            int maxStatistics, Comparator<MethodStatistics> comparator) {
        List<MethodStatistics> result = Lists.newArrayList();

        MinMaxPriorityQueue<MethodStatistics> selected = MinMaxPriorityQueue.orderedBy(comparator)
                .maximumSize(maxStatistics).create(statistics);

        for (MethodStatistics method : selected) {
            result.add(method);
        }

        return result;
    }

    private MethodProfile assembleProfile(MethodStatistics method) {
        MethodProfile profile = new MethodProfile(method.getMethod());
        profile.setObservations(method.getObservations());
        profile.setInStackRatio(method.getObservations() / ((double) observations));
        profile.setOnTopRatio(method.getOnTopObservations() / ((double) observations));

        return profile;
    }

    private InvocationProfile assembleProfile(Invocation invocation) {
        InvocationProfile profile = new InvocationProfile();
        profile.setObservations(invocation.getObservations());

        return profile;
    }

    private MethodStatistics locateMethodStatistics(Method method) {
        MethodStatistics methodStatistics = methodIndex.get(method);
        if (methodStatistics == null) {
            methodStatistics = new MethodStatistics(method);
            methodIndex.put(method, methodStatistics);
            graph.addVertex(methodStatistics);
        }

        return methodStatistics;
    }

    private Invocation locateInvocation(Method caller, Method callee) {
        MethodStatistics callerMethod = locateMethodStatistics(caller);
        MethodStatistics calleeMethod = locateMethodStatistics(callee);

        Invocation invocation = graph.findEdge(callerMethod, calleeMethod);
        if (invocation == null) {
            invocation = new Invocation();
            graph.addEdge(invocation, callerMethod, calleeMethod);
        }

        return invocation;
    }

    public List<Pattern> getIncludePatterns() {
        return includePatterns;
    }

    public void setIncludePatterns(List<Pattern> includePatterns) {
        this.includePatterns = includePatterns;
    }

    public List<Pattern> getExcludePatterns() {
        return excludePatterns;
    }

    public void setExcludePatterns(List<Pattern> excludePatterns) {
        this.excludePatterns = excludePatterns;
    }

    public long getObservations() {
        return observations;
    }

    public int getMethodCount() {
        return graph.getVertexCount();
    }

    @Override
    public String toString() {
        return "RuntimeGraph{" + "observations=" + observations + ", graph=" + graph + ", methodIndex="
                + methodIndex + ", includePatterns=" + includePatterns + ", excludePatterns=" + excludePatterns
                + '}';
    }
}