All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sleepycat.je.utilint.DoubleExpMovingAvg Maven / Gradle / Ivy

The newest version!
/*-
 * Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
 *
 * This file was distributed by Oracle as part of a version of Oracle Berkeley
 * DB Java Edition made available at:
 *
 * http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
 *
 * Please see the LICENSE file included in the top-level directory of the
 * appropriate version of Oracle Berkeley DB Java Edition for a copy of the
 * license and additional information.
 */

package com.sleepycat.je.utilint;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import com.sleepycat.utilint.FormatUtil;

/**
 * A double JE stat component generated from an exponential moving average over
 * a specified time period of values supplied with associated times, to support
 * averaging values that are generated at irregular intervals.
 */
public class DoubleExpMovingAvg
        extends MapStatComponent {

    private static final long serialVersionUID = 1L;

    /** The name of this stat. */
    private final String name;

    /** The averaging period in milliseconds. */
    private final long periodMillis;

    /**
     * The time in milliseconds specified with the previous value, or 0 if no
     * values have been provided.  Synchronize on this instance when accessing
     * this field.
     */
    private long prevTime;

    /**
     * The current average, or 0 if no values have been provided.  Synchronize
     * on this instance when accessing this field.
     */
    private double avg;

    /**
     * Creates an instance of this class.  The {@code periodMillis} represents
     * the time period in milliseconds over which values will be averaged.
     *
     * @param name the name of this stat
     * @param periodMillis the averaging period in milliseconds
     */
    public DoubleExpMovingAvg(String name, long periodMillis) {
        assert name != null;
        assert periodMillis > 0;
        this.name = name;
        this.periodMillis = periodMillis;
    }

    /**
     * Creates an instance of this class as a copy of another instance.
     *
     * @param other the other instance to copy
     */
    DoubleExpMovingAvg(DoubleExpMovingAvg other) {
        name = other.name;
        periodMillis = other.periodMillis;
        synchronized (this) {
            synchronized (other) {
                prevTime = other.prevTime;
                avg = other.avg;
            }
        }
    }

    /**
     * Returns the name of this stat.
     *
     * @return the name of this stat
     */
    public String getName() {
        return name;
    }

    /**
     * Adds a new value to the average, ignoring values that are not newer than
     * time of the previous call.
     *
     * @param value the new value
     * @param time the current time in milliseconds
     */
    public synchronized void add(double value, long time) {
        assert time > 0;
        if (time <= prevTime) {
            return;
        }
        if (prevTime == 0) {
            avg = value;
        } else {

            /*
             * Compute the exponential moving average, as described in:
             * http://en.wikipedia.org/wiki/
             *   Moving_average#Application_to_measuring_computer_performance
             */
            double m = Math.exp(-((time - prevTime)/((double) periodMillis)));
            avg = ((1-m) * value) + (m * avg);
        }
        prevTime = time;
    }

    /**
     * Add the values from another average.
     *
     * @param other the other average
     */
    public void add(DoubleExpMovingAvg other) {
        final double otherValue;
        final long otherTime;
        synchronized (other) {
            if (other.isNotSet()) {
                return;
            }
            otherValue = other.avg;
            otherTime = other.prevTime;
        }
        add(otherValue, otherTime);
    }

    /** Returns the current average as a primitive value. */
    synchronized double getPrimitive() {
        return avg;
    }

    /** Returns the current average, or 0 if no values have been added. */
    @Override
    public Double get() {
        return getPrimitive();
    }

    @Override
    public synchronized void clear() {
        prevTime = 0;
        avg = 0;
    }

    @Override
    public DoubleExpMovingAvg copy() {
        return new DoubleExpMovingAvg(this);
    }

    @Override
    protected synchronized String getFormattedValue(boolean useCommas) {
        if (isNotSet()) {
            return "unknown";
        } else if (Double.isNaN(avg)) {
            return "NaN";
        } else if (useCommas) {
            return FormatUtil.decimalScale2().format(avg);
        } else {
            return String.format("%.2f", avg);
        }
    }

    @Override
    public synchronized boolean isNotSet() {
       return prevTime == 0;
    }

    @Override
    public synchronized String toString() {
        return "DoubleExpMovingAvg[name=" + name + ", avg=" + avg +
            ", prevTime=" + prevTime + ", periodMillis=" + periodMillis + "]";
    }

    /** Synchronize access to fields. */
    private synchronized void readObject(ObjectInputStream in)
        throws IOException, ClassNotFoundException {

        in.defaultReadObject();
    }

    /** Synchronize access to fields. */
    private synchronized void writeObject(ObjectOutputStream out)
        throws IOException {

        out.defaultWriteObject();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy