View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.filter.statistic;
21  
22  import java.util.HashSet;
23  import java.util.Set;
24  import java.util.concurrent.TimeUnit;
25  import java.util.concurrent.atomic.AtomicLong;
26  
27  import org.apache.mina.core.filterchain.IoFilterAdapter;
28  import org.apache.mina.core.session.IdleStatus;
29  import org.apache.mina.core.session.IoEventType;
30  import org.apache.mina.core.session.IoSession;
31  import org.apache.mina.core.write.WriteRequest;
32  
33  /**
34   * This class will measure the time it takes for a
35   * method in the {@link IoFilterAdapter} class to execute.  The basic
36   * premise of the logic in this class is to get the current time
37   * at the beginning of the method, call method on nextFilter, and
38   * then get the current time again.  An example of how to use
39   * the filter is:
40   *
41   * <pre>
42   * ProfilerTimerFilter profiler = new ProfilerTimerFilter(
43   *         TimeUnit.MILLISECOND, IoEventType.MESSAGE_RECEIVED);
44   * chain.addFirst("Profiler", profiler);
45   * </pre>
46   * 
47   * The profiled {@link IoEventType} are :
48   * <ul>
49   * <li>IoEventType.MESSAGE_RECEIVED</li>
50   * <li>IoEventType.MESSAGE_SENT</li>
51   * <li>IoEventType.SESSION_CREATED</li>
52   * <li>IoEventType.SESSION_OPENED</li>
53   * <li>IoEventType.SESSION_IDLE</li>
54   * <li>IoEventType.SESSION_CLOSED</li>
55   * </ul>
56   *
57   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
58   * @org.apache.xbean.XBean
59   */
60  public class ProfilerTimerFilter extends IoFilterAdapter {
61      /** TRhe selected time unit */
62      private volatile TimeUnit timeUnit;
63      
64      /** A TimerWorker for the MessageReceived events */
65      private TimerWorker messageReceivedTimerWorker;
66      
67      /** A flag to tell the filter that the MessageReceived must be profiled */
68      private boolean profileMessageReceived = false;
69  
70      /** A TimerWorker for the MessageSent events */
71      private TimerWorker messageSentTimerWorker;
72  
73      /** A flag to tell the filter that the MessageSent must be profiled */
74      private boolean profileMessageSent = false;
75  
76      /** A TimerWorker for the SessionCreated events */
77      private TimerWorker sessionCreatedTimerWorker;
78  
79      /** A flag to tell the filter that the SessionCreated must be profiled */
80      private boolean profileSessionCreated = false;
81  
82      /** A TimerWorker for the SessionOpened events */
83      private TimerWorker sessionOpenedTimerWorker;
84  
85      /** A flag to tell the filter that the SessionOpened must be profiled */
86      private boolean profileSessionOpened = false;
87  
88      /** A TimerWorker for the SessionIdle events */
89      private TimerWorker sessionIdleTimerWorker;
90  
91      /** A flag to tell the filter that the SessionIdle must be profiled */
92      private boolean profileSessionIdle = false;
93  
94      /** A TimerWorker for the SessionClosed events */
95      private TimerWorker sessionClosedTimerWorker;
96  
97      /** A flag to tell the filter that the SessionClosed must be profiled */
98      private boolean profileSessionClosed = false;
99  
100     /**
101      * Creates a new instance of ProfilerFilter.  This is the
102      * default constructor and will print out timings for
103      * messageReceived and messageSent and the time increment
104      * will be in milliseconds.
105      */
106     public ProfilerTimerFilter() {
107         this(
108                 TimeUnit.MILLISECONDS, 
109                 IoEventType.MESSAGE_RECEIVED, IoEventType.MESSAGE_SENT);
110     }
111     
112     /**
113      * Creates a new instance of ProfilerFilter.  This is the
114      * default constructor and will print out timings for
115      * messageReceived and messageSent.
116      * 
117      * @param timeUnit the time increment to set
118      */
119     public ProfilerTimerFilter(TimeUnit timeUnit) {
120         this(
121                 timeUnit, 
122                 IoEventType.MESSAGE_RECEIVED, IoEventType.MESSAGE_SENT);
123     }
124     
125     /**
126      * Creates a new instance of ProfilerFilter.  An example
127      * of this call would be:
128      *
129      * <pre>
130      * new ProfilerTimerFilter(
131      *         TimeUnit.MILLISECONDS,
132      *         IoEventType.MESSAGE_RECEIVED, IoEventType.MESSAGE_SENT);
133      * </pre>
134      * 
135      * Note : you can add as many {@link IoEventType} as you want. The method accepts
136      * a variable number of arguments.
137      * 
138      * @param timeUnit Used to determine the level of precision you need in your timing.
139      * @param eventTypes A list of {@link IoEventType} representation of the methods to profile
140      */
141     public ProfilerTimerFilter(TimeUnit timeUnit, IoEventType... eventTypes) {
142         this.timeUnit = timeUnit;
143 
144         setProfilers(eventTypes);
145     }
146     
147     /**
148      * Create the profilers for a list of {@link IoEventType}.
149      * 
150      * @param eventTypes the list of {@link IoEventType} to profile
151      */
152     private void setProfilers(IoEventType... eventTypes) {
153         for (IoEventType type : eventTypes) {
154             switch (type) {
155                 case MESSAGE_RECEIVED :
156                     messageReceivedTimerWorker = new TimerWorker();
157                     profileMessageReceived = true;
158                     break;
159 
160                 case MESSAGE_SENT :
161                     messageSentTimerWorker = new TimerWorker();
162                     profileMessageSent = true;
163                     break;
164 
165                 case SESSION_CREATED :
166                     sessionCreatedTimerWorker = new TimerWorker();
167                     profileSessionCreated = true;
168                     break;
169                     
170                 case SESSION_OPENED :
171                     sessionOpenedTimerWorker = new TimerWorker();
172                     profileSessionOpened = true;
173                     break;
174                     
175                 case SESSION_IDLE :
176                     sessionIdleTimerWorker = new TimerWorker();
177                     profileSessionIdle = true;
178                     break;
179                     
180                 case SESSION_CLOSED :
181                     sessionClosedTimerWorker = new TimerWorker();
182                     profileSessionClosed = true;
183                     break;
184             }
185         }
186     }
187 
188     /**
189      * Sets the {@link TimeUnit} being used.
190      *
191      * @param timeUnit the new {@link TimeUnit} to be used.
192      */
193     public void setTimeUnit(TimeUnit timeUnit) {
194         this.timeUnit = timeUnit;
195     }
196 
197     /**
198      * Set the {@link IoEventType} to be profiled
199      *
200      * @param type The {@link IoEventType} to profile
201      */
202     public void profile(IoEventType type) {
203         switch (type) {
204             case MESSAGE_RECEIVED :
205                 profileMessageReceived = true;
206                 
207                 if (messageReceivedTimerWorker == null) {
208                     messageReceivedTimerWorker = new TimerWorker();
209                 }
210                 
211                 return;
212                 
213             case MESSAGE_SENT :
214                 profileMessageSent = true;
215                 
216                 if (messageSentTimerWorker == null) {
217                     messageSentTimerWorker = new TimerWorker();
218                 }
219                 
220                 return;
221                 
222             case SESSION_CREATED :
223                 profileSessionCreated = true;
224                 
225                 if (sessionCreatedTimerWorker == null) {
226                     sessionCreatedTimerWorker = new TimerWorker();
227                 }
228                 
229                 return;
230                 
231             case SESSION_OPENED :
232                 profileSessionOpened = true;
233                 
234                 if (sessionOpenedTimerWorker == null) {
235                     sessionOpenedTimerWorker = new TimerWorker();
236                 }
237                 
238                 return;
239                 
240             case SESSION_IDLE :
241                 profileSessionIdle = true;
242                 
243                 if (sessionIdleTimerWorker == null) {
244                     sessionIdleTimerWorker = new TimerWorker();
245                 }
246                 
247                 return;
248                 
249             case SESSION_CLOSED :
250                 profileSessionClosed = true;
251                 
252                 if (sessionClosedTimerWorker == null) {
253                     sessionClosedTimerWorker = new TimerWorker();
254                 }
255                 
256                 return;
257         }
258     }
259 
260     /**
261      * Stop profiling an {@link IoEventType}
262      *
263      * @param type The {@link IoEventType} to stop profiling
264      */
265     public void stopProfile(IoEventType type) {
266         switch (type) {
267             case MESSAGE_RECEIVED :
268                 profileMessageReceived = false;
269                 return;
270                 
271             case MESSAGE_SENT :
272                 profileMessageSent = false;
273                 return;
274                 
275             case SESSION_CREATED :
276                 profileSessionCreated = false;
277                 return;
278 
279             case SESSION_OPENED :
280                 profileSessionOpened = false;
281                 return;
282 
283             case SESSION_IDLE :
284                 profileSessionIdle = false;
285                 return;
286 
287             case SESSION_CLOSED :
288                 profileSessionClosed = false;
289                 return;
290         }
291     }
292 
293     /**
294      * Return the set of {@link IoEventType} which are profiled.
295      *
296      * @return a Set containing all the profiled {@link IoEventType} 
297      */
298     public Set<IoEventType> getEventsToProfile() {
299         Set<IoEventType> set = new HashSet<IoEventType>();
300         
301         if ( profileMessageReceived ) {
302             set.add(IoEventType.MESSAGE_RECEIVED);
303         }
304         
305         if ( profileMessageSent) {
306             set.add(IoEventType.MESSAGE_SENT);
307         }
308         
309         if ( profileSessionCreated ) {
310             set.add(IoEventType.SESSION_CREATED);
311         }
312         
313         if ( profileSessionOpened ) {
314             set.add(IoEventType.SESSION_OPENED);
315         }
316         
317         if ( profileSessionIdle ) {
318             set.add(IoEventType.SESSION_IDLE);
319         }
320         
321         if ( profileSessionClosed ) {
322             set.add(IoEventType.SESSION_CLOSED);
323         }
324         
325         return set;
326     }
327 
328     /**
329      * Set the profilers for a list of {@link IoEventType}
330      * 
331      * @param eventTypes the list of {@link IoEventType} to profile
332      */
333     public void setEventsToProfile(IoEventType... eventTypes) {
334         setProfilers(eventTypes);
335     }
336 
337     /**
338      * Profile a MessageReceived event. This method will gather the following
339      * informations :
340      * - the method duration
341      * - the shortest execution time
342      * - the slowest execution time
343      * - the average execution time
344      * - the global number of calls
345      * 
346      * @param nextFilter The filter to call next
347      * @param session The associated session
348      * @param message the received message
349      */
350     @Override
351     public void messageReceived(NextFilter nextFilter, IoSession session,
352             Object message) throws Exception {
353         if (profileMessageReceived) {
354             long start = timeNow();
355             nextFilter.messageReceived(session, message);
356             long end = timeNow();
357             messageReceivedTimerWorker.addNewDuration(end - start);
358         } else {
359             nextFilter.messageReceived(session, message);
360         }
361     }
362 
363     /**
364      * Profile a MessageSent event. This method will gather the following
365      * informations :
366      * - the method duration
367      * - the shortest execution time
368      * - the slowest execution time
369      * - the average execution time
370      * - the global number of calls
371      * 
372      * @param nextFilter The filter to call next
373      * @param session The associated session
374      * @param writeRequest the sent message
375      */
376     @Override
377     public void messageSent(NextFilter nextFilter, IoSession session,
378             WriteRequest writeRequest) throws Exception {
379         if (profileMessageSent) {
380             long start = timeNow();
381             nextFilter.messageSent(session, writeRequest);
382             long end = timeNow();
383             messageSentTimerWorker.addNewDuration(end - start);
384         } else {
385             nextFilter.messageSent(session, writeRequest);
386         }
387     }
388 
389     /**
390      * Profile a SessionCreated event. This method will gather the following
391      * informations :
392      * - the method duration
393      * - the shortest execution time
394      * - the slowest execution time
395      * - the average execution time
396      * - the global number of calls
397      * 
398      * @param nextFilter The filter to call next
399      * @param session The associated session
400      */
401     @Override
402     public void sessionCreated(NextFilter nextFilter, IoSession session)
403             throws Exception {
404         if (profileSessionCreated) {
405             long start = timeNow();
406             nextFilter.sessionCreated(session);
407             long end = timeNow();
408             sessionCreatedTimerWorker.addNewDuration(end - start);
409         } else {
410             nextFilter.sessionCreated(session);
411         }
412     }
413 
414     /**
415      * Profile a SessionOpened event. This method will gather the following
416      * informations :
417      * - the method duration
418      * - the shortest execution time
419      * - the slowest execution time
420      * - the average execution time
421      * - the global number of calls
422      * 
423      * @param nextFilter The filter to call next
424      * @param session The associated session
425      */
426     @Override
427     public void sessionOpened(NextFilter nextFilter, IoSession session)
428             throws Exception {
429         if (profileSessionOpened) {
430             long start = timeNow();
431             nextFilter.sessionOpened(session);
432             long end = timeNow();
433             sessionOpenedTimerWorker.addNewDuration(end - start);
434         } else {
435             nextFilter.sessionOpened(session);
436         }
437     }
438 
439     /**
440      * Profile a SessionIdle event. This method will gather the following
441      * informations :
442      * - the method duration
443      * - the shortest execution time
444      * - the slowest execution time
445      * - the average execution time
446      * - the global number of calls
447      * 
448      * @param nextFilter The filter to call next
449      * @param session The associated session
450      * @param status The session's status
451      */
452     @Override
453     public void sessionIdle(NextFilter nextFilter, IoSession session,
454             IdleStatus status) throws Exception {
455         if (profileSessionIdle) {
456             long start = timeNow();
457             nextFilter.sessionIdle(session, status);
458             long end = timeNow();
459             sessionIdleTimerWorker.addNewDuration(end - start);
460         } else {
461             nextFilter.sessionIdle(session, status);
462         }
463     }
464 
465     /**
466      * Profile a SessionClosed event. This method will gather the following
467      * informations :
468      * - the method duration
469      * - the shortest execution time
470      * - the slowest execution time
471      * - the average execution time
472      * - the global number of calls
473      * 
474      * @param nextFilter The filter to call next
475      * @param session The associated session
476      */
477     @Override
478     public void sessionClosed(NextFilter nextFilter, IoSession session)
479             throws Exception {
480         if (profileSessionClosed) {
481             long start = timeNow();
482             nextFilter.sessionClosed(session);
483             long end = timeNow();
484             sessionClosedTimerWorker.addNewDuration(end - start);
485         } else {
486             nextFilter.sessionClosed(session);
487         }
488     }
489 
490     /**
491      * Get the average time for the specified method represented by the {@link IoEventType}
492      *
493      * @param type
494      *  The {@link IoEventType} that the user wants to get the average method call time
495      * @return
496      *  The average time it took to execute the method represented by the {@link IoEventType}
497      */
498     public double getAverageTime(IoEventType type) {
499         switch (type) {
500             case MESSAGE_RECEIVED :
501                 if (profileMessageReceived) {
502                     return messageReceivedTimerWorker.getAverage();
503                 }
504                 
505                 break;
506                 
507             case MESSAGE_SENT :
508                 if (profileMessageSent) {
509                     return messageSentTimerWorker.getAverage();
510                 }
511                 
512                 break;
513                 
514             case SESSION_CREATED :
515                 if (profileSessionCreated) {
516                     return sessionCreatedTimerWorker.getAverage();
517                 }
518                 
519                 break;
520                 
521             case SESSION_OPENED :
522                 if (profileSessionOpened) {
523                     return sessionOpenedTimerWorker.getAverage();
524                 }
525                 
526                 break;
527                 
528             case SESSION_IDLE :
529                 if (profileSessionIdle) {
530                     return sessionIdleTimerWorker.getAverage();
531                 }
532                 
533                 break;
534                 
535             case SESSION_CLOSED :
536                 if (profileSessionClosed) {
537                     return sessionClosedTimerWorker.getAverage();
538                 }
539                 
540                 break;
541         }
542 
543         throw new IllegalArgumentException(
544                 "You are not monitoring this event.  Please add this event first.");
545     }
546 
547     /**
548      * Gets the total number of times the method has been called that is represented by the
549      * {@link IoEventType}
550      *
551      * @param type
552      *  The {@link IoEventType} that the user wants to get the total number of method calls
553      * @return
554      *  The total number of method calls for the method represented by the {@link IoEventType}
555      */
556     public long getTotalCalls(IoEventType type) {
557         switch (type) {
558             case MESSAGE_RECEIVED :
559                 if (profileMessageReceived) {
560                     return messageReceivedTimerWorker.getCallsNumber();
561                 }
562                 
563                 break;
564                 
565             case MESSAGE_SENT :
566                 if (profileMessageSent) {
567                     return messageSentTimerWorker.getCallsNumber();
568                 }
569                 
570                 break;
571                 
572             case SESSION_CREATED :
573                 if (profileSessionCreated) {
574                     return sessionCreatedTimerWorker.getCallsNumber();
575                 }
576                 
577                 break;
578                 
579             case SESSION_OPENED :
580                 if (profileSessionOpened) {
581                     return sessionOpenedTimerWorker.getCallsNumber();
582                 }
583                 
584                 break;
585                 
586             case SESSION_IDLE :
587                 if (profileSessionIdle) {
588                     return sessionIdleTimerWorker.getCallsNumber();
589                 }
590                 
591                 break;
592                 
593             case SESSION_CLOSED :
594                 if (profileSessionClosed) {
595                     return sessionClosedTimerWorker.getCallsNumber();
596                 }
597                 
598                 break;
599         }
600     
601         throw new IllegalArgumentException(
602                 "You are not monitoring this event.  Please add this event first.");
603     }
604 
605     /**
606      * The total time this method has been executing
607      *
608      * @param type
609      *  The {@link IoEventType} that the user wants to get the total time this method has
610      *  been executing
611      * @return
612      *  The total time for the method represented by the {@link IoEventType}
613      */
614     public long getTotalTime(IoEventType type) {
615         switch (type) {
616             case MESSAGE_RECEIVED :
617                 if (profileMessageReceived) {
618                     return messageReceivedTimerWorker.getTotal();
619                 }
620                 
621                 break;
622                 
623             case MESSAGE_SENT :
624                 if (profileMessageSent) {
625                     return messageSentTimerWorker.getTotal();
626                 }
627                 
628                 break;
629                 
630             case SESSION_CREATED :
631                 if (profileSessionCreated) {
632                     return sessionCreatedTimerWorker.getTotal();
633                 }
634                 
635                 break;
636                 
637             case SESSION_OPENED :
638                 if (profileSessionOpened) {
639                     return sessionOpenedTimerWorker.getTotal();
640                 }
641                 
642                 break;
643                 
644             case SESSION_IDLE :
645                 if (profileSessionIdle) {
646                     return sessionIdleTimerWorker.getTotal();
647                 }
648                 
649                 break;
650                 
651             case SESSION_CLOSED :
652                 if (profileSessionClosed) {
653                     return sessionClosedTimerWorker.getTotal();
654                 }
655                 
656                 break;
657         }
658     
659         throw new IllegalArgumentException(
660                 "You are not monitoring this event.  Please add this event first.");
661     }
662 
663     /**
664      * The minimum time the method represented by {@link IoEventType} has executed
665      *
666      * @param type
667      *  The {@link IoEventType} that the user wants to get the minimum time this method has
668      *  executed
669      * @return
670      *  The minimum time this method has executed represented by the {@link IoEventType}
671      */
672     public long getMinimumTime(IoEventType type) {
673         switch (type) {
674             case MESSAGE_RECEIVED :
675                 if (profileMessageReceived) {
676                     return messageReceivedTimerWorker.getMinimum();
677                 }
678                 
679                 break;
680                 
681             case MESSAGE_SENT :
682                 if (profileMessageSent) {
683                     return messageSentTimerWorker.getMinimum();
684                 }
685                 
686                 break;
687                 
688             case SESSION_CREATED :
689                 if (profileSessionCreated) {
690                     return sessionCreatedTimerWorker.getMinimum();
691                 }
692                 
693                 break;
694                 
695             case SESSION_OPENED :
696                 if (profileSessionOpened) {
697                     return sessionOpenedTimerWorker.getMinimum();
698                 }
699                 
700                 break;
701                 
702             case SESSION_IDLE :
703                 if (profileSessionIdle) {
704                     return sessionIdleTimerWorker.getMinimum();
705                 }
706                 
707                 break;
708                 
709             case SESSION_CLOSED :
710                 if (profileSessionClosed) {
711                     return sessionClosedTimerWorker.getMinimum();
712                 }
713                 
714                 break;
715         }
716     
717         throw new IllegalArgumentException(
718                 "You are not monitoring this event.  Please add this event first.");
719     }
720 
721     /**
722      * The maximum time the method represented by {@link IoEventType} has executed
723      *
724      * @param type
725      *  The {@link IoEventType} that the user wants to get the maximum time this method has
726      *  executed
727      * @return
728      *  The maximum time this method has executed represented by the {@link IoEventType}
729      */
730     public long getMaximumTime(IoEventType type) {
731         switch (type) {
732             case MESSAGE_RECEIVED :
733                 if (profileMessageReceived) {
734                     return messageReceivedTimerWorker.getMaximum();
735                 }
736                 
737                 break;
738                 
739             case MESSAGE_SENT :
740                 if (profileMessageSent) {
741                     return messageSentTimerWorker.getMaximum();
742                 }
743                 
744                 break;
745                 
746             case SESSION_CREATED :
747                 if (profileSessionCreated) {
748                     return sessionCreatedTimerWorker.getMaximum();
749                 }
750                 
751                 break;
752                 
753             case SESSION_OPENED :
754                 if (profileSessionOpened) {
755                     return sessionOpenedTimerWorker.getMaximum();
756                 }
757                 
758                 break;
759                 
760             case SESSION_IDLE :
761                 if (profileSessionIdle) {
762                     return sessionIdleTimerWorker.getMaximum();
763                 }
764                 
765                 break;
766                 
767             case SESSION_CLOSED :
768                 if (profileSessionClosed) {
769                     return sessionClosedTimerWorker.getMaximum();
770                 }
771                 
772                 break;
773         }
774         
775         throw new IllegalArgumentException(
776                 "You are not monitoring this event.  Please add this event first.");
777     }
778 
779     /**
780      * Class that will track the time each method takes and be able to provide information
781      * for each method.
782      *
783      */
784     private class TimerWorker {
785         /** The sum of all operation durations */
786         private final AtomicLong total;
787         
788         /** The number of calls */
789         private final AtomicLong callsNumber;
790         
791         /** The fastest operation */
792         private final AtomicLong minimum;
793         
794         /** The slowest operation */
795         private final AtomicLong maximum;
796         
797         /** A lock for synchinized blocks */
798         private final Object lock = new Object();
799 
800         /**
801          * Creates a new instance of TimerWorker.
802          *
803          */
804         public TimerWorker() {
805             total = new AtomicLong();
806             callsNumber = new AtomicLong();
807             minimum = new AtomicLong();
808             maximum = new AtomicLong();
809         }
810 
811         /**
812          * Add a new operation duration to this class.  Total is updated
813          * and calls is incremented
814          *
815          * @param duration
816          *  The new operation duration
817          */
818         public void addNewDuration(long duration) {
819             callsNumber.incrementAndGet();
820             total.addAndGet(duration);
821 
822             synchronized (lock) {
823                 // this is not entirely thread-safe, must lock
824                 if (duration < minimum.longValue()) {
825                     minimum.set(duration);
826                 }
827 
828                 // this is not entirely thread-safe, must lock
829                 if (duration > maximum.longValue()) {
830                     maximum.set(duration);
831                 }
832             }
833         }
834 
835         /**
836          * Gets the average reading for this event
837          *
838          * @return the average reading for this event
839          */
840         public double getAverage() {
841             synchronized (lock) {
842                 // There are two operations, we need to synchronize the block
843                 return total.longValue() / callsNumber.longValue();
844             }
845         }
846 
847         /**
848          * Returns the total number of profiled operations
849          *
850          * @return The total number of profiled operation 
851          */
852         public long getCallsNumber() {
853             return callsNumber.longValue();
854         }
855 
856         /**
857          * Returns the total time
858          *
859          * @return the total time
860          */
861         public long getTotal() {
862             return total.longValue();
863         }
864 
865         /**
866          * Returns the lowest execution time 
867          *
868          * @return the lowest execution time
869          */
870         public long getMinimum() {
871             return minimum.longValue();
872         }
873 
874         /**
875          * Returns the longest execution time
876          *
877          * @return the longest execution time
878          */
879         public long getMaximum() {
880             return maximum.longValue();
881         }
882     }
883 
884     /**
885      * @return the current time, expressed using the fixed TimeUnit.
886      */
887     private long timeNow() {
888         switch (timeUnit) {
889             case SECONDS :
890                 return System.currentTimeMillis()/1000;
891                 
892             case MICROSECONDS :
893                 return System.nanoTime()/1000;
894                 
895             case NANOSECONDS :
896                 return System.nanoTime();
897                 
898             default :
899                 return System.currentTimeMillis();
900         }
901     }
902 }