package com.macmillan.nmeyers; import java.util.*; import javax.swing.tree.*; import java.text.*; /* * CallerInclusive.java: Part of the PerfAnal tool * * This class encapsulates a tree, consisting of DefaultMutableTreeNodes, * of performance data by procedure, broken down by callee, inclusive of * called procedures. * * Author: Nathan Meyers, nmeyers@javalinux.net * $Id: CallerInclusive.java,v 1.13 1999/11/10 03:36:14 nathanm Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program 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 for more details. * * You should have received a copy of the GNU General Public License * with this program. If not, the license is available from the * GNU project, at http://www.gnu.org. */ class CallerInclusive extends PerfTree.PerfTreeNode implements Comparable { HashMap kidInfo = new HashMap(); CallerInclusive(HashMap procedures, int totalCount) { super(new ProcCountInfo(new Procedure(""))); ((ProcCountInfo)getUserObject()).count = totalCount; // Build a list of procedures, sorted by usage Iterator iterator = procedures.values().iterator(); while (iterator.hasNext()) { ProcCountInfo info = new ProcCountInfo((Procedure)iterator.next()); add(info); } if (children == null) return; // Step through the procedures, and populate the tree with // descendant information for (iterator = children.iterator(); iterator.hasNext();) { CallerInclusive child = (CallerInclusive)iterator.next(); Procedure.TraceInfo prevTraceInfo = null; // Step through all of the tracebacks relevant to this proc for (Iterator traceIterator = ((ProcCountInfo)child.getUserObject()). procedure.myTraces.iterator(); traceIterator.hasNext();) { Procedure.TraceInfo traceInfo = (Procedure.TraceInfo)traceIterator.next(); // We want only the first instance of a particular // traceback for this Procedure... it will have the // deepest callee stack. Later instances are recursion // and muddle the results. if (prevTraceInfo != null && prevTraceInfo.traceBack.equals(traceInfo.traceBack)) continue; prevTraceInfo = traceInfo; child.addDescendants(traceInfo.traceBack, traceInfo.depth - 1); } } // Propagate the timing information processNodes(); } TreePath findThisProc(String procName) { // Linear search for child with given name Iterator iterator = children.iterator(); while (iterator.hasNext()) { CallerInclusive child = (CallerInclusive)iterator.next(); ProcCountInfo pci = (ProcCountInfo)child.getUserObject(); if (pci.procedure.procName.equals(procName)) return new TreePath(child.getPath()); } return null; } private CallerInclusive(ProcCountInfo pci) { super(pci); } private CallerInclusive add(ProcCountInfo pci) { CallerInclusive pi = new CallerInclusive(pci); kidInfo.put(pci.procedure.procName, new KidInfo(pci.procedure.procName, pi)); add(pi); return pi; } // processNodes() traverses the tree, doing assorted important processing: // // Null out the kidInfo pointer to free up memory we no longer need // Propagate our profile times upward // Sort the children into descending time order private void processNodes() { // Clean out some memory we no longer need kidInfo = null; // Initialize our count with time spent in this method ProcCountInfo pci = (ProcCountInfo)getUserObject(); if (getLevel() > 0) pci.count = pci.myCount; // Recursively handle the children, and add their time to ours if (children != null) { ListIterator iterator = children.listIterator(); while (iterator.hasNext()) { CallerInclusive pi = (CallerInclusive)iterator.next(); ProcCountInfo childPci = (ProcCountInfo)pi.getUserObject(); pi.processNodes(); if (getLevel() > 0) pci.count += childPci.count; } Collections.sort(children); } } private void addDescendants(TraceBack traceBack, int depth) { if (traceBack.thread != null && !traceBack.thread.enabled) return; if (depth >= 0) { String procName = ((TraceBack.TraceBackEntry)traceBack. entries.get(depth)).procName; KidInfo ki = (KidInfo)kidInfo.get(procName); CallerInclusive ci; if (ki == null) ci = add(new ProcCountInfo(new Procedure(procName))); else ci = ki.kid; ci.addDescendants(traceBack, depth - 1); } else ((ProcCountInfo)getUserObject()).myCount += traceBack.traceCount; } public int compareTo(Object o) { return ((ProcCountInfo)getUserObject()).compareTo( ((PerfTree.PerfTreeNode)o).getUserObject()); } public String toString() { ProcCountInfo rootPci = (ProcCountInfo) ((PerfTree.PerfTreeNode)getRoot()).getUserObject(); if (getLevel() == 0) return "Method Times by Caller (times inclusive): " + rootPci.count + " ticks"; ProcCountInfo pci = (ProcCountInfo)getUserObject(); return pci.toString(rootPci.count); } public String getProcName() { return ((ProcCountInfo)getUserObject()).procedure.procName; } static class ProcCountInfo implements Comparable { Procedure procedure; int count = 0; int myCount = 0; static DecimalFormat format = new DecimalFormat("##0.##%"); ProcCountInfo(Procedure p) { procedure = p; } public String toString(int totalCount) { return procedure.procName + ": " + format.format((double)count / (double)totalCount) + " (" + count + " inclusive / " + myCount + " exclusive)"; } public int compareTo(Object o) { return ((ProcCountInfo)o).count - count; } public boolean equals(Object o) { return count == ((ProcCountInfo)o).count; } } static class KidInfo implements Comparable { String kidName; CallerInclusive kid; KidInfo(String kn, CallerInclusive k) { kidName = kn; kid = k; } public int compareTo(Object o) { return kidName.compareTo(((KidInfo)o).kidName); } } }