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 */
018
019package org.apache.hadoop.hbase.util;
020
021import org.apache.yetus.audience.InterfaceAudience;
022import org.slf4j.Logger;
023import org.slf4j.LoggerFactory;
024
025/**
026 * The purpose of introduction of {@link MovingAverage} mainly is to measure execution time of a
027 * specific method, which can help us to know its performance fluctuation in response to different
028 * machine states or situations, better case, then to act accordingly.
029 * <br>
030 * In different situation, different {@link MovingAverage} algorithm can be used based on needs.
031 */
032@InterfaceAudience.Private
033public abstract class MovingAverage<T> {
034  private final static Logger LOG = LoggerFactory.getLogger(MovingAverage.class);
035
036  protected final String label;
037
038  protected MovingAverage(String label) {
039    this.label = label;
040  }
041
042  /**
043   * Mark start time of an execution.
044   * @return time in ns.
045   */
046  protected long start() {
047    return System.nanoTime();
048  }
049
050  /**
051   * Mark end time of an execution, and return its interval.
052   * @param startTime start time of an execution
053   * @return elapsed time
054   */
055  protected long stop(long startTime) {
056    return System.nanoTime() - startTime;
057  }
058
059  /**
060   * Measure elapsed time of a measurable method.
061   * @param measurable method implements {@link TimeMeasurable}
062   * @return T it refers to the original return type of the measurable method
063   */
064  public T measure(TimeMeasurable<T> measurable) {
065    long startTime = start();
066    LOG.trace("{} - start to measure at: {} ns.", label, startTime);
067    // Here may throw exceptions which should be taken care by caller, not here.
068    // If exception occurs, this time wouldn't count.
069    T result = measurable.measure();
070    long elapsed = stop(startTime);
071    LOG.trace("{} - elapse: {} ns.", label, elapsed);
072    updateMostRecentTime(elapsed);
073    return result;
074  }
075
076  /**
077   * Update the most recent data.
078   * @param elapsed elapsed time of the most recent measurement
079   */
080  protected abstract void updateMostRecentTime(long elapsed);
081
082  /**
083   * Get average execution time of the measured method.
084   * @return average time in ns
085   */
086  public abstract double getAverageTime();
087}