View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.metrics2.lib;
20  
21  import java.util.concurrent.atomic.AtomicLong;
22  
23  import org.apache.commons.lang.StringUtils;
24  import org.apache.hadoop.hbase.classification.InterfaceAudience;
25  import org.apache.hadoop.hbase.metrics.Interns;
26  import org.apache.hadoop.metrics2.MetricHistogram;
27  import org.apache.hadoop.metrics2.MetricsInfo;
28  import org.apache.hadoop.metrics2.MetricsRecordBuilder;
29  
30  import com.yammer.metrics.stats.ExponentiallyDecayingSample;
31  import com.yammer.metrics.stats.Sample;
32  import com.yammer.metrics.stats.Snapshot;
33  
34  /**
35   * A histogram implementation that runs in constant space, and exports to hadoop2's metrics2 system.
36   */
37  @InterfaceAudience.Private
38  public class MutableHistogram extends MutableMetric implements MetricHistogram {
39  
40    private static final int DEFAULT_SAMPLE_SIZE = 2046;
41    // the bias towards sampling from more recent data.
42    // Per Cormode et al. an alpha of 0.015 strongly biases to the last 5 minutes
43    private static final double DEFAULT_ALPHA = 0.015;
44  
45    protected final String name;
46    protected final String desc;
47    private final Sample sample;
48    private final AtomicLong min;
49    private final AtomicLong max;
50    private final AtomicLong sum;
51    private final AtomicLong count;
52  
53    private boolean metricsInfoStringInited = false;
54    private String NUM_OPS_METRIC;
55    private String MIN_METRIC;
56    private String MAX_METRIC;
57    private String MEAN_METRIC;
58    private String MEDIAN_METRIC;
59    private String SEVENTY_FIFTH_PERCENTILE_METRIC;
60    private String NINETIETH_PERCENTILE_METRIC;
61    private String NINETY_FIFTH_PERCENTILE_METRIC;
62    private String NINETY_NINETH_PERCENTILE_METRIC;
63  
64    public MutableHistogram(MetricsInfo info) {
65      this(info.name(), info.description());
66    }
67  
68    public MutableHistogram(String name, String description) {
69      this.name = StringUtils.capitalize(name);
70      this.desc = StringUtils.uncapitalize(description);
71      sample = new ExponentiallyDecayingSample(DEFAULT_SAMPLE_SIZE, DEFAULT_ALPHA);
72      count = new AtomicLong();
73      min = new AtomicLong(Long.MAX_VALUE);
74      max = new AtomicLong(Long.MIN_VALUE);
75      sum = new AtomicLong();
76    }
77  
78    public void add(final long val) {
79      setChanged();
80      count.incrementAndGet();
81      sample.update(val);
82      setMax(val);
83      setMin(val);
84      sum.getAndAdd(val);
85    }
86  
87    private void setMax(final long potentialMax) {
88      boolean done = false;
89      while (!done) {
90        final long currentMax = max.get();
91        done = currentMax >= potentialMax
92            || max.compareAndSet(currentMax, potentialMax);
93      }
94    }
95  
96    private void setMin(long potentialMin) {
97      boolean done = false;
98      while (!done) {
99        final long currentMin = min.get();
100       done = currentMin <= potentialMin
101           || min.compareAndSet(currentMin, potentialMin);
102     }
103   }
104 
105   public long getMax() {
106     if (count.get() > 0) {
107       return max.get();
108     }
109     return 0L;
110   }
111 
112   public long getMin() {
113     if (count.get() > 0) {
114       return min.get();
115     }
116     return 0L;
117   }
118 
119   public double getMean() {
120     long cCount = count.get();
121     if (cCount > 0) {
122       return sum.get() / (double) cCount;
123     }
124     return 0.0;
125   }
126 
127   @Override
128   public void snapshot(MetricsRecordBuilder metricsRecordBuilder, boolean all) {
129     if (all || changed()) {
130       clearChanged();
131       updateSnapshotMetrics(metricsRecordBuilder);
132     }
133   }
134   
135   public void updateSnapshotMetrics(MetricsRecordBuilder metricsRecordBuilder) {
136     final Snapshot s = sample.getSnapshot();
137     if (!metricsInfoStringInited) {
138       NUM_OPS_METRIC = name + NUM_OPS_METRIC_NAME;
139       MIN_METRIC = name + MIN_METRIC_NAME;
140       MAX_METRIC = name + MAX_METRIC_NAME;
141       MEAN_METRIC = name + MEAN_METRIC_NAME;
142       MEDIAN_METRIC = name + MEDIAN_METRIC_NAME;
143       SEVENTY_FIFTH_PERCENTILE_METRIC = name + SEVENTY_FIFTH_PERCENTILE_METRIC_NAME;
144       NINETIETH_PERCENTILE_METRIC = name + NINETIETH_PERCENTILE_METRIC_NAME;
145       NINETY_FIFTH_PERCENTILE_METRIC = name + NINETY_FIFTH_PERCENTILE_METRIC_NAME;
146       NINETY_NINETH_PERCENTILE_METRIC = name + NINETY_NINETH_PERCENTILE_METRIC_NAME;
147 
148       metricsInfoStringInited = true;
149     }
150 
151     metricsRecordBuilder.addCounter(Interns.info(NUM_OPS_METRIC, desc), count.get());
152     metricsRecordBuilder.addGauge(Interns.info(MIN_METRIC, desc), getMin());
153     metricsRecordBuilder.addGauge(Interns.info(MAX_METRIC, desc), getMax());
154     metricsRecordBuilder.addGauge(Interns.info(MEAN_METRIC, desc), getMean());
155     metricsRecordBuilder.addGauge(Interns.info(MEDIAN_METRIC, desc), s.getMedian());
156     metricsRecordBuilder.addGauge(Interns.info(SEVENTY_FIFTH_PERCENTILE_METRIC, desc),
157         s.get75thPercentile());
158     metricsRecordBuilder.addGauge(Interns.info(NINETIETH_PERCENTILE_METRIC, desc),
159         s.getValue(0.90));
160     metricsRecordBuilder.addGauge(Interns.info(NINETY_FIFTH_PERCENTILE_METRIC, desc),
161         s.get95thPercentile());
162     metricsRecordBuilder.addGauge(Interns.info(NINETY_NINETH_PERCENTILE_METRIC, desc),
163         s.get99thPercentile());
164   }
165 }