001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.util;
019
020import org.apache.yetus.audience.InterfaceAudience;
021import org.slf4j.Logger;
022import org.slf4j.LoggerFactory;
023
024/**
025 * The purpose of introduction of {@link MovingAverage} mainly is to measure execution time of a
026 * specific method, which can help us to know its performance fluctuation in response to different
027 * machine states or situations, better case, then to act accordingly. <br>
028 * In different situation, different {@link MovingAverage} algorithm can be used based on needs.
029 */
030@InterfaceAudience.Private
031public abstract class MovingAverage<T> {
032  private final static Logger LOG = LoggerFactory.getLogger(MovingAverage.class);
033
034  protected final String label;
035
036  protected MovingAverage(String label) {
037    this.label = label;
038  }
039
040  /**
041   * Mark start time of an execution.
042   * @return time in ns.
043   */
044  protected long start() {
045    return System.nanoTime();
046  }
047
048  /**
049   * Mark end time of an execution, and return its interval.
050   * @param startTime start time of an execution
051   * @return elapsed time
052   */
053  protected long stop(long startTime) {
054    return System.nanoTime() - startTime;
055  }
056
057  /**
058   * Measure elapsed time of a measurable method.
059   * @param measurable method implements {@link TimeMeasurable}
060   * @return T it refers to the original return type of the measurable method
061   */
062  public T measure(TimeMeasurable<T> measurable) {
063    long startTime = start();
064    LOG.trace("{} - start to measure at: {} ns.", label, startTime);
065    // Here may throw exceptions which should be taken care by caller, not here.
066    // If exception occurs, this time wouldn't count.
067    T result = measurable.measure();
068    long elapsed = stop(startTime);
069    LOG.trace("{} - elapse: {} ns.", label, elapsed);
070    updateMostRecentTime(elapsed);
071    return result;
072  }
073
074  /**
075   * Update the most recent data.
076   * @param elapsed elapsed time of the most recent measurement
077   */
078  protected abstract void updateMostRecentTime(long elapsed);
079
080  /**
081   * Get average execution time of the measured method.
082   * @return average time in ns
083   */
084  public abstract double getAverageTime();
085}