1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.metrics.histogram;
20
21 import java.util.concurrent.atomic.AtomicLong;
22 import java.util.concurrent.atomic.AtomicReference;
23
24 import org.apache.hadoop.metrics.MetricsRecord;
25 import org.apache.hadoop.metrics.util.MetricsBase;
26 import org.apache.hadoop.metrics.util.MetricsRegistry;
27
28 import com.yammer.metrics.stats.Sample;
29 import com.yammer.metrics.stats.Snapshot;
30 import com.yammer.metrics.stats.UniformSample;
31 import com.yammer.metrics.stats.ExponentiallyDecayingSample;
32
33 @Deprecated
34 public class MetricsHistogram extends MetricsBase {
35
36
37
38 private static final int DEFAULT_SAMPLE_SIZE = 1028;
39
40
41
42 private static final double DEFAULT_ALPHA = 0.015;
43 public static final String NUM_OPS_METRIC_NAME = "_num_ops";
44 public static final String MIN_METRIC_NAME = "_min";
45 public static final String MAX_METRIC_NAME = "_max";
46 public static final String MEAN_METRIC_NAME = "_mean";
47 public static final String STD_DEV_METRIC_NAME = "_std_dev";
48 public static final String MEDIAN_METRIC_NAME = "_median";
49 public static final String SEVENTY_FIFTH_PERCENTILE_METRIC_NAME = "_75th_percentile";
50 public static final String NINETY_FIFTH_PERCENTILE_METRIC_NAME = "_95th_percentile";
51 public static final String NINETY_NINETH_PERCENTILE_METRIC_NAME = "_99th_percentile";
52
53
54
55
56
57
58
59
60
61
62 public MetricsHistogram(final String nam, final MetricsRegistry registry,
63 final String description, boolean forwardBiased) {
64 super(nam, description);
65
66 this.min = new AtomicLong();
67 this.max = new AtomicLong();
68 this.sum = new AtomicLong();
69 this.sample = forwardBiased ?
70 new ExponentiallyDecayingSample(DEFAULT_SAMPLE_SIZE, DEFAULT_ALPHA)
71 : new UniformSample(DEFAULT_SAMPLE_SIZE);
72
73 this.variance = new AtomicReference<double[]>(new double[]{-1, 0});
74 this.count = new AtomicLong();
75
76 this.clear();
77
78 if (registry != null) {
79 registry.add(nam, this);
80 }
81 }
82
83
84
85
86
87
88
89 public MetricsHistogram(final String nam, MetricsRegistry registry,
90 final String description) {
91 this(nam, registry, NO_DESCRIPTION, true);
92 }
93
94
95
96
97
98
99 public MetricsHistogram(final String nam, MetricsRegistry registry) {
100 this(nam, registry, NO_DESCRIPTION);
101 }
102
103 private final Sample sample;
104 private final AtomicLong min;
105 private final AtomicLong max;
106 private final AtomicLong sum;
107
108
109
110 private final AtomicReference<double[]> variance;
111 private final AtomicLong count;
112
113
114
115
116 public void clear() {
117 this.sample.clear();
118 this.count.set(0);
119 this.max.set(Long.MIN_VALUE);
120 this.min.set(Long.MAX_VALUE);
121 this.sum.set(0);
122 variance.set(new double[]{-1, 0});
123 }
124
125 public void update(int val) {
126 update((long) val);
127 }
128
129 public void update(final long val) {
130 count.incrementAndGet();
131 sample.update(val);
132 setMax(val);
133 setMin(val);
134 sum.getAndAdd(val);
135 updateVariance(val);
136 }
137
138 private void setMax(final long potentialMax) {
139 boolean done = false;
140 while (!done) {
141 final long currentMax = max.get();
142 done = currentMax >= potentialMax
143 || max.compareAndSet(currentMax, potentialMax);
144 }
145 }
146
147 private void setMin(long potentialMin) {
148 boolean done = false;
149 while (!done) {
150 final long currentMin = min.get();
151 done = currentMin <= potentialMin
152 || min.compareAndSet(currentMin, potentialMin);
153 }
154 }
155
156 private void updateVariance(long value) {
157 boolean done = false;
158 while (!done) {
159 final double[] oldValues = variance.get();
160 final double[] newValues = new double[2];
161 if (oldValues[0] == -1) {
162 newValues[0] = value;
163 newValues[1] = 0;
164 } else {
165 final double oldM = oldValues[0];
166 final double oldS = oldValues[1];
167
168 final double newM = oldM + ((value - oldM) / getCount());
169 final double newS = oldS + ((value - oldM) * (value - newM));
170
171 newValues[0] = newM;
172 newValues[1] = newS;
173 }
174 done = variance.compareAndSet(oldValues, newValues);
175 }
176 }
177
178
179 public long getCount() {
180 return count.get();
181 }
182
183 public long getMax() {
184 if (getCount() > 0) {
185 return max.get();
186 }
187 return 0L;
188 }
189
190 public long getMin() {
191 if (getCount() > 0) {
192 return min.get();
193 }
194 return 0L;
195 }
196
197 public double getMean() {
198 if (getCount() > 0) {
199 return sum.get() / (double) getCount();
200 }
201 return 0.0;
202 }
203
204 public double getStdDev() {
205 if (getCount() > 0) {
206 return Math.sqrt(getVariance());
207 }
208 return 0.0;
209 }
210
211 public Snapshot getSnapshot() {
212 return sample.getSnapshot();
213 }
214
215 private double getVariance() {
216 if (getCount() <= 1) {
217 return 0.0;
218 }
219 return variance.get()[1] / (getCount() - 1);
220 }
221
222 @Override
223 public void pushMetric(MetricsRecord mr) {
224 final Snapshot s = this.getSnapshot();
225 mr.setMetric(getName() + NUM_OPS_METRIC_NAME, this.getCount());
226 mr.setMetric(getName() + MIN_METRIC_NAME, this.getMin());
227 mr.setMetric(getName() + MAX_METRIC_NAME, this.getMax());
228
229 mr.setMetric(getName() + MEAN_METRIC_NAME, (float) this.getMean());
230 mr.setMetric(getName() + STD_DEV_METRIC_NAME, (float) this.getStdDev());
231
232 mr.setMetric(getName() + MEDIAN_METRIC_NAME, (float) s.getMedian());
233 mr.setMetric(getName() + SEVENTY_FIFTH_PERCENTILE_METRIC_NAME,
234 (float) s.get75thPercentile());
235 mr.setMetric(getName() + NINETY_FIFTH_PERCENTILE_METRIC_NAME,
236 (float) s.get95thPercentile());
237 mr.setMetric(getName() + NINETY_NINETH_PERCENTILE_METRIC_NAME,
238 (float) s.get99thPercentile());
239 }
240 }