package com.macmillan.nmeyers; import java.io.*; import java.util.*; import javax.swing.*; import java.awt.*; import java.awt.event.*; /* * PerfAnal.java: Part of the PerfAnal tool * * This is the main class. * * Usage: PerfAnal * * Author: Nathan Meyers, nmeyers@javalinux.net * $Id: PerfAnal.java,v 1.24 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 PerfAnal extends JFrame implements PerfTree.FindMethod, SaveDialog.DoSave, SelectThreads.ChooseThread { HashMap traceBacks = new HashMap(); // For holding TraceBack objects HashMap procedures = new HashMap(); // For holding Procedure objects HashMap threads = new HashMap(); // For holding ThreadInfo objects CallerInclusive callerInclusive; CalleeInclusive calleeInclusive; LineInclusive lineInclusive; LineExclusive lineExclusive; PerfTree tree1, tree2, tree3, tree4; SelectMethod selectMethod; SelectThreads selectThreads; int totalCount = 0; static int frameCount = 0; PerfAnal(String fileName, Reader reader) { super("Performance Analysis: " + fileName); // Build our one little menu JMenuBar menuBar = new JMenuBar(); setJMenuBar(menuBar); JMenu fileMenu = new JMenu("File"); menuBar.add(fileMenu); // Button to save analysis data to a file JMenuItem menuItem = new JMenuItem("Save..."); fileMenu.add(menuItem); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { new SaveDialog(PerfAnal.this, PerfAnal.this); } }); fileMenu.add(new JSeparator()); // Button to quit menuItem = new JMenuItem("Exit"); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } }); fileMenu.add(menuItem); getContentPane().setLayout(new GridLayout(2, 2)); // Start parsing input file. Look for lines that mark the start // of a stack trace or info on a thread LineNumberReader lineReader = null; if (reader != null) try { lineReader = new LineNumberReader(reader); String line; while ((line = lineReader.readLine()) != null) { // Check for start of the next section if (line.startsWith("CPU SAMPLES BEGIN")) break; if (line.startsWith("THREAD START") && line.indexOf("name=") != -1) { ThreadInfo info = ThreadInfo.parse(line); if (info != null) threads.put(new Integer(info.threadNumber), info); } if (line.startsWith("TRACE ") && line.indexOf(':') != -1) { // This looks like a real traceback. TraceBack traceBack = TraceBack.parse(line, lineReader, threads); if (traceBack == null) throw new IOException("Cannot parse stack trace"); traceBacks.put(new Integer(traceBack.traceNumber), traceBack); } } // We're to the second section -- the CPU sample counts. // Waste the next line, which is a header. lineReader.readLine(); // Now start parsing these entries, building our list of // procedure references and counts as we go. while ((line = lineReader.readLine()) != null) { // Check for end of this section if (line.startsWith("CPU SAMPLES END")) break; totalCount += Procedure.parse(line, procedures, traceBacks); } } catch (IOException e) { displayError("Line " + lineReader.getLineNumber() + ": " + e, this); } // Create our method selection dialog selectMethod = new SelectMethod(this, this, procedures); // Create our thread selection dialog selectThreads = new SelectThreads(this, this, threads); // Create trees for our inclusive procedure call counts callerInclusive = new CallerInclusive(procedures, totalCount); lineInclusive = new LineInclusive(procedures, totalCount); calleeInclusive = new CalleeInclusive(procedures, totalCount); lineExclusive = new LineExclusive(procedures, totalCount); // Ready to roll getContentPane().add(tree1 = new PerfTree(callerInclusive, this, this)); getContentPane().add(tree2 = new PerfTree(lineInclusive, this, this)); getContentPane().add(tree3 = new PerfTree(calleeInclusive, this, this)); getContentPane().add(tree4 = new PerfTree(lineExclusive, this, this)); pack(); // Try to keep this from getting too big Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension mySize = getSize(); if (mySize.width > 3 * screenSize.width / 4) mySize.width = 3 * screenSize.width / 4; if (mySize.height > 3 * screenSize.height / 4) mySize.height = 3 * screenSize.height / 4; setSize(mySize); setVisible(true); incFrameCount(); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent ev) { dispose(); decFrameCount(); } }); } public void findMethod(String s) { if (s == null) selectMethod.setVisible(true); else { tree1.selectThisProc(s); tree2.selectThisProc(s); tree3.selectThisProc(s); tree4.selectThisProc(s); } } public void chooseThread() { selectThreads.setVisible(true); } public void recomputeTotals() { super.setEnabled(false); super.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); callerInclusive = new CallerInclusive(procedures, totalCount); lineInclusive = new LineInclusive(procedures, totalCount); calleeInclusive = new CalleeInclusive(procedures, totalCount); lineExclusive = new LineExclusive(procedures, totalCount); tree1.initializeRoot(callerInclusive); tree2.initializeRoot(lineInclusive); tree3.initializeRoot(calleeInclusive); tree4.initializeRoot(lineExclusive); invalidate(); validate(); super.setCursor(Cursor.getDefaultCursor()); super.setEnabled(true); } public void doSave(File file) { PrintWriter writer = null; try { writer = new PrintWriter(new BufferedWriter(new FileWriter(file))); tree1.saveData(writer); writer.println(""); tree2.saveData(writer); writer.println(""); tree3.saveData(writer); writer.println(""); tree4.saveData(writer); } catch (IOException e) { displayError(e.toString(), this); } finally { if (writer != null) writer.close(); } } static void displayError(String s, final JFrame parent) { final Window dialog = (parent == null ? (Window)(new JFrame("Error")) : (Window)(new JDialog(parent, "Error", true))); ((RootPaneContainer)dialog).getContentPane(). add(new JLabel(s), BorderLayout.CENTER); JButton OKButton = new JButton("OK"); ((RootPaneContainer)dialog).getContentPane(). add(OKButton, BorderLayout.SOUTH); ((RootPaneContainer)dialog).getRootPane().setDefaultButton(OKButton); OKButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { dialog.dispose(); if (parent == null) decFrameCount(); } }); dialog.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent ev) { dialog.dispose(); if (parent == null) decFrameCount(); } }); dialog.pack(); dialog.setVisible(true); if (parent == null) incFrameCount(); } static void incFrameCount() { frameCount++; } static void decFrameCount() { if (--frameCount == 0) System.exit(0); } static public void main(String argv[]) { if (argv.length == 0) new PerfAnal("stdin", new InputStreamReader(System.in)); else { for (int i = 0; i < argv.length; i++) try { new PerfAnal(argv[i], new FileReader(argv[i])); } catch (FileNotFoundException e) { displayError(e.toString(), null); } } } }