KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jmeter > reporters > Summariser


1 // $Header: /home/cvs/jakarta-jmeter/src/core/org/apache/jmeter/reporters/Summariser.java,v 1.5.2.3 2004/06/18 17:14:54 sebb Exp $
2
/*
3  * Copyright 2003-2004 The Apache Software Foundation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17 */

18
19 package org.apache.jmeter.reporters;
20
21 import java.io.Serializable JavaDoc;
22 import java.text.DecimalFormat JavaDoc;
23 import java.util.Hashtable JavaDoc;
24
25 import org.apache.jmeter.engine.event.LoopIterationEvent;
26 import org.apache.jmeter.samplers.Clearable;
27 import org.apache.jmeter.samplers.SampleEvent;
28 import org.apache.jmeter.samplers.SampleListener;
29 import org.apache.jmeter.samplers.SampleResult;
30 import org.apache.jmeter.testelement.AbstractTestElement;
31 import org.apache.jmeter.testelement.TestListener;
32 import org.apache.jmeter.util.JMeterUtils;
33 import org.apache.jmeter.visualizers.RunningSample;
34 import org.apache.jorphan.logging.LoggingManager;
35 import org.apache.jorphan.util.JOrphanUtils;
36 import org.apache.log.Logger;
37
38 /**
39  * Generate a summary of the test run so far to the log file and/or
40  * standard output. Both running and differential totals are shown.
41  * Output is generated every n seconds (default 3 minutes) on the appropriate
42  * time boundary, so that multiple test runs on the same time will be
43  * synchronised.
44  *
45  * This is mainly intended for batch (non-GUI) runs
46  *
47  * @version $Revision: 1.5.2.3 $ Last updated: $Date: 2004/06/18 17:14:54 $
48  */

49 public class Summariser
50     extends AbstractTestElement
51     implements Serializable JavaDoc,
52     SampleListener,
53     TestListener,
54     Clearable
55 {
56     private static final Logger log = LoggingManager.getLoggerForClass();
57     
58     /** interval between summaries (in seconds) default 3 minutes*/
59     private static final long INTERVAL =
60         JMeterUtils.getPropDefault("summariser.interval",3*60); //$NON-NLS-1$
61

62     /** Write messages to log file ?*/
63     private static final boolean TOLOG =
64         JMeterUtils.getPropDefault("summariser.log",true); //$NON-NLS-1$
65

66     /** Write messages to System.out ?*/
67     private static final boolean TOOUT =
68         JMeterUtils.getPropDefault("summariser.out",true); //$NON-NLS-1$
69

70     /**
71      * Summariser elements are cloned for each thread in each group;
72      * this Map is used to allow them to share the same statistics.
73      * The key is the Summariser name, so all Summarisers with the same name
74      * will use the same accumulators.
75      */

76     private static Hashtable JavaDoc accumulators = new Hashtable JavaDoc();
77
78     /*
79      * Constructor is initially called once for each occurrence in the test plan
80      * For GUI, several more instances are created
81      * Then clear is called at start of test
82      * Called several times during test startup
83      * The name will not necessarily have been set at this point.
84      */

85     public Summariser(){
86         super();
87         //log.debug(Thread.currentThread().getName());
88
//System.out.println(">> "+me+" "+this.getName()+" "+Thread.currentThread().getName());
89
}
90
91     /*
92      * Constructor for use during startup
93      * (intended for non-GUI use)
94      * @param name of summariser
95      */

96     public Summariser(String JavaDoc name){
97         this();
98         setName(name);
99     }
100     
101     /*
102      * This is called once for each occurrence in the test plan, before the start of the test.
103      * The super.clear() method clears the name (and all other properties),
104      * so it is called last.
105      */

106     public void clear()
107     {
108         //System.out.println("-- "+me+this.getName()+" "+Thread.currentThread().getName());
109

110         myName = this.getName();
111
112         // Hashtable is synchronised, but there could be more than one Summariser
113
// with the same name, so we need to synch.
114
synchronized(accumulators){
115             Totals tots = (Totals) accumulators.get(myName);
116             if (tots != null){// This can be null (before first sample)
117
tots.clear();
118             } else {
119                 //System.out.println("Creating totals for "+myName);
120
tots = new Totals();
121                 accumulators.put(myName,tots);
122             }
123         }
124
125         super.clear();
126     }
127     
128     /**
129      * Contains the items needed to collect stats for a summariser
130      *
131      * @version $revision$ Last updated: $date$
132      */

133     private static class Totals{
134
135         /** Time of last summary (to prevent double reporting) */
136         private long last = 0;// set to -1 by TestEnded to prevent double reporting
137

138         private RunningSample delta = new RunningSample("DELTA",0);
139         private RunningSample total = new RunningSample("TOTAL",0);
140
141         private void clear(){
142             delta.clear();
143             total.clear();
144             last = 0;
145         }
146         
147         /**
148          * Add the delta values to the total values and clear the delta
149          */

150         private synchronized void moveDelta(){
151             total.addSample(delta);
152             delta.clear();
153         }
154     }
155     
156     /**
157      * Cached copy of Totals for this instance
158      * These do not need to be synchronised, as they are not shared
159      * between threads
160      */

161     transient private Totals myTotals = null;
162     transient private String JavaDoc myName;
163
164
165     /**
166      * Ensure that a report is not skipped if we are slightly late in checking
167      * the time.
168      */

169     private static final int INTERVAL_WINDOW = 5; // in seconds
170

171     /**
172      * Accumulates the sample in two SampleResult objects
173      * - one for running totals, and the other for deltas
174      *
175      * @see org.apache.jmeter.samplers.SampleListener#sampleOccurred(org.apache.jmeter.samplers.SampleEvent)
176      */

177     public void sampleOccurred(SampleEvent e) {
178         SampleResult s = e.getResult();
179
180         //System.out.println("SO "+me+this.getName()+" "+Thread.currentThread().getName()
181
//+" "+s.getSampleLabel());
182

183         if (myName == null) myName = getName();
184
185         if (myTotals == null) myTotals = (Totals) accumulators.get(myName);
186
187         if (s != null)
188         {
189             myTotals.delta.addSample(s);
190         }
191
192         long now = System.currentTimeMillis()/1000;// in seconds
193

194          RunningSample myDelta=null;
195          RunningSample myTotal=null;
196          boolean reportNow = false;
197
198         /* Have we reached the reporting boundary?
199          * Need to allow for a margin of error, otherwise can miss the slot
200          * Also need to check we've not hit the window already
201          */

202          synchronized(myTotals){
203             if ((now > myTotals.last + INTERVAL_WINDOW) && (now % INTERVAL <= INTERVAL_WINDOW))
204             {
205                 reportNow=true;
206                 myDelta = new RunningSample(myTotals.delta);// copy the data to minimise ...
207
myTotals.moveDelta();
208                 myTotal = new RunningSample(myTotals.total);// ... the synch time
209
myTotals.last = now;
210             }
211         }
212         if (reportNow){
213             String JavaDoc str;
214             str = format(myDelta,"+");
215             if (TOLOG) log.info(str);
216             if (TOOUT) System.out.println(str);
217     
218             if (myTotal.getNumSamples() != myDelta.getNumSamples()) {// Only if we have updated them
219
str = format(myTotal,"=");
220                 if (TOLOG) log.info(str);
221                 if (TOOUT) System.out.println(str);
222             }
223         }
224     }
225
226     private static StringBuffer JavaDoc longToSb(StringBuffer JavaDoc sb,long l, int len){
227         sb.setLength(0);
228         sb.append(l);
229         return JOrphanUtils.rightAlign(sb,len);
230     }
231     
232     private static DecimalFormat JavaDoc dfDouble = new DecimalFormat JavaDoc("#0.0");
233     private static StringBuffer JavaDoc doubleToSb(StringBuffer JavaDoc sb,double d, int len, int frac){
234         sb.setLength(0);
235         dfDouble.setMinimumFractionDigits(frac);
236         dfDouble.setMaximumFractionDigits(frac);
237         sb.append(dfDouble.format(d));
238         return JOrphanUtils.rightAlign(sb,len);
239     }
240     /**
241      * @param myTotal
242      * @param string
243      * @return
244      */

245     private String JavaDoc format(RunningSample s, String JavaDoc type)
246     {
247         StringBuffer JavaDoc tmp = new StringBuffer JavaDoc(20); // for intermediate use
248
StringBuffer JavaDoc sb = new StringBuffer JavaDoc(100); // output line buffer
249
sb.append(myName);
250         sb.append(" ");
251         sb.append(type);
252         sb.append(" ");
253         sb.append(longToSb(tmp,s.getNumSamples(),5));
254         sb.append(" in ");
255         long elapsed = s.getElapsed();
256         sb.append(doubleToSb(tmp,(double)elapsed/1000.0,5,1));
257         sb.append("s = ");
258         if (elapsed > 0)
259         {
260             sb.append(doubleToSb(tmp,s.getRate(),6,1));
261         }
262         else
263         {
264             sb.append("******");// Rate is effectively infinite
265
}
266         sb.append("/s Avg: ");
267         sb.append(longToSb(tmp,s.getAverage(),5));
268         sb.append(" Min: ");
269         sb.append(longToSb(tmp,s.getMin(),5));
270         sb.append(" Max: ");
271         sb.append(longToSb(tmp,s.getMax(),5));
272         sb.append(" Err: ");
273         sb.append(longToSb(tmp,s.getErrorCount(),5));
274         sb.append(" (");
275         sb.append(s.getErrorPercentageString());
276         sb.append(")");
277         return sb.toString();
278     }
279
280
281     /* (non-Javadoc)
282      * @see org.apache.jmeter.samplers.SampleListener#sampleStarted(org.apache.jmeter.samplers.SampleEvent)
283      */

284     public void sampleStarted(SampleEvent e)
285     {
286         // not used
287
}
288
289     /* (non-Javadoc)
290      * @see org.apache.jmeter.samplers.SampleListener#sampleStopped(org.apache.jmeter.samplers.SampleEvent)
291      */

292     public void sampleStopped(SampleEvent e) {
293         // not used
294
}
295
296     /* (non-Javadoc)
297      * @see org.apache.jmeter.testelement.TestListener#testStarted()
298      */

299     public void testStarted()
300     {
301         // not used
302
}
303     /* (non-Javadoc)
304      * @see org.apache.jmeter.testelement.TestListener#testEnded()
305      */

306     public void testEnded()
307     {
308         testEnded("local");
309         
310     }
311     /* (non-Javadoc)
312      * @see org.apache.jmeter.testelement.TestListener#testStarted(java.lang.String)
313      */

314     public void testStarted(String JavaDoc host)
315     {
316      // not used
317
}
318     /* (non-Javadoc)
319      * Can be called more than once with the same name, so need to synch.
320      * However, there is no need to create copies, to shorten the synch zone,
321      * as timing is not critical at the end of the test.
322      *
323      * @see org.apache.jmeter.testelement.TestListener#testEnded(java.lang.String)
324      */

325     public void testEnded(String JavaDoc host)
326     {
327         //System.out.println("TE "+me+this.getName()+" "+Thread.currentThread().getName());
328
synchronized(accumulators){
329             Totals t = (Totals) accumulators.get(myName);
330             if (t.last != -1){
331                 String JavaDoc str;
332                 if (t.total.getNumSamples() != 0){//Only print delta if different from total
333
str = format(t.delta,"+");
334                     if (TOLOG) log.info(str);
335                     if (TOOUT) System.out.println(str);
336                 }
337                 t.moveDelta();
338                 str = format(t.total,"=");
339                 if (TOLOG) log.info(str);
340                 if (TOOUT) System.out.println(str);
341                 t.last = -1;
342             }
343         }
344     }
345     /* (non-Javadoc)
346      * @see org.apache.jmeter.testelement.TestListener#testIterationStart(org.apache.jmeter.engine.event.LoopIterationEvent)
347      */

348     public void testIterationStart(LoopIterationEvent event)
349     {
350         // not used
351
}
352
353 }
354
Popular Tags