1
16
17 package net.sf.ehcache.util.ratestatistics;
18
19 import java.util.concurrent.TimeUnit;
20 import java.util.concurrent.atomic.AtomicLong;
21
22
27 public class AtomicRateStatistic extends AbstractRateStatistic {
28
29 private static final int SAMPLE_TIME_FLAG_BITS = 1;
30 private static final long CALCULATION_FLAG = 0x1L;
31
32 private final AtomicLong count = new AtomicLong(0L);
33 private final AtomicLong rateSampleTime = new AtomicLong(getTime() << SAMPLE_TIME_FLAG_BITS);
34
35 private volatile float rateSample = 0.0f;
36
37 private volatile long sampleRateMask;
38 private volatile long previousSample;
39
40
46 public AtomicRateStatistic(long averagePeriod, TimeUnit unit) {
47 super(averagePeriod, unit);
48 }
49
50
53 public void event() {
54 long value = count.incrementAndGet();
55 if ((value & sampleRateMask) == 0L) {
56 long now = getTime();
57 long previous = startIncrementTime(now);
58 try {
59 if (now != previous && value > previousSample) {
60 float nowRate = ((float)(value - previousSample)) / (now - previous);
61 rateSample = iterateMovingAverage(nowRate, now, rateSample, previous);
62 previousSample = value;
63 long suggestedSampleRateMask = Long.highestOneBit(Math.max(1L, (long)(getRateAveragePeriod() * rateSample))) - 1;
64 if (suggestedSampleRateMask != sampleRateMask) {
65 sampleRateMask = suggestedSampleRateMask;
66 }
67 }
68 } finally {
69 finishIncrementTime(now);
70 }
71 }
72 }
73
74
77 public long getCount() {
78 return count.get();
79 }
80
81
84 public float getRate() {
85 long then;
86 long lastSample;
87 float thenAverage;
88 do {
89 then = startReadTime();
90 lastSample = previousSample;
91 thenAverage = rateSample;
92 } while (!validateTimeRead(then));
93
94 long now = getTime();
95 if (now == then) {
96 return thenAverage;
97 } else {
98 float nowValue = ((float) (count.get() - lastSample)) / (now - then);
99 final float rate = iterateMovingAverage(nowValue, now, thenAverage, then) * TimeUnit.SECONDS.toNanos(1);
100 if (Float.isNaN(rate)) {
101 if (Float.isNaN(thenAverage)) {
102 return 0f;
103 } else {
104 return thenAverage;
105 }
106 } else {
107 return rate;
108 }
109 }
110 }
111
112 private long startIncrementTime(long newTime) {
113 while (true) {
114 long current = rateSampleTime.get();
115 if (((current & CALCULATION_FLAG) == 0) && rateSampleTime.compareAndSet(current, (newTime << SAMPLE_TIME_FLAG_BITS) | CALCULATION_FLAG)) {
116 return current >>> SAMPLE_TIME_FLAG_BITS;
117 }
118 }
119 }
120
121 private void finishIncrementTime(long value) {
122 if (!rateSampleTime.compareAndSet((value << SAMPLE_TIME_FLAG_BITS) | CALCULATION_FLAG, value << SAMPLE_TIME_FLAG_BITS)) {
123 throw new AssertionError();
124 }
125 }
126
127 private long startReadTime() {
128 while (true) {
129 long current = rateSampleTime.get();
130 if ((current & CALCULATION_FLAG) == 0) {
131 return current >>> SAMPLE_TIME_FLAG_BITS;
132 }
133 }
134 }
135
136 private boolean validateTimeRead(long current) {
137 return rateSampleTime.get() == (current << SAMPLE_TIME_FLAG_BITS);
138 }
139
140
141 private static long getTime() {
142 return System.nanoTime();
143 }
144 }
145