package com.macmillan.nmeyers; import java.util.*; /* * Procedure.java: Part of the PerfAnal tool * * This class holds profile information for individual methods. * Because the traces do not include full signature information, we * cannot distinguish among multiple versions of a methods. * * Author: Nathan Meyers, nmeyers@javalinux.net * $Id: Procedure.java,v 1.12 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 Procedure implements Comparable { public String procName; public int countInclusive = 0; public int countExclusive = 0; // "lines" keeps track of profile info for individual lines of source. TreeSet lines = new TreeSet(); // "mytraces" keeps track of which stack traces reference us LinkedList myTraces = new LinkedList(); Procedure(String str) { procName = str; } // Allocate a new Procedure object and add to the map, or return existing one // from the map public static Procedure factory(String str, HashMap map) { Procedure result = (Procedure)map.get(str); if (result != null) return result; result = new Procedure(str); map.put(str, result); return result; } // Parse the trace information from the CPU sample counts, update // the caller's procedures tree and our own tree of line number data public static int parse(String str, HashMap procedures, HashMap traceBacks) { StringTokenizer tokenizer = new StringTokenizer(str); // Parse the sample data. Ignore rank, self, and accum fields. tokenizer.nextToken(); tokenizer.nextToken(); tokenizer.nextToken(); // Read the count and trace fields int count = Integer.parseInt(tokenizer.nextToken()); Integer traceNum = new Integer(tokenizer.nextToken()); TraceBack tb = (TraceBack)traceBacks.get(traceNum); // Update the count in the traceback tb.traceCount = count; if (tb.thread != null) tb.thread.count += count; // For each entry in the callback, update appropriate Procedure // and Line counts, and add this traceback to the Procedure // traceback chain. if (tb != null && !tb.entries.isEmpty()) { int depth = 0; Iterator iterator = tb.entries.iterator(); // Keep track of procedures and lines we've recorded from // this traceback, in an attempt to reduce confusion caused // by recursion. TreeSet procsRecorded = new TreeSet(); TreeSet linesRecorded = new TreeSet(); while (iterator.hasNext()) { TraceBack.TraceBackEntry traceBackEntry = (TraceBack.TraceBackEntry)iterator.next(); // Find (or create) an entry for this procedure Procedure procedure = Procedure.factory(traceBackEntry.procName, procedures); // Find (or create) an entry for this line Line line = Line.factory(traceBackEntry.procLineNum, procedure.lines, tb.thread); // Update inclusive counts, avoiding repeats from recursion // in an attempt to make inclusive counts somewhat useful. if (procsRecorded.add(procedure)) procedure.countInclusive += count; if (linesRecorded.add(procedure)) line.countInclusive += count; // Update exclusive counts if we're at top of stack if (depth == 0) { procedure.countExclusive += count; line.countExclusive += count; } // Add this stack trace to our collection procedure.myTraces.add(new TraceInfo(tb, depth)); depth++; } } return count; } public int compareTo(Object o) { return procName.compareTo(((Procedure)o).procName); } public boolean equals(Object o) { return procName.equals(((Procedure)o).procName); } static class TraceInfo { public TraceBack traceBack; public int depth; TraceInfo(TraceBack tb, int d) { traceBack = tb; depth = d; } public String toString() { return "[traceBack=" + traceBack + ",depth=" + depth + ']'; } } // This class holds profile information for a particular line number // of a procedure. static class Line implements Comparable { public String lineInfo; public int countInclusive = 0; public int countExclusive = 0; public ThreadInfo thread = null; private Line(String str, ThreadInfo thr) { lineInfo = str; thread = thr; } // Allocate a new Line object and add to the set, or return existing one // from the set public static Line factory(String str, TreeSet set, ThreadInfo thr) { Line result = new Line(str, thr); if (set.add(result)) return result; else return (Line)set.tailSet(result).first(); } public int compareTo(Object o) { int result = lineInfo.compareTo(((Line)o).lineInfo); if (result == 0 && thread != null) result = thread.compareTo(((Line)o).thread); return result; } public boolean equals(Object o) { return lineInfo.equals(((Line)o).lineInfo) && (thread == null || thread.equals(((Line)o).thread)); } public String toString() { return "[lineInfo=" + lineInfo + ",countInclusive=" + countInclusive + ",countExclusive=" + countExclusive + ",thread=" + thread + ']'; } } public String toString() { return procName; } }