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.util.Collections;
034: import java.util.Comparator;
035: import java.util.Map;
036: import java.util.Set;
037: import java.util.HashMap;
038: import java.util.TreeMap;
039: import java.util.HashSet;
040: import java.util.ArrayList;
041: import java.util.List;
042:
043: class JipRun implements IJipParseHandler {
044: private String mDate;
045:
046: // current thread, or 0 if none...
047: private long mCurThreadId;
048:
049: // maps threadId (as Long) to List<JipFrame>
050: private Map<Long, List<JipFrame>> mThreads = new HashMap<Long, List<JipFrame>>();
051:
052: // current interaction id or 0.
053: private long mCurInteractionId;
054:
055: // current frame or null
056: private JipFrame mCurFrame;
057:
058: // from each short class name to the full class name
059: private Map<String, String> mFullClassNames = new TreeMap();
060:
061: // maps from a method to the PerMethodInfo for it.
062: private Map<JipMethod, PerMethodInfo> mPerMethods = new HashMap<JipMethod, PerMethodInfo>();
063:
064: public void setDate(String date) {
065: if (mDate != null) {
066: throw new RuntimeException("already set date! (" + mDate
067: + ")");
068: }
069: mDate = date;
070: }
071:
072: public void startThread(long threadId) {
073: if (mCurThreadId != 0) {
074: throw new RuntimeException("already in thread "
075: + mCurThreadId);
076: }
077: mCurThreadId = threadId;
078: }
079:
080: public void endThread() {
081: if (mCurThreadId == 0) {
082: throw new RuntimeException("there's no thread to end!");
083: }
084: mCurThreadId = 0;
085: }
086:
087: public void startInteraction(long id) {
088: if (mCurInteractionId != 0) {
089: throw new RuntimeException("already in interaction "
090: + mCurInteractionId);
091: }
092: mCurInteractionId = id;
093: }
094:
095: public void endInteraction() {
096: if (mCurInteractionId == 0) {
097: throw new RuntimeException("there's no interaction to end!");
098: }
099: mCurInteractionId = 0;
100: }
101:
102: public void startFrame(String className, String methodName,
103: long count, long time) {
104:
105: //System.out.println("startFrame(" + className + ", " +
106: //methodName + ", " + count + ", " + time);
107:
108: /*
109: * NOTE: I'm basically ignoring className because I don't really
110: * see the usefulness of the split between className and
111: * methodName in profile.xml. If we're gonna use the classMap,
112: * let's not include the full class name in the methodName.
113: */
114:
115: JipMethod method = new JipMethod(methodName);
116: JipFrame frame = new JipFrame(mCurFrame, method, mCurThreadId,
117: count, time);
118:
119: if (mCurFrame == null) {
120: List<JipFrame> vFrame = mThreads.get(mCurThreadId);
121: if (vFrame == null) {
122: vFrame = new ArrayList<JipFrame>();
123: mThreads.put(mCurThreadId, vFrame);
124: }
125: vFrame.add(frame);
126: }
127: mCurFrame = frame;
128: }
129:
130: public void endFrame() {
131: mCurFrame.computeNetTime();
132: updatePerMethodInfo(mCurFrame);
133:
134: // pop!
135: mCurFrame = mCurFrame.getParentOrNull();
136: }
137:
138: // allocations not handled -- i want some examples first -- :)
139:
140: public void addToClassMap(String abbrev, String full) {
141: mFullClassNames.put(abbrev, full);
142: }
143:
144: public String toString() {
145: StringBuffer buf = new StringBuffer();
146: buf.append("JipRun\n");
147: buf.append("{\n");
148:
149: for (Long threadId : mThreads.keySet()) {
150: int i = 1;
151: for (JipFrame f : mThreads.get(threadId)) {
152: buf.append("* thread " + threadId + " interaction " + i
153: + "\n");
154: buf.append(f);
155: i++;
156: }
157: }
158:
159: buf.append("}\n");
160:
161: return buf.toString();
162: }
163:
164: public Iterable<Long> threads() {
165: return mThreads.keySet();
166: }
167:
168: long getTotalTimeForAllThreads() {
169: long total = 0;
170: for (Long threadId : threads()) {
171: for (JipFrame frame : mThreads.get(threadId.longValue())) {
172: total += frame.getTotalTime();
173: }
174: }
175: return total;
176: }
177:
178: public Iterable<JipFrame> interactions(long threadId) {
179: return mThreads.get(threadId);
180: }
181:
182: public Iterable<JipFrame> allCallers(JipMethod method) {
183: Set<JipFrame> set = new HashSet<JipFrame>();
184: PerMethodInfo perMethod = mPerMethods.get(method);
185: if (perMethod != null) {
186: for (JipFrame frame : perMethod.allFrames()) {
187: JipFrame parent = frame.getParentOrNull();
188: if (parent != null) {
189: set.add(parent);
190: }
191: }
192: }
193:
194: return set;
195: }
196:
197: public Iterable<JipFrame> allCallees(JipMethod method) {
198: Set set = new HashSet<JipFrame>();
199: PerMethodInfo perMethod = mPerMethods.get(method);
200: if (perMethod != null) {
201: for (JipFrame frame : perMethod.allFrames()) {
202: for (JipFrame callee : frame.getChildren()) {
203: set.add(callee);
204: }
205: }
206: }
207:
208: return set;
209: }
210:
211: /**
212: * Returns an iterable containing PerMethodInfos in descending totalTime
213: * order.
214: */
215: public List<PerMethodInfo> perMethodsInTotalTimeOrder() {
216: Comparator cmp = new Comparator<PerMethodInfo>() {
217: public int compare(PerMethodInfo a, PerMethodInfo b) {
218: long timeA = a.getAllThreadAllFramesTime();
219: long timeB = b.getAllThreadAllFramesTime();
220: if (timeA < timeB) {
221: return -1;
222: } else if (timeA > timeB) {
223: return 1;
224: } else {
225: String nameA = a.getMethod().getMethodName();
226: String nameB = a.getMethod().getMethodName();
227: return nameA.compareToIgnoreCase(nameB);
228: }
229: }
230: };
231: List v = new ArrayList(mPerMethods.values());
232: Collections.sort(v, cmp);
233: return v;
234: }
235:
236: public PerMethodInfo getPerMethod(JipMethod method) {
237: PerMethodInfo perMethod = mPerMethods.get(method);
238: if (perMethod == null) {
239: throw new RuntimeException("unknown method (" + method
240: + ")?");
241: }
242:
243: return perMethod;
244: }
245:
246: static class PerMethodInfo {
247: private JipMethod mMethod;
248:
249: // NOTE: mAllThreadsAllFramesTime includes times from *all* threads.
250: private long mAllThreadsAllFramesTime;
251: private long mAllThreadsAllFramesTimeIncludingReentrant;
252: private List<JipFrame> mvFrame = new ArrayList<JipFrame>();
253:
254: PerMethodInfo(JipMethod method) {
255: mMethod = method;
256: }
257:
258: JipMethod getMethod() {
259: return mMethod;
260: }
261:
262: void addFrame(JipFrame frame) {
263: mvFrame.add(frame);
264:
265: long frameTime = frame.getTotalTime();
266:
267: mAllThreadsAllFramesTimeIncludingReentrant += frameTime;
268:
269: if (!frame.isReentrant()) {
270: mAllThreadsAllFramesTime += frameTime;
271: }
272: }
273:
274: long getAllThreadAllFramesTime() {
275: return mAllThreadsAllFramesTime;
276: }
277:
278: long getAllThreadAllFramesTimeIncludingReentrant() {
279: return mAllThreadsAllFramesTimeIncludingReentrant;
280: }
281:
282: Iterable<JipFrame> allFrames() {
283: return mvFrame;
284: }
285:
286: public String toString() {
287: return mMethod.getMethodName();
288: }
289: }
290:
291: private void updatePerMethodInfo(JipFrame frame) {
292: JipMethod method = frame.getMethod();
293: PerMethodInfo perMethod = mPerMethods.get(method);
294: if (perMethod == null) {
295: perMethod = new PerMethodInfo(method);
296: mPerMethods.put(method, perMethod);
297: }
298: perMethod.addFrame(frame);
299: }
300: };
|