View Javadoc

1   /*
2    * Jour - java profiler and monitoring library
3    *
4    * Copyright (C) 2004 Jour team
5    *
6    * This library is free software; you can redistribute it and/or
7    * modify it under the terms of the GNU Library General Public
8    * License as published by the Free Software Foundation; either
9    * version 2 of the License, or (at your option) any later version.
10   *
11   * This library is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   * Library General Public License for more details.
15   *
16   * You should have received a copy of the GNU Library General Public
17   * License along with this library; if not, write to the
18   * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19   * Boston, MA  02111-1307, USA.
20   */
21  package net.sf.jour.rt.swingmonitor;
22  
23  import java.io.BufferedWriter;
24  import java.io.File;
25  import java.io.FileWriter;
26  import java.io.IOException;
27  import java.io.Serializable;
28  import java.util.HashMap;
29  import java.util.Iterator;
30  
31  import net.sf.jour.filter.MatchFilter;
32  import net.sf.jour.rt.agent.ProfilerEvent;
33  import net.sf.jour.rt.swingmonitor.ui.FDouble;
34  import net.sf.jour.rt.view.ViewFilter;
35  import net.sf.jour.rt.view.ViewFilterItem;
36  import net.sf.jour.statistic.MethodAccumulation;
37  import net.sf.jour.statistic.TimeBaseAccumulationList;
38  import net.sf.jour.util.queue.Queue;
39  
40  import org.apache.log4j.Logger;
41  
42  /***
43   * 
44   * TODO ...
45   *  
46   * Created on 04.12.2004
47   *
48   * Contributing Author(s):
49   *
50   *   Misha Lifschitz <mishalifschitz at users.sourceforge.net> (Inital implementation)
51   *   Vlad Skarzhevskyy <vlads at users.sourceforge.net> (Inital implementation)
52   *
53   * @author michaellif
54   * @version $Revision: 1.19 $ ($Author: vlads $) $Date: 2004/12/17 04:17:46 $
55   */
56  public class MethodExceutionStatistics implements Serializable {
57      
58      protected static final Logger log = Logger.getLogger(MethodExceutionStatistics.class);
59  
60  	private HashMap methodStatHash = new HashMap();
61  	private ViewFilter viewFilter;
62  
63  	TimeBaseAccumulationList totals;
64  	
65      private transient HashMap notCompletedMethodsHash = new HashMap();
66  
67      public final static String[] columnNames = { "Method", "first", "min", "max", "average", "count", "sd", "total", "Exc" };
68      
69      long countTotal;
70      
71  	public MethodExceutionStatistics(ViewFilter viewFilter) {
72  		totals = new TimeBaseAccumulationList(); 
73  		this.viewFilter = viewFilter;
74  	}
75  	
76      /***
77       * @return Returns the countTotal.
78       */
79      public long getCountTotal() {
80          return countTotal;
81      }
82      
83      /***
84       * DOCUMENT ME!
85       *
86       * @param clazz DOCUMENT ME!
87       */
88      public boolean processEvent(ProfilerEvent event, MatchFilter filter) {
89          countTotal ++;
90          if (event.onMethodStart()) {
91              addStartedMethodEvent(event);
92          } else {
93              recalcMethodStat(event, filter);
94          }
95          return true;
96      }
97  
98      public void recalcMethodStat(ProfilerEvent endMethodEvent, MatchFilter filter) {
99          Object methodInstanceId = getMethodInstanceId(endMethodEvent);
100         if (!notCompletedMethodsHash.containsKey(methodInstanceId)) {
101             //throw new Error("Method end event before method start:" + endMethodEvent);
102             log.warn("Method end event before method start:" + endMethodEvent);
103             return;
104         }
105         Queue queue = (Queue) notCompletedMethodsHash.get(methodInstanceId);
106         if (queue == null) {
107             log.warn("Method end but there is no start events:" + endMethodEvent);
108             return;
109         }
110         if (queue.isEmpty()) {
111             log.warn("Method end but there is no start events:" + endMethodEvent);
112             return;
113         }
114         ProfilerEvent startMethodEvent = (ProfilerEvent)queue.dequeue();
115         double time = endMethodEvent.getTimestamp() - startMethodEvent.getTimestamp();
116 
117         if ((totals.getCount() == 0) && (filter != null) && (filter instanceof ViewFilterItem)) {
118             totals.setTimeFrame(((ViewFilterItem)filter).getTimeFrame());
119         }
120         totals.add(endMethodEvent.getTimestamp(),  new Double(time));
121         
122         MethodAccumulation methodStat = getMethodStat(endMethodEvent.getMethodID(), endMethodEvent, filter);
123         methodStat.add(startMethodEvent, endMethodEvent);
124     }
125 
126     public void addStartedMethodEvent(ProfilerEvent event) {
127         Object methodInstanceId = getMethodInstanceId(event);
128         Queue queue = null;
129         if (!notCompletedMethodsHash.containsKey(methodInstanceId)) {
130             queue = new Queue();
131             notCompletedMethodsHash.put(methodInstanceId, queue);
132         } else {
133             queue = (Queue) notCompletedMethodsHash.get(methodInstanceId);
134         }
135         if (queue != null) {
136             queue.enqueue(event);
137         }
138     }
139     
140     public MethodAccumulation getMethodStat(Object methodId, ProfilerEvent endMethodEvent, MatchFilter filter) {
141         MethodAccumulation methodStat;
142         if (!methodStatHash.containsKey(methodId)) {
143             methodStat = new MethodAccumulation(getUiMethodName(endMethodEvent));
144             if  ((filter != null) && (filter instanceof ViewFilterItem)) {
145                 methodStat.setTimeFrame(((ViewFilterItem)filter).getTimeFrame());
146             }
147             synchronized (this) {
148                 methodStatHash.put(methodId, methodStat);
149             }
150         } else {
151             methodStat = (MethodAccumulation) methodStatHash.get(methodId);
152             if (methodStat.getCount() == 0) {
153                 if (filter instanceof ViewFilterItem) {
154                     methodStat.setTimeFrame(((ViewFilterItem)filter).getTimeFrame());
155                 }
156                 // Allow dynamic changes in name presentation.
157                 methodStat.setName(getUiMethodName(endMethodEvent));
158             }
159         }
160         return methodStat;
161     }
162 
163     /***
164      * DOCUMENT ME!
165      *
166      * @return DOCUMENT ME!
167      */
168     public synchronized Object[][] getReport() {
169         Object[][] retVal = new Object[methodStatHash.keySet().size()][10];
170         Iterator iter = methodStatHash.keySet().iterator();
171         int counter = 0;
172 				
173         while (iter.hasNext()) {
174             Object methodId = iter.next();
175             MethodAccumulation methodStat = (MethodAccumulation) methodStatHash.get(methodId);
176             retVal[counter][0] = methodStat;
177             retVal[counter][1] = methodStat.getName();
178             retVal[counter][2] = new FDouble(methodStat.getFirstRunElapsedTime());
179             retVal[counter][3] = new FDouble(methodStat.getMin());
180             retVal[counter][4] = new FDouble(methodStat.getMax());
181             retVal[counter][5] = new FDouble(methodStat.getMean());
182             retVal[counter][6] = new Long(methodStat.getCount());
183             retVal[counter][7] = new FDouble(methodStat.getStandardDeviation());
184             retVal[counter][8] = new FDouble(methodStat.getTotal());
185             retVal[counter][9] = new Long(methodStat.getExceptionCount());
186             
187             counter++;
188         }
189 
190         return retVal;
191     }
192     
193     public void writeCSV(BufferedWriter bw, Object[] line) throws IOException {
194         bw.write("\"");
195         for (int i = 1; i < line.length; i++) {
196             bw.write(line[i].toString());
197             if (i < line.length -1) {
198                 bw.write("\",\"");
199             }
200         }
201         bw.write("\"\n");
202     }
203     
204     public synchronized boolean saveReport(File file, Object[][] data) {
205         try {
206             BufferedWriter bw = new BufferedWriter(new FileWriter(file));
207             
208             writeCSV(bw, columnNames);
209             
210             for (int i = 0; i < data.length; i++) {
211                 writeCSV(bw, data[i]);
212             }
213             bw.close();
214             return true;
215         } catch (IOException e) {
216             // e.printStackTrace();
217             log.error("Error", e);
218             return false;
219         }
220         
221     }
222     
223     public synchronized void reset() {
224         totals.reset();
225         //this.methodStatHash = new HashMap();
226         Iterator iter = methodStatHash.values().iterator();
227         while (iter.hasNext()) {
228             MethodAccumulation methodStat = (MethodAccumulation) iter.next();
229             methodStat.reset();
230         }
231         // TODO fix this for runtime
232         this.notCompletedMethodsHash = new HashMap();
233         this.countTotal = 0;
234     }
235     
236 	public String getUiMethodSignature(ProfilerEvent endMethodEvent) {
237 		String s = endMethodEvent.getMethodSignature();
238 		if (s == null) {
239 			return "";
240 		}
241 		return viewFilter.getMethodsignatureView().subst(s);
242 	}
243 	
244 	private String getUiMethodName(ProfilerEvent endMethodEvent) {
245 		String method = endMethodEvent.getMethodName().trim();
246 		if (method.equals(endMethodEvent.getClassName())) {
247 			method = "<init>";
248 		} 
249 		return viewFilter.getClassnameView().subst(endMethodEvent.getClassName()) 
250 			+ "->" + method 
251 			+ getUiMethodSignature(endMethodEvent);
252 	}
253 	
254     //TODO add id for overloaded methods
255     private String x_getMethodId(String clazz, String method) {
256         return clazz.trim() + "->" + method.trim() +"";
257     }
258 
259     /***
260      * 
261      * @param clazz
262      * @param method
263      * @param threadName
264      * @return
265      */
266     //TODO add id for overloaded methods
267     private String x_getMethodInstanceId(String clazz, String method, String threadName) {
268         return clazz.trim() + "->(" + method.trim() +")[" + threadName.trim() + "]";
269     }
270     
271     /*
272 	class EventInstanceId  {
273         
274 	    Object methodID;
275 
276         Object threadID;
277         
278         EventInstanceId(Object methodID, Object threadID) {
279             this.methodID = methodID;
280             this.threadID = threadID;
281         }
282         
283         public int hashCode() {
284         	return (int)(value ^ (value >>> 32));
285         }
286 
287         public boolean equals(Object obj) {
288             if (obj instanceof EventInstanceId) {
289                 EventInstanceId e = (EventInstanceId) obj;
290                 return (this.methodID.equals(e.methodID) && this.threadID.equals(e.threadID));
291             } else {
292                 return false;
293             }
294         }
295     }
296 	*/
297 	
298     private Object getMethodInstanceId(ProfilerEvent event) {
299         //return clazz.trim() + "->(" + method.trim() +")[" + threadName.trim() + "]";
300         //return new EventInstanceId(event.getMethodID(), event.getThreadID());
301         return event.getMethodID().toString() + "@" + event.getThreadID().toString();
302     }
303 
304 		
305     /***
306      * @return Returns the totals.
307      */
308     public TimeBaseAccumulationList getTotals() {
309         return totals;
310     }
311 }