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