1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.filter.statistic;
21
22 import java.util.Collections;
23 import java.util.EnumSet;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.concurrent.TimeUnit;
27 import java.util.concurrent.atomic.AtomicLong;
28
29 import org.apache.mina.core.filterchain.IoFilterAdapter;
30 import org.apache.mina.core.session.IdleStatus;
31 import org.apache.mina.core.session.IoEventType;
32 import org.apache.mina.core.session.IoSession;
33 import org.apache.mina.core.write.WriteRequest;
34 import org.apache.mina.util.CopyOnWriteMap;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 public class ProfilerTimerFilter extends IoFilterAdapter {
54
55 private volatile EnumSet<IoEventType> eventsToProfile;
56 private volatile ProfilerTimerUnit timeUnit;
57 private final Map<IoEventType, TimerWorker> timerManager;
58
59
60
61
62
63
64
65 public ProfilerTimerFilter() {
66 this(
67 TimeUnit.MILLISECONDS, EnumSet.of(IoEventType.MESSAGE_RECEIVED,
68 IoEventType.MESSAGE_SENT));
69 }
70
71
72
73
74
75
76
77 public ProfilerTimerFilter(TimeUnit unit) {
78 this(
79 unit,
80 IoEventType.MESSAGE_RECEIVED, IoEventType.MESSAGE_SENT);
81 }
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97 public ProfilerTimerFilter(TimeUnit unit, IoEventType firstEventType, IoEventType... otherEventTypes) {
98 this(unit, EnumSet.of(firstEventType, otherEventTypes));
99 }
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 public ProfilerTimerFilter(TimeUnit unit, EnumSet<IoEventType> eventTypes) {
117 setTimeUnit(unit);
118 setEventsToProfile(eventTypes);
119
120 timerManager = new CopyOnWriteMap<IoEventType, TimerWorker>();
121 for (IoEventType type : eventsToProfile) {
122 timerManager.put(type, new TimerWorker());
123 }
124 }
125
126
127
128
129
130
131 public void setTimeUnit(TimeUnit unit) {
132 if (unit == TimeUnit.MILLISECONDS) {
133 this.timeUnit = ProfilerTimerUnit.MILLISECONDS;
134 } else if (unit == TimeUnit.NANOSECONDS) {
135 this.timeUnit = ProfilerTimerUnit.NANOSECONDS;
136 } else if (unit == TimeUnit.SECONDS) {
137 this.timeUnit = ProfilerTimerUnit.SECONDS;
138 } else {
139 throw new IllegalArgumentException(
140 "Invalid Time specified: " + unit + " (expected: " +
141 TimeUnit.MILLISECONDS + ", " +
142 TimeUnit.NANOSECONDS + " or " +
143 TimeUnit.SECONDS + ')');
144 }
145 }
146
147
148
149
150
151
152
153 public void addEventToProfile(IoEventType type) {
154 if (!timerManager.containsKey(type)) {
155 timerManager.put(type, new TimerWorker());
156 }
157 }
158
159
160
161
162
163
164
165 public void removeEventToProfile(IoEventType type) {
166 timerManager.remove(type);
167 }
168
169
170
171
172
173
174
175
176 public Set<IoEventType> getEventsToProfile() {
177 return Collections.unmodifiableSet(eventsToProfile);
178 }
179
180
181
182
183
184 public void setEventsToProfile(IoEventType firstEventType, IoEventType... otherEventTypes) {
185 this.setEventsToProfile(EnumSet.of(firstEventType, otherEventTypes));
186 }
187
188
189
190
191
192
193
194
195 public void setEventsToProfile(Set<IoEventType> eventTypes) {
196 if (eventTypes == null) {
197 throw new NullPointerException("eventTypes");
198 }
199 if (eventTypes.isEmpty()) {
200 throw new IllegalArgumentException("eventTypes is empty.");
201 }
202
203 EnumSet<IoEventType> newEventsToProfile = EnumSet.noneOf(IoEventType.class);
204 for (IoEventType e: eventTypes) {
205 newEventsToProfile.add(e);
206 }
207
208 this.eventsToProfile = newEventsToProfile;
209 }
210
211 @Override
212 public void messageReceived(NextFilter nextFilter, IoSession session,
213 Object message) throws Exception {
214 long start = timeUnit.timeNow();
215 nextFilter.messageReceived(session, message);
216 long end = timeUnit.timeNow();
217
218 if (getEventsToProfile().contains(IoEventType.MESSAGE_RECEIVED)) {
219 timerManager.get(IoEventType.MESSAGE_RECEIVED).addNewReading(
220 end - start);
221 }
222 }
223
224 @Override
225 public void messageSent(NextFilter nextFilter, IoSession session,
226 WriteRequest writeRequest) throws Exception {
227 long start = timeUnit.timeNow();
228 nextFilter.messageSent(session, writeRequest);
229 long end = timeUnit.timeNow();
230
231 if (getEventsToProfile().contains(IoEventType.MESSAGE_SENT)) {
232 timerManager.get(IoEventType.MESSAGE_SENT).addNewReading(
233 end - start);
234 }
235 }
236
237 @Override
238 public void sessionClosed(NextFilter nextFilter, IoSession session)
239 throws Exception {
240 long start = timeUnit.timeNow();
241 nextFilter.sessionClosed(session);
242 long end = timeUnit.timeNow();
243
244 if (getEventsToProfile().contains(IoEventType.SESSION_CLOSED)) {
245 timerManager.get(IoEventType.SESSION_CLOSED).addNewReading(
246 end - start);
247 }
248 }
249
250 @Override
251 public void sessionCreated(NextFilter nextFilter, IoSession session)
252 throws Exception {
253 long start = timeUnit.timeNow();
254 nextFilter.sessionCreated(session);
255 long end = timeUnit.timeNow();
256
257 if (getEventsToProfile().contains(IoEventType.SESSION_CREATED)) {
258 timerManager.get(IoEventType.SESSION_CREATED).addNewReading(
259 end - start);
260 }
261 }
262
263 @Override
264 public void sessionIdle(NextFilter nextFilter, IoSession session,
265 IdleStatus status) throws Exception {
266 long start = timeUnit.timeNow();
267 nextFilter.sessionIdle(session, status);
268 long end = timeUnit.timeNow();
269
270 if (getEventsToProfile().contains(IoEventType.SESSION_IDLE)) {
271 timerManager.get(IoEventType.SESSION_IDLE).addNewReading(
272 end - start);
273 }
274 }
275
276 @Override
277 public void sessionOpened(NextFilter nextFilter, IoSession session)
278 throws Exception {
279 long start = timeUnit.timeNow();
280 nextFilter.sessionOpened(session);
281 long end = timeUnit.timeNow();
282
283 if (getEventsToProfile().contains(IoEventType.SESSION_OPENED)) {
284 timerManager.get(IoEventType.SESSION_OPENED).addNewReading(
285 end - start);
286 }
287 }
288
289
290
291
292
293
294
295
296
297 public double getAverageTime(IoEventType type) {
298 if (!timerManager.containsKey(type)) {
299 throw new IllegalArgumentException(
300 "You are not monitoring this event. Please add this event first.");
301 }
302
303 return timerManager.get(type).getAverage();
304 }
305
306
307
308
309
310
311
312
313
314
315 public long getTotalCalls(IoEventType type) {
316 if (!timerManager.containsKey(type)) {
317 throw new IllegalArgumentException(
318 "You are not monitoring this event. Please add this event first.");
319 }
320
321 return timerManager.get(type).getCalls();
322 }
323
324
325
326
327
328
329
330
331
332
333 public long getTotalTime(IoEventType type) {
334 if (!timerManager.containsKey(type)) {
335 throw new IllegalArgumentException(
336 "You are not monitoring this event. Please add this event first.");
337 }
338
339 return timerManager.get(type).getTotal();
340 }
341
342
343
344
345
346
347
348
349
350
351 public long getMinimumTime(IoEventType type) {
352 if (!timerManager.containsKey(type)) {
353 throw new IllegalArgumentException(
354 "You are not monitoring this event. Please add this event first.");
355 }
356
357 return timerManager.get(type).getMinimum();
358 }
359
360
361
362
363
364
365
366
367
368
369 public long getMaximumTime(IoEventType type) {
370 if (!timerManager.containsKey(type)) {
371 throw new IllegalArgumentException(
372 "You are not monitoring this event. Please add this event first.");
373 }
374
375 return timerManager.get(type).getMaximum();
376 }
377
378
379
380
381
382
383 private class TimerWorker {
384
385 private final AtomicLong total;
386 private final AtomicLong calls;
387 private final AtomicLong minimum;
388 private final AtomicLong maximum;
389 private final Object lock = new Object();
390
391
392
393
394
395 public TimerWorker() {
396 total = new AtomicLong();
397 calls = new AtomicLong();
398 minimum = new AtomicLong();
399 maximum = new AtomicLong();
400 }
401
402
403
404
405
406
407
408
409 public void addNewReading(long newReading) {
410 calls.incrementAndGet();
411 total.addAndGet(newReading);
412
413 synchronized (lock) {
414
415 if (newReading < minimum.longValue()) {
416 minimum.set(newReading);
417 }
418
419
420 if (newReading > maximum.longValue()) {
421 maximum.set(newReading);
422 }
423 }
424 }
425
426
427
428
429
430
431
432 public double getAverage() {
433 return total.longValue() / calls.longValue();
434 }
435
436
437
438
439
440
441
442 public long getCalls() {
443 return calls.longValue();
444 }
445
446
447
448
449
450
451
452 public long getTotal() {
453 return total.longValue();
454 }
455
456
457
458
459
460
461
462 public long getMinimum() {
463 return minimum.longValue();
464 }
465
466
467
468
469
470
471
472 public long getMaximum() {
473 return maximum.longValue();
474 }
475 }
476
477 private enum ProfilerTimerUnit {
478 SECONDS {
479 @Override
480 public long timeNow() {
481 return System.currentTimeMillis() / 1000;
482 }
483
484 @Override
485 public String getDescription() {
486 return "seconds";
487 }
488 },
489 MILLISECONDS {
490 @Override
491 public long timeNow() {
492 return System.currentTimeMillis();
493 }
494
495 @Override
496 public String getDescription() {
497 return "milliseconds";
498 }
499 },
500 NANOSECONDS {
501 @Override
502 public long timeNow() {
503 return System.nanoTime();
504 }
505
506 @Override
507 public String getDescription() {
508 return "nanoseconds";
509 }
510 };
511
512
513
514
515
516
517
518
519
520
521
522
523 public long timeNow() {
524 throw new AbstractMethodError();
525 }
526
527 public String getDescription() {
528 throw new AbstractMethodError();
529 }
530 }
531 }