Merge "Do not require namespace repairing"
[yangtools.git] / common / util / src / main / java / org / opendaylight / yangtools / util / DurationStatsTracker.java
1 /*
2  * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.yangtools.util;
10
11 import static java.util.concurrent.TimeUnit.MICROSECONDS;
12 import static java.util.concurrent.TimeUnit.MILLISECONDS;
13 import static java.util.concurrent.TimeUnit.NANOSECONDS;
14 import static java.util.concurrent.TimeUnit.SECONDS;
15
16 import java.util.Date;
17 import java.util.concurrent.TimeUnit;
18 import java.util.concurrent.atomic.AtomicLong;
19
20 import com.google.common.util.concurrent.AtomicDouble;
21
22 /**
23  * Class that calculates and tracks time duration statistics.
24  *
25  * @author Thomas Pantelis
26  */
27 public class DurationStatsTracker {
28
29     private final AtomicLong totalDurations = new AtomicLong();
30     private final AtomicLong longestDuration = new AtomicLong();
31     private volatile long timeOfLongestDuration;
32     private final AtomicLong shortestDuration = new AtomicLong(Long.MAX_VALUE);
33     private volatile long timeOfShortestDuration;
34     private final AtomicDouble averageDuration = new AtomicDouble();
35
36     /**
37      * Add a duration to track.
38      *
39      * @param duration the duration in nanoseconds.
40      */
41     public void addDuration(long duration) {
42
43         double currentAve = averageDuration.get();
44         long currentTotal = totalDurations.get();
45
46         long newTotal = currentTotal + 1;
47
48         // Calculate moving cumulative average.
49         double newAve = currentAve * (double)currentTotal / (double)newTotal + (double)duration / (double)newTotal;
50
51         averageDuration.compareAndSet(currentAve, newAve);
52         totalDurations.compareAndSet(currentTotal, newTotal);
53
54         long longest = longestDuration.get();
55         if( duration > longest ) {
56             if(longestDuration.compareAndSet( longest, duration )) {
57                 timeOfLongestDuration = System.currentTimeMillis();
58             }
59         }
60
61         long shortest = shortestDuration.get();
62         if( duration < shortest ) {
63             if(shortestDuration.compareAndSet( shortest, duration )) {
64                 timeOfShortestDuration = System.currentTimeMillis();
65             }
66         }
67     }
68
69     /**
70      * Returns the total number of tracked durations.
71      */
72     public long getTotalDurations() {
73         return totalDurations.get();
74     }
75
76     /**
77      * Returns the longest duration in nanoseconds.
78      */
79     public long getLongestDuration() {
80         return longestDuration.get();
81     }
82
83     /**
84      * Returns the shortest duration in nanoseconds.
85      */
86     public long getShortestDuration() {
87         long shortest = shortestDuration.get();
88         return shortest < Long.MAX_VALUE ? shortest : 0;
89     }
90
91     /**
92      * Returns the average duration in nanoseconds.
93      */
94     public double getAverageDuration() {
95         return averageDuration.get();
96     }
97
98     /**
99      * Returns the time stamp of the longest duration.
100      */
101     public long getTimeOfLongestDuration() {
102         return timeOfLongestDuration;
103     }
104
105     /**
106      * Returns the time stamp of the shortest duration.
107      */
108     public long getTimeOfShortestDuration() {
109         return timeOfShortestDuration;
110     }
111
112     /**
113      * Resets all statistics back to their defaults.
114      */
115     public void reset() {
116         totalDurations.set(0);
117         longestDuration.set(0);
118         timeOfLongestDuration = 0;
119         shortestDuration.set(Long.MAX_VALUE);
120         timeOfShortestDuration = 0;
121         averageDuration.set(0.0);
122     }
123
124     /**
125      * Returns the average duration as a displayable String with units, e.g. "12.34 ms".
126      */
127     public String getDisplayableAverageDuration() {
128         return formatDuration(getAverageDuration(), 0);
129     }
130
131     /**
132      * Returns the shortest duration as a displayable String with units and the date/time at
133      * which it occurred, e.g. "12.34 ms at 08/02/2014 12:30:24".
134      */
135     public String getDisplayableShortestDuration() {
136         return formatDuration(getShortestDuration(), getTimeOfShortestDuration());
137     }
138
139     /**
140      * Returns the longest duration as a displayable String with units and the date/time at
141      * which it occurred, e.g. "12.34 ms at 08/02/2014 12:30:24".
142      */
143     public String getDisplayableLongestDuration() {
144         return formatDuration(getLongestDuration(), getTimeOfLongestDuration());
145     }
146
147     private String formatDuration(double duration, long timeStamp) {
148         TimeUnit unit = chooseUnit((long)duration);
149         double value = duration / NANOSECONDS.convert(1, unit);
150         return timeStamp > 0 ?
151                 String.format("%.4g %s at %3$tD %3$tT", value, abbreviate(unit), new Date(timeStamp)) :
152                 String.format("%.4g %s", value, abbreviate(unit));
153     }
154
155     private static TimeUnit chooseUnit(long nanos) {
156         if(SECONDS.convert(nanos, NANOSECONDS) > 0) {
157             return SECONDS;
158         }
159
160         if(MILLISECONDS.convert(nanos, NANOSECONDS) > 0) {
161             return MILLISECONDS;
162         }
163
164         if(MICROSECONDS.convert(nanos, NANOSECONDS) > 0) {
165             return MICROSECONDS;
166         }
167
168         return NANOSECONDS;
169     }
170
171     private static String abbreviate(TimeUnit unit) {
172         switch(unit) {
173             case NANOSECONDS:
174                 return "ns";
175             case MICROSECONDS:
176                 return "\u03bcs"; // μs
177             case MILLISECONDS:
178                 return "ms";
179             case SECONDS:
180                 return "s";
181             default:
182                 return "";
183         }
184     }
185 }