001: /*/////////////////////////////////////////////////////////////////////
002:
003: Copyright (C) 2006 TiVo Inc. All rights reserved.
004:
005: Redistribution and use in source and binary forms, with or without
006: modification, are permitted provided that the following conditions are met:
007:
008: + Redistributions of source code must retain the above copyright notice,
009: this list of conditions and the following disclaimer.
010: + Redistributions in binary form must reproduce the above copyright notice,
011: this list of conditions and the following disclaimer in the documentation
012: and/or other materials provided with the distribution.
013: + Neither the name of TiVo Inc nor the names of its contributors may be
014: used to endorse or promote products derived from this software without
015: specific prior written permission.
016:
017: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018: AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
020: ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
021: LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
022: CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
023: SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
024: INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
025: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
026: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
027: POSSIBILITY OF SUCH DAMAGE.
028:
029: /////////////////////////////////////////////////////////////////////*/
030:
031: package com.tivo.jipviewer;
032:
033: import java.awt.Container;
034: import java.awt.event.MouseEvent;
035: import java.awt.event.MouseListener;
036: import java.text.NumberFormat;
037: import java.util.HashMap;
038: import java.util.Map;
039:
040: import javax.swing.BoxLayout;
041: import javax.swing.JLabel;
042: import javax.swing.JScrollPane;
043: import javax.swing.JSeparator;
044: import javax.swing.JTable;
045: import javax.swing.SwingConstants;
046: import javax.swing.table.DefaultTableCellRenderer;
047: import javax.swing.table.TableColumn;
048: import javax.swing.table.TableColumnModel;
049: import javax.swing.table.TableModel;
050:
051: class MethodViewer extends Container implements ChangeListener,
052: MouseListener {
053: private ValueModel<JipMethod> mModel;
054: private JLabel mLabel;
055: private JTable mCallers;
056: private JTable mSelf;
057: private JTable mCallees;
058: private JipRun mRun;
059:
060: private MethodRowTableModel mSelfModel = new MethodRowTableModel();
061: private MethodRowTableModel mCallersModel = new MethodRowTableModel();
062: private MethodRowTableModel mCalleesModel = new MethodRowTableModel();
063:
064: MethodViewer(JipRun run, ValueModel<JipMethod> model) {
065: mRun = run;
066: mModel = model;
067: mModel.addChangeListener(this );
068:
069: mLabel = makeLabel("method:");
070:
071: mCallers = makeTableForMethodRows(mCallersModel);
072: mSelf = makeTableForMethodRows(mSelfModel);
073: mCallees = makeTableForMethodRows(mCalleesModel);
074:
075: // listen some...
076: mCallers.addMouseListener(this );
077: mCallees.addMouseListener(this );
078:
079: add(makeLabel("called by:"));
080: add(new JScrollPane(mCallers));
081: add(new JSeparator());
082: add(mLabel);
083: add(mSelf);
084: add(new JSeparator());
085: add(makeLabel("calls:"));
086: add(new JScrollPane(mCallees));
087: setLayout(new BoxLayout(this , BoxLayout.Y_AXIS));
088: }
089:
090: public void changed(Object source) {
091: JipMethod method = mModel.getValue();
092:
093: mCallersModel.clear();
094: mSelfModel.clear();
095: mCalleesModel.clear();
096:
097: if (method != null) {
098:
099: // do callers...
100: Map<JipMethod, MethodRow> rows = new HashMap<JipMethod, MethodRow>();
101: long allCallersTime = 0;
102: for (JipFrame caller : mRun.allCallers(method)) {
103: JipMethod callerMethod = caller.getMethod();
104: MethodRow mr = rows.get(callerMethod);
105: if (mr == null) {
106: mr = new MethodRow(callerMethod);
107: mCallersModel.add(mr);
108: rows.put(callerMethod, mr);
109: }
110: mr.addFrame(caller);
111: allCallersTime += caller.getTotalTime();
112: }
113: for (MethodRow mr : rows.values()) {
114: mr.setTimeDenominator(allCallersTime);
115: }
116:
117: // do self...
118: JipRun.PerMethodInfo perMethod = mRun.getPerMethod(method);
119: long selfTotalTimeIncReentrant = perMethod
120: .getAllThreadAllFramesTimeIncludingReentrant();
121:
122: MethodRow selfRow = new MethodRow(method);
123: selfRow.setTimeDenominator(selfTotalTimeIncReentrant);
124: for (JipFrame frame : perMethod.allFrames()) {
125: selfRow.addFrame(frame);
126: }
127: mSelfModel.add(selfRow);
128:
129: // do callees...
130: rows = new HashMap<JipMethod, MethodRow>();
131: for (JipFrame callee : mRun.allCallees(method)) {
132: JipMethod calleeMethod = callee.getMethod();
133: MethodRow mr = rows.get(calleeMethod);
134: if (mr == null) {
135: mr = new MethodRow(calleeMethod);
136: mr.setTimeDenominator(selfTotalTimeIncReentrant);
137: mCalleesModel.add(mr);
138: rows.put(calleeMethod, mr);
139: }
140: mr.addFrame(callee);
141: }
142: }
143: }
144:
145: // A renderer that displays doubles with a fixed number of decimal columns
146: static class MyDoubleRenderer extends DefaultTableCellRenderer {
147: NumberFormat mFormat;
148:
149: MyDoubleRenderer() {
150: super ();
151: setHorizontalAlignment(SwingConstants.RIGHT);
152: }
153:
154: public void setValue(Object value) {
155: if (mFormat == null) {
156: mFormat = (NumberFormat) NumberFormat.getInstance()
157: .clone();
158: mFormat.setMinimumFractionDigits(2);
159: }
160: setText(mFormat.format(value));
161: }
162: };
163:
164: static int svWidth[] = { 50, 100, 50, 50, 50, 190, 200, 190 };
165:
166: static JTable makeTableForMethodRows(TableModel model) {
167: TableSorter sorter = new TableSorter(model);
168: JTable table = new JTable(sorter);
169: sorter.setTableHeader(table.getTableHeader());
170:
171: TableColumnModel colModel = table.getColumnModel();
172: int nCol = model.getColumnCount();
173: for (int iCol = 0; iCol < nCol; iCol++) {
174: TableColumn col = colModel.getColumn(iCol);
175: if (iCol < svWidth.length) {
176: col.setPreferredWidth(svWidth[iCol]);
177: }
178: }
179: table.doLayout();
180:
181: table.setDefaultRenderer(Double.class, new MyDoubleRenderer());
182: return table;
183: }
184:
185: private JLabel makeLabel(String text) {
186: JLabel label = new JLabel(text);
187: //label.setHorizontalTextPosition(JLabel.LEFT);
188: return label;
189: }
190:
191: //
192: // MouseListener
193: //
194:
195: public void mouseClicked(MouseEvent e) {
196: if ((e.getSource() != mCallers) && (e.getSource() != mCallees)) {
197: return;
198: }
199:
200: if (e.getButton() != MouseEvent.BUTTON1) {
201: return;
202: }
203:
204: if (e.getID() != MouseEvent.MOUSE_CLICKED) {
205: return;
206: }
207:
208: if (e.getClickCount() != 2) {
209: return;
210: }
211:
212: // ok...button1 was double-clicked on either mCallers or mCallees.
213:
214: // find the index of the row in the view...
215: JTable table = (JTable) e.getSource();
216: int iRow = table.rowAtPoint(e.getPoint());
217:
218: // convert to index of the row in the unsorted model...
219: TableSorter sorter = (TableSorter) table.getModel();
220: iRow = sorter.modelIndex(iRow);
221:
222: // get the row from the unsorted model...
223: MethodRowTableModel rowModel = (MethodRowTableModel) sorter
224: .getTableModel();
225:
226: MethodRow row = rowModel.getRow(iRow);
227:
228: // update the model!
229: mModel.setValue(row.getMethod());
230: }
231:
232: public void mouseEntered(MouseEvent e) {
233: }
234:
235: public void mouseExited(MouseEvent e) {
236: }
237:
238: public void mousePressed(MouseEvent e) {
239: }
240:
241: public void mouseReleased(MouseEvent e) {
242: }
243: };
|