001: /*
002: Copyright (c) 2005 - 2006, MentorGen, LLC
003: 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 MentorGen LLC 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: package com.mentorgen.tools.profile.output;
030:
031: import java.io.BufferedWriter;
032: import java.io.File;
033: import java.io.FileWriter;
034: import java.io.IOException;
035: import java.io.PrintWriter;
036: import java.text.SimpleDateFormat;
037: import java.util.Collections;
038: import java.util.Comparator;
039: import java.util.Date;
040: import java.util.HashMap;
041: import java.util.LinkedList;
042:
043: import com.mentorgen.tools.profile.Controller;
044: import com.mentorgen.tools.profile.runtime.ClassAllocation;
045: import com.mentorgen.tools.profile.runtime.Frame;
046: import com.mentorgen.tools.profile.runtime.Profile;
047:
048: /**
049: * This class outputs the profile in a human-readable text format.
050: *
051: * @author Andrew Wilcox
052: * @see com.mentorgen.tools.profile.output.ProfileXMLDump
053: */
054: final class ProfileTextDump {
055: static HashMap<String, Holder> _clumpedFrameMap;
056:
057: static void dump() throws IOException {
058:
059: // init
060: //
061: _clumpedFrameMap = new HashMap<String, Holder>();
062:
063: //
064: // output
065: //
066: String fileName = null;
067: File f = new File(Controller._fileName);
068: Date now = new Date();
069:
070: if (f.isDirectory()) {
071: StringBuffer b = new StringBuffer(f.getAbsolutePath());
072: b.append(File.separator);
073: b.append(new SimpleDateFormat("yyyyMMdd-HHmmss")
074: .format(now));
075: b.append(".txt");
076: fileName = b.toString();
077: } else {
078: if (Controller._fileName.endsWith(".txt")) {
079: fileName = Controller._fileName;
080: } else {
081: StringBuffer b = new StringBuffer(Controller._fileName);
082: b.append(".txt");
083: fileName = b.toString();
084: }
085: }
086:
087: FileWriter out = new FileWriter(fileName);
088: BufferedWriter bufferedWriter = new BufferedWriter(out);
089: PrintWriter writer = new PrintWriter(bufferedWriter);
090:
091: writer
092: .println("+----------------------------------------------------------------------");
093: writer.print("| File: ");
094: writer.println(fileName);
095: writer.print("| Date: ");
096: writer.println(new SimpleDateFormat("yyyy.MM.dd HH:mm:ss a")
097: .format(now));
098: writer
099: .println("+----------------------------------------------------------------------");
100: writer.println();
101:
102: if (!Controller._outputSummaryOnly) {
103: dumpThreads(writer);
104: }
105:
106: dumpFrames(writer);
107: dumpClumpedFrames(writer);
108: dumpAllocation(writer);
109:
110: writer.flush();
111: out.close();
112: }
113:
114: private static void dumpThreads(PrintWriter writer) {
115:
116: // announce the control level for the threads
117: //
118: writer.println("+------------------------------");
119: writer.print("| Thread depth limit: ");
120:
121: if (Controller._compactThreadDepth) {
122: writer.println("Compact");
123: } else if (Controller._threadDepth == Controller.UNLIMITED) {
124: writer.println("Unlimited");
125: } else {
126: writer.println(Controller._threadDepth);
127: }
128:
129: writer.println("+------------------------------");
130:
131: // display the threads
132: //
133: for (Long threadId : Profile.threads()) {
134: int i = 1;
135:
136: for (Frame iteractionRoot : Profile.interactions(threadId)) {
137: FrameDump.dump(writer, iteractionRoot, i);
138: i++;
139: }
140: }
141: }
142:
143: private static void dumpFrames(PrintWriter writer) {
144:
145: // announce the control level
146: //
147: writer.println();
148: writer.println("+--------------------------------------");
149: writer.println("| Most expensive methods (by net time)");
150: writer.print("| Frame Count Limit: ");
151:
152: if (Controller._compactMethodCount) {
153: writer.println("Compact");
154: } else if (Controller._methodCount == Controller.UNLIMITED) {
155: writer.println("Unlimited");
156: } else {
157: writer.println(Controller._methodCount);
158: }
159:
160: writer.println("+--------------------------------------");
161: writer.println();
162:
163: // display the frame information
164: //
165: writer.println(" Net");
166: writer.println(" ------------");
167: writer.println(" Count Time Pct Location");
168: writer.println(" ===== ==== === ========");
169: int count = 0;
170: boolean display = true;
171: Profile.sortFrameList(new FrameComparator());
172:
173: for (Frame frame : Profile.frameList()) {
174:
175: long threadId = frame.getThreadId();
176:
177: double threadTotalTime = Profile
178: .getThreadTotalTime(threadId);
179: double percent = Math.toPercent(frame.netTime(),
180: threadTotalTime);
181: double time = Math.nanoToMilli(frame.netTime());
182: String name = frame.getName();
183:
184: if (display && belowThreshold(time, count)) {
185: display = false;
186: }
187:
188: count++;
189:
190: if (display) {
191: writer.printf("%6d ", frame._metrics.getCount());
192: writer.printf("%8.1f ", time);
193: writer.printf("%5.1f ", percent);
194: writer.println(name);
195: }
196:
197: clumpFrame(frame._metrics.getCount(), time, percent, name);
198: }
199: }
200:
201: private static void clumpFrame(long count, double time,
202: double percent, String name) {
203: Holder h = _clumpedFrameMap.get(name);
204:
205: if (h == null) {
206: h = new Holder(count, time, percent, name);
207: _clumpedFrameMap.put(name, h);
208: } else {
209: h._count += count;
210: h._time += time;
211: h._percent += percent;
212: }
213: }
214:
215: private static void dumpClumpedFrames(PrintWriter writer) {
216: writer.println();
217: writer.println("+--------------------------------------+");
218: writer.println("| Most expensive methods summarized |");
219: writer.println("+--------------------------------------+");
220: writer.println();
221:
222: LinkedList<Holder> list = new LinkedList<Holder>();
223:
224: for (Holder h : _clumpedFrameMap.values()) {
225: list.add(h);
226: }
227:
228: Collections.sort(list, new HolderComparator());
229:
230: writer.println(" Net");
231: writer.println(" ------------");
232: writer.println(" Count Time Pct Location");
233: writer.println(" ===== ==== === ========");
234:
235: long count = 0;
236:
237: for (Holder h : list) {
238:
239: if (belowThreshold(h._time, count)) {
240: break;
241: }
242: count++;
243:
244: writer.printf("%6d ", h._count);
245: writer.printf("%8.1f ", h._time);
246: writer.printf("%5.1f ", h._percent);
247: writer.println(h._name);
248: }
249: }
250:
251: private static boolean belowThreshold(double time, long count) {
252:
253: if (Controller._compactMethodCount) {
254: if (time < (Controller._compactMethodThreshold)) {
255: return true;
256: }
257: } else if (Controller._methodCount != Controller.UNLIMITED) {
258: if (count + 1 == Controller._methodCount)
259: return true;
260: }
261:
262: return false;
263: }
264:
265: private static void dumpAllocation(PrintWriter writer) {
266:
267: if (!Controller._trackObjectAlloc) {
268: return;
269: }
270:
271: writer.println();
272: writer.println("+---------------------------------+");
273: writer.println("| Object Allocation |");
274: writer.println("+---------------------------------+");
275: writer.println();
276: writer.println(" Count Class Name");
277: writer.println(" ===== ==========");
278:
279: LinkedList<ClassAllocation> caList = new LinkedList<ClassAllocation>();
280:
281: for (ClassAllocation ca : Profile.allocations()) {
282: caList.add(ca);
283: }
284:
285: Collections.sort(caList, new ClassAllocComparator());
286:
287: for (ClassAllocation ca : caList) {
288: writer.printf("%10d ", ca.getAllocCount());
289: writer.println(ca.getClassName());
290: }
291: }
292: }
293:
294: class Holder {
295: long _count;
296: double _time;
297: double _percent;
298: String _name;
299:
300: Holder(long count, double time, double percent, String name) {
301: _count = count;
302: _time = time;
303: _percent = percent;
304: _name = name;
305: }
306: }
307:
308: class FrameComparator implements Comparator<Frame> {
309:
310: public int compare(Frame fa, Frame fb) {
311: //
312: // IMPORTANT NOTE:
313: //
314: // Returning:
315: // fb.netTime() - fa.netTime()
316: //
317: // won't work. This is because netTime is a long. So, for
318: // example, if fb.netTime() is close to zero and fa.netTime()
319: // is large, you might end up with a number that can't be expressed
320: // properly as an integer.
321: //
322:
323: if (fa.netTime() < fb.netTime()) {
324: return 1;
325: } else if (fa.netTime() == fb.netTime()) {
326: return 0;
327: } else {
328: return -1;
329: }
330: }
331:
332: }
333:
334: class HolderComparator implements Comparator<Holder> {
335:
336: public int compare(Holder ha, Holder hb) {
337:
338: if (ha._time < hb._time) {
339: return 1;
340: } else if (ha._time == hb._time) {
341: return 0;
342: } else {
343: return -1;
344: }
345: }
346: }
347:
348: class ClassAllocComparator implements Comparator<ClassAllocation> {
349:
350: public int compare(ClassAllocation ca1, ClassAllocation ca2) {
351: return ca2.getAllocCount() - ca1.getAllocCount();
352: }
353: }
|