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