1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.util;
18
19 import java.io.Serializable;
20 import java.text.DecimalFormat;
21
22
23
24
25
26
27 public class Timer implements Serializable, StringBuilderFormattable
28 {
29 private static final long serialVersionUID = 9175191792439630013L;
30
31 private final String name;
32 public enum Status {
33 Started, Stopped, Paused
34 }
35 private Status status;
36 private long elapsedTime;
37 private final int iterations;
38 private static long NANO_PER_SECOND = 1000000000L;
39 private static long NANO_PER_MINUTE = NANO_PER_SECOND * 60;
40 private static long NANO_PER_HOUR = NANO_PER_MINUTE * 60;
41 private ThreadLocal<Long> startTime = new ThreadLocal<Long>() {
42 @Override protected Long initialValue() {
43 return 0L;
44 }
45 };
46
47
48
49
50
51
52 public Timer(final String name)
53 {
54 this(name, 0);
55 }
56
57
58
59
60
61
62 public Timer(final String name, final int iterations)
63 {
64 this.name = name;
65 status = Status.Stopped;
66 this.iterations = (iterations > 0) ? iterations : 0;
67 }
68
69
70
71
72 public synchronized void start()
73 {
74 startTime.set(System.nanoTime());
75 elapsedTime = 0;
76 status = Status.Started;
77 }
78
79 public synchronized void startOrResume() {
80 if (status == Status.Stopped) {
81 start();
82 } else {
83 resume();
84 }
85 }
86
87
88
89
90 public synchronized String stop()
91 {
92 elapsedTime += System.nanoTime() - startTime.get();
93 startTime.set(0L);
94 status = Status.Stopped;
95 return toString();
96 }
97
98
99
100
101 public synchronized void pause()
102 {
103 elapsedTime += System.nanoTime() - startTime.get();
104 startTime.set(0L);
105 status = Status.Paused;
106 }
107
108
109
110
111 public synchronized void resume()
112 {
113 startTime.set(System.nanoTime());
114 status = Status.Started;
115 }
116
117
118
119
120
121 public String getName()
122 {
123 return name;
124 }
125
126
127
128
129
130
131 public long getElapsedTime()
132 {
133 return elapsedTime / 1000000;
134 }
135
136
137
138
139
140
141 public long getElapsedNanoTime()
142 {
143 return elapsedTime;
144 }
145
146
147
148
149
150
151 public Status getStatus()
152 {
153 return status;
154 }
155
156
157
158
159 @Override
160 public String toString()
161 {
162 final StringBuilder result = new StringBuilder();
163 formatTo(result);
164 return result.toString();
165 }
166
167 @Override
168 public void formatTo(final StringBuilder buffer) {
169 buffer.append("Timer ").append(name);
170 switch (status) {
171 case Started:
172 buffer.append(" started");
173 break;
174 case Paused:
175 buffer.append(" paused");
176 break;
177 case Stopped:
178 long nanoseconds = elapsedTime;
179
180 long hours = nanoseconds / NANO_PER_HOUR;
181
182 nanoseconds = nanoseconds % NANO_PER_HOUR;
183
184 long minutes = nanoseconds / NANO_PER_MINUTE;
185
186 nanoseconds = nanoseconds % NANO_PER_MINUTE;
187
188 long seconds = nanoseconds / NANO_PER_SECOND;
189
190 nanoseconds = nanoseconds % NANO_PER_SECOND;
191
192 String elapsed = Strings.EMPTY;
193
194 if (hours > 0) {
195 elapsed += hours + " hours ";
196 }
197 if (minutes > 0 || hours > 0) {
198 elapsed += minutes + " minutes ";
199 }
200
201 DecimalFormat numFormat;
202 numFormat = new DecimalFormat("#0");
203 elapsed += numFormat.format(seconds) + '.';
204 numFormat = new DecimalFormat("000000000");
205 elapsed += numFormat.format(nanoseconds) + " seconds";
206 buffer.append(" stopped. Elapsed time: ").append(elapsed);
207 if (iterations > 0) {
208 nanoseconds = elapsedTime / iterations;
209
210 hours = nanoseconds / NANO_PER_HOUR;
211
212 nanoseconds = nanoseconds % NANO_PER_HOUR;
213
214 minutes = nanoseconds / NANO_PER_MINUTE;
215
216 nanoseconds = nanoseconds % NANO_PER_MINUTE;
217
218 seconds = nanoseconds / NANO_PER_SECOND;
219
220 nanoseconds = nanoseconds % NANO_PER_SECOND;
221
222 elapsed = Strings.EMPTY;
223
224 if (hours > 0) {
225 elapsed += hours + " hours ";
226 }
227 if (minutes > 0 || hours > 0) {
228 elapsed += minutes + " minutes ";
229 }
230
231 numFormat = new DecimalFormat("#0");
232 elapsed += numFormat.format(seconds) + '.';
233 numFormat = new DecimalFormat("000000000");
234 elapsed += numFormat.format(nanoseconds) + " seconds";
235 buffer.append(" Average per iteration: ").append(elapsed);
236 }
237 break;
238 default:
239 buffer.append(' ').append(status);
240 break;
241 }
242 }
243
244 @Override
245 public boolean equals(final Object o) {
246 if (this == o) {
247 return true;
248 }
249 if (!(o instanceof Timer)) {
250 return false;
251 }
252
253 final Timer timer = (Timer) o;
254
255 if (elapsedTime != timer.elapsedTime) {
256 return false;
257 }
258 if (startTime != timer.startTime) {
259 return false;
260 }
261 if (name != null ? !name.equals(timer.name) : timer.name != null) {
262 return false;
263 }
264 if (status != null ? !status.equals(timer.status) : timer.status != null) {
265 return false;
266 }
267
268 return true;
269 }
270
271 @Override
272 public int hashCode() {
273 int result;
274 result = (name != null ? name.hashCode() : 0);
275 result = 29 * result + (status != null ? status.hashCode() : 0);
276 long time = startTime.get();
277 result = 29 * result + (int) (time ^ (time >>> 32));
278 result = 29 * result + (int) (elapsedTime ^ (elapsedTime >>> 32));
279 return result;
280 }
281
282 }