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             case SESSION_OPENED :
230                 profileSessionOpened = true;
231                 
232                 if (sessionOpenedTimerWorker == null) {
233                     sessionOpenedTimerWorker = new TimerWorker();
234                 }
235                 
236             case SESSION_IDLE :
237                 profileSessionIdle = true;
238                 
239                 if (sessionIdleTimerWorker == null) {
240                     sessionIdleTimerWorker = new TimerWorker();
241                 }
242                 
243             case SESSION_CLOSED :
244                 profileSessionClosed = true;
245                 
246                 if (sessionClosedTimerWorker == null) {
247                     sessionClosedTimerWorker = new TimerWorker();
248                 }
249         }
250     }
251 
252     /**
253      * Stop profiling an {@link IoEventType}
254      *
255      * @param type The {@link IoEventType} to stop profiling
256      */
257     public void stopProfile(IoEventType type) {
258         switch (type) {
259             case MESSAGE_RECEIVED :
260                 profileMessageReceived = false;
261                 return;
262                 
263             case MESSAGE_SENT :
264                 profileMessageSent = false;
265                 return;
266                 
267             case SESSION_CREATED :
268                 profileSessionCreated = false;
269                 return;
270 
271             case SESSION_OPENED :
272                 profileSessionOpened = false;
273                 return;
274 
275             case SESSION_IDLE :
276                 profileSessionIdle = false;
277                 return;
278 
279             case SESSION_CLOSED :
280                 profileSessionClosed = false;
281                 return;
282         }
283     }
284 
285     /**
286      * Return the set of {@link IoEventType} which are profiled.
287      *
288      * @return a Set containing all the profiled {@link IoEventType} 
289      */
290     public Set<IoEventType> getEventsToProfile() {
291         Set<IoEventType> set = new HashSet<IoEventType>();
292         
293         if ( profileMessageReceived ) {
294             set.add(IoEventType.MESSAGE_RECEIVED);
295         }
296         
297         if ( profileMessageSent) {
298             set.add(IoEventType.MESSAGE_SENT);
299         }
300         
301         if ( profileSessionCreated ) {
302             set.add(IoEventType.SESSION_CREATED);
303         }
304         
305         if ( profileSessionOpened ) {
306             set.add(IoEventType.SESSION_OPENED);
307         }
308         
309         if ( profileSessionIdle ) {
310             set.add(IoEventType.SESSION_IDLE);
311         }
312         
313         if ( profileSessionClosed ) {
314             set.add(IoEventType.SESSION_CLOSED);
315         }
316         
317         return set;
318     }
319 
320     /**
321      * Set the profilers for a list of {@link IoEventType}
322      * 
323      * @param eventTypes the list of {@link IoEventType} to profile
324      */
325     public void setEventsToProfile(IoEventType... eventTypes) {
326         setProfilers(eventTypes);
327     }
328 
329     /**
330      * Profile a MessageReceived event. This method will gather the following
331      * informations :
332      * - the method duration
333      * - the shortest execution time
334      * - the slowest execution time
335      * - the average execution time
336      * - the global number of calls
337      * 
338      * @param nextFilter The filter to call next
339      * @param session The associated session
340      * @param message the received message
341      */
342     @Override
343     public void messageReceived(NextFilter nextFilter, IoSession session,
344             Object message) throws Exception {
345         if (profileMessageReceived) {
346             long start = timeNow();
347             nextFilter.messageReceived(session, message);
348             long end = timeNow();
349             messageReceivedTimerWorker.addNewDuration(end - start);
350         } else {
351             nextFilter.messageReceived(session, message);
352         }
353     }
354 
355     /**
356      * Profile a MessageSent event. This method will gather the following
357      * informations :
358      * - the method duration
359      * - the shortest execution time
360      * - the slowest execution time
361      * - the average execution time
362      * - the global number of calls
363      * 
364      * @param nextFilter The filter to call next
365      * @param session The associated session
366      * @param writeRequest the sent message
367      */
368     @Override
369     public void messageSent(NextFilter nextFilter, IoSession session,
370             WriteRequest writeRequest) throws Exception {
371         if (profileMessageSent) {
372             long start = timeNow();
373             nextFilter.messageSent(session, writeRequest);
374             long end = timeNow();
375             messageSentTimerWorker.addNewDuration(end - start);
376         } else {
377             nextFilter.messageSent(session, writeRequest);
378         }
379     }
380 
381     /**
382      * Profile a SessionCreated event. This method will gather the following
383      * informations :
384      * - the method duration
385      * - the shortest execution time
386      * - the slowest execution time
387      * - the average execution time
388      * - the global number of calls
389      * 
390      * @param nextFilter The filter to call next
391      * @param session The associated session
392      */
393     @Override
394     public void sessionCreated(NextFilter nextFilter, IoSession session)
395             throws Exception {
396         if (profileSessionCreated) {
397             long start = timeNow();
398             nextFilter.sessionCreated(session);
399             long end = timeNow();
400             sessionCreatedTimerWorker.addNewDuration(end - start);
401         } else {
402             nextFilter.sessionCreated(session);
403         }
404     }
405 
406     /**
407      * Profile a SessionOpened event. This method will gather the following
408      * informations :
409      * - the method duration
410      * - the shortest execution time
411      * - the slowest execution time
412      * - the average execution time
413      * - the global number of calls
414      * 
415      * @param nextFilter The filter to call next
416      * @param session The associated session
417      */
418     @Override
419     public void sessionOpened(NextFilter nextFilter, IoSession session)
420             throws Exception {
421         if (profileSessionOpened) {
422             long start = timeNow();
423             nextFilter.sessionOpened(session);
424             long end = timeNow();
425             sessionOpenedTimerWorker.addNewDuration(end - start);
426         } else {
427             nextFilter.sessionOpened(session);
428         }
429     }
430 
431     /**
432      * Profile a SessionIdle event. This method will gather the following
433      * informations :
434      * - the method duration
435      * - the shortest execution time
436      * - the slowest execution time
437      * - the average execution time
438      * - the global number of calls
439      * 
440      * @param nextFilter The filter to call next
441      * @param session The associated session
442      * @param status The session's status
443      */
444     @Override
445     public void sessionIdle(NextFilter nextFilter, IoSession session,
446             IdleStatus status) throws Exception {
447         if (profileSessionIdle) {
448             long start = timeNow();
449             nextFilter.sessionIdle(session, status);
450             long end = timeNow();
451             sessionIdleTimerWorker.addNewDuration(end - start);
452         } else {
453             nextFilter.sessionIdle(session, status);
454         }
455     }
456 
457     /**
458      * Profile a SessionClosed event. This method will gather the following
459      * informations :
460      * - the method duration
461      * - the shortest execution time
462      * - the slowest execution time
463      * - the average execution time
464      * - the global number of calls
465      * 
466      * @param nextFilter The filter to call next
467      * @param session The associated session
468      */
469     @Override
470     public void sessionClosed(NextFilter nextFilter, IoSession session)
471             throws Exception {
472         if (profileSessionClosed) {
473             long start = timeNow();
474             nextFilter.sessionClosed(session);
475             long end = timeNow();
476             sessionClosedTimerWorker.addNewDuration(end - start);
477         } else {
478             nextFilter.sessionClosed(session);
479         }
480     }
481 
482     /**
483      * Get the average time for the specified method represented by the {@link IoEventType}
484      *
485      * @param type
486      *  The {@link IoEventType} that the user wants to get the average method call time
487      * @return
488      *  The average time it took to execute the method represented by the {@link IoEventType}
489      */
490     public double getAverageTime(IoEventType type) {
491         switch (type) {
492             case MESSAGE_RECEIVED :
493                 if (profileMessageReceived) {
494                     return messageReceivedTimerWorker.getAverage();
495                 }
496                 
497                 break;
498                 
499             case MESSAGE_SENT :
500                 if (profileMessageSent) {
501                     return messageSentTimerWorker.getAverage();
502                 }
503                 
504                 break;
505                 
506             case SESSION_CREATED :
507                 if (profileSessionCreated) {
508                     return sessionCreatedTimerWorker.getAverage();
509                 }
510                 
511                 break;
512                 
513             case SESSION_OPENED :
514                 if (profileSessionOpened) {
515                     return sessionOpenedTimerWorker.getAverage();
516                 }
517                 
518                 break;
519                 
520             case SESSION_IDLE :
521                 if (profileSessionIdle) {
522                     return sessionIdleTimerWorker.getAverage();
523                 }
524                 
525                 break;
526                 
527             case SESSION_CLOSED :
528                 if (profileSessionClosed) {
529                     return sessionClosedTimerWorker.getAverage();
530                 }
531                 
532                 break;
533         }
534 
535         throw new IllegalArgumentException(
536                 "You are not monitoring this event.  Please add this event first.");
537     }
538 
539     /**
540      * Gets the total number of times the method has been called that is represented by the
541      * {@link IoEventType}
542      *
543      * @param type
544      *  The {@link IoEventType} that the user wants to get the total number of method calls
545      * @return
546      *  The total number of method calls for the method represented by the {@link IoEventType}
547      */
548     public long getTotalCalls(IoEventType type) {
549         switch (type) {
550             case MESSAGE_RECEIVED :
551                 if (profileMessageReceived) {
552                     return messageReceivedTimerWorker.getCallsNumber();
553                 }
554                 
555                 break;
556                 
557             case MESSAGE_SENT :
558                 if (profileMessageSent) {
559                     return messageSentTimerWorker.getCallsNumber();
560                 }
561                 
562                 break;
563                 
564             case SESSION_CREATED :
565                 if (profileSessionCreated) {
566                     return sessionCreatedTimerWorker.getCallsNumber();
567                 }
568                 
569                 break;
570                 
571             case SESSION_OPENED :
572                 if (profileSessionOpened) {
573                     return sessionOpenedTimerWorker.getCallsNumber();
574                 }
575                 
576                 break;
577                 
578             case SESSION_IDLE :
579                 if (profileSessionIdle) {
580                     return sessionIdleTimerWorker.getCallsNumber();
581                 }
582                 
583                 break;
584                 
585             case SESSION_CLOSED :
586                 if (profileSessionClosed) {
587                     return sessionClosedTimerWorker.getCallsNumber();
588                 }
589                 
590                 break;
591         }
592     
593         throw new IllegalArgumentException(
594                 "You are not monitoring this event.  Please add this event first.");
595     }
596 
597     /**
598      * The total time this method has been executing
599      *
600      * @param type
601      *  The {@link IoEventType} that the user wants to get the total time this method has
602      *  been executing
603      * @return
604      *  The total time for the method represented by the {@link IoEventType}
605      */
606     public long getTotalTime(IoEventType type) {
607         switch (type) {
608             case MESSAGE_RECEIVED :
609                 if (profileMessageReceived) {
610                     return messageReceivedTimerWorker.getTotal();
611                 }
612                 
613                 break;
614                 
615             case MESSAGE_SENT :
616                 if (profileMessageSent) {
617                     return messageSentTimerWorker.getTotal();
618                 }
619                 
620                 break;
621                 
622             case SESSION_CREATED :
623                 if (profileSessionCreated) {
624                     return sessionCreatedTimerWorker.getTotal();
625                 }
626                 
627                 break;
628                 
629             case SESSION_OPENED :
630                 if (profileSessionOpened) {
631                     return sessionOpenedTimerWorker.getTotal();
632                 }
633                 
634                 break;
635                 
636             case SESSION_IDLE :
637                 if (profileSessionIdle) {
638                     return sessionIdleTimerWorker.getTotal();
639                 }
640                 
641                 break;
642                 
643             case SESSION_CLOSED :
644                 if (profileSessionClosed) {
645                     return sessionClosedTimerWorker.getTotal();
646                 }
647                 
648                 break;
649         }
650     
651         throw new IllegalArgumentException(
652                 "You are not monitoring this event.  Please add this event first.");
653     }
654 
655     /**
656      * The minimum time the method represented by {@link IoEventType} has executed
657      *
658      * @param type
659      *  The {@link IoEventType} that the user wants to get the minimum time this method has
660      *  executed
661      * @return
662      *  The minimum time this method has executed represented by the {@link IoEventType}
663      */
664     public long getMinimumTime(IoEventType type) {
665         switch (type) {
666             case MESSAGE_RECEIVED :
667                 if (profileMessageReceived) {
668                     return messageReceivedTimerWorker.getMinimum();
669                 }
670                 
671                 break;
672                 
673             case MESSAGE_SENT :
674                 if (profileMessageSent) {
675                     return messageSentTimerWorker.getMinimum();
676                 }
677                 
678                 break;
679                 
680             case SESSION_CREATED :
681                 if (profileSessionCreated) {
682                     return sessionCreatedTimerWorker.getMinimum();
683                 }
684                 
685                 break;
686                 
687             case SESSION_OPENED :
688                 if (profileSessionOpened) {
689                     return sessionOpenedTimerWorker.getMinimum();
690                 }
691                 
692                 break;
693                 
694             case SESSION_IDLE :
695                 if (profileSessionIdle) {
696                     return sessionIdleTimerWorker.getMinimum();
697                 }
698                 
699                 break;
700                 
701             case SESSION_CLOSED :
702                 if (profileSessionClosed) {
703                     return sessionClosedTimerWorker.getMinimum();
704                 }
705                 
706                 break;
707         }
708     
709         throw new IllegalArgumentException(
710                 "You are not monitoring this event.  Please add this event first.");
711     }
712 
713     /**
714      * The maximum time the method represented by {@link IoEventType} has executed
715      *
716      * @param type
717      *  The {@link IoEventType} that the user wants to get the maximum time this method has
718      *  executed
719      * @return
720      *  The maximum time this method has executed represented by the {@link IoEventType}
721      */
722     public long getMaximumTime(IoEventType type) {
723         switch (type) {
724             case MESSAGE_RECEIVED :
725                 if (profileMessageReceived) {
726                     return messageReceivedTimerWorker.getMaximum();
727                 }
728                 
729                 break;
730                 
731             case MESSAGE_SENT :
732                 if (profileMessageSent) {
733                     return messageSentTimerWorker.getMaximum();
734                 }
735                 
736                 break;
737                 
738             case SESSION_CREATED :
739                 if (profileSessionCreated) {
740                     return sessionCreatedTimerWorker.getMaximum();
741                 }
742                 
743                 break;
744                 
745             case SESSION_OPENED :
746                 if (profileSessionOpened) {
747                     return sessionOpenedTimerWorker.getMaximum();
748                 }
749                 
750                 break;
751                 
752             case SESSION_IDLE :
753                 if (profileSessionIdle) {
754                     return sessionIdleTimerWorker.getMaximum();
755                 }
756                 
757                 break;
758                 
759             case SESSION_CLOSED :
760                 if (profileSessionClosed) {
761                     return sessionClosedTimerWorker.getMaximum();
762                 }
763                 
764                 break;
765         }
766         
767         throw new IllegalArgumentException(
768                 "You are not monitoring this event.  Please add this event first.");
769     }
770 
771     /**
772      * Class that will track the time each method takes and be able to provide information
773      * for each method.
774      *
775      */
776     private class TimerWorker {
777         /** The sum of all operation durations */
778         private final AtomicLong total;
779         
780         /** The number of calls */
781         private final AtomicLong callsNumber;
782         
783         /** The fastest operation */
784         private final AtomicLong minimum;
785         
786         /** The slowest operation */
787         private final AtomicLong maximum;
788         
789         /** A lock for synchinized blocks */
790         private final Object lock = new Object();
791 
792         /**
793          * Creates a new instance of TimerWorker.
794          *
795          */
796         public TimerWorker() {
797             total = new AtomicLong();
798             callsNumber = new AtomicLong();
799             minimum = new AtomicLong();
800             maximum = new AtomicLong();
801         }
802 
803         /**
804          * Add a new operation duration to this class.  Total is updated
805          * and calls is incremented
806          *
807          * @param duration
808          *  The new operation duration
809          */
810         public void addNewDuration(long duration) {
811             callsNumber.incrementAndGet();
812             total.addAndGet(duration);
813 
814             synchronized (lock) {
815                 // this is not entirely thread-safe, must lock
816                 if (duration < minimum.longValue()) {
817                     minimum.set(duration);
818                 }
819 
820                 // this is not entirely thread-safe, must lock
821                 if (duration > maximum.longValue()) {
822                     maximum.set(duration);
823                 }
824             }
825         }
826 
827         /**
828          * Gets the average reading for this event
829          *
830          * @return the average reading for this event
831          */
832         public double getAverage() {
833             synchronized (lock) {
834                 // There are two operations, we need to synchronize the block
835                 return total.longValue() / callsNumber.longValue();
836             }
837         }
838 
839         /**
840          * Returns the total number of profiled operations
841          *
842          * @return The total number of profiled operation 
843          */
844         public long getCallsNumber() {
845             return callsNumber.longValue();
846         }
847 
848         /**
849          * Returns the total time
850          *
851          * @return the total time
852          */
853         public long getTotal() {
854             return total.longValue();
855         }
856 
857         /**
858          * Returns the lowest execution time 
859          *
860          * @return the lowest execution time
861          */
862         public long getMinimum() {
863             return minimum.longValue();
864         }
865 
866         /**
867          * Returns the longest execution time
868          *
869          * @return the longest execution time
870          */
871         public long getMaximum() {
872             return maximum.longValue();
873         }
874     }
875 
876     /**
877      * @return the current time, expressed using the fixed TimeUnit.
878      */
879     private long timeNow() {
880         switch (timeUnit) {
881             case SECONDS :
882                 return System.currentTimeMillis()/1000;
883                 
884             case MICROSECONDS :
885                 return System.nanoTime()/1000;
886                 
887             case NANOSECONDS :
888                 return System.nanoTime();
889                 
890             default :
891                 return System.currentTimeMillis();
892         }
893     }
894 }