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

com.fizzed.crux.util.StopWatch Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2017 Fizzed, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.fizzed.crux.util;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * Lightweight timing for a little bit of anything. Uses System.nanoTime()
 * under-the-hood for highly precise measurements.  NOTE: nothing is synchronized
 * and should ideally only be used within a single thread.
 *  
 * @author joelauer
 */
public class StopWatch {

    private final TimeUnit tu;
    private final long start;
    // note: System.nanoTime() may return negative values so we must use
    // another variable to determine if the stopwatch is stopped yet
    private long stop;
    private boolean stopped;
    
    /**
     * Creates a stopwatch with a default time unit of milliseconds.
     */
    public StopWatch() {
        this(TimeUnit.MILLISECONDS, System.nanoTime(), -1, false);
    }
    
    /**
     * Creates a stopwatch with the specified time unit.
     * 
     * @param tu The time unit for formatting and comparison
     */
    public StopWatch(TimeUnit tu) {
        this(tu, System.nanoTime(), -1, false);
        Objects.requireNonNull(tu, "time unit was null");
    }
    
    // package-level for testing
    
    StopWatch(TimeUnit tu, long start, long stop, boolean stopped) {
        this.tu = tu;
        this.start = start;
        this.stop = stop;
        this.stopped = stopped;
    }

    /**
     * If still running (not stopped yet)
     * 
     * @return True if running or false if stopped
     */
    public boolean isRunning() {
        return !this.stopped;
    }
    
    public boolean isStopped() {
        return this.stopped;
    }

    public StopWatch stop() {
        if (isRunning()) {
            this.stop = System.nanoTime();
            this.stopped = true;
        }
        return this;
    }
    
    static public StopWatch timeMillis() {
        return new StopWatch(TimeUnit.MILLISECONDS);
    }
    
    static public StopWatch timeMillis(Runnable runnable) {
        return time(TimeUnit.MILLISECONDS, runnable);
    }
    
    static public StopWatch timeNanos() {
        return new StopWatch(TimeUnit.NANOSECONDS);
    }
    
    static public StopWatch timeNanos(Runnable runnable) {
        return time(TimeUnit.NANOSECONDS, runnable);
    }
    
    static public StopWatch timeSeconds() {
        return new StopWatch(TimeUnit.SECONDS);
    }
    
    static public StopWatch timeSeconds(Runnable runnable) {
        return time(TimeUnit.SECONDS, runnable);
    }
    
    static public StopWatch time(TimeUnit tu) {
        return new StopWatch(tu);
    }
    
    static public StopWatch time(TimeUnit tu, Runnable runnable) {
        StopWatch watch = new StopWatch(tu);
        try {
            runnable.run();
        } finally {
            watch.stop();
        }
        return watch;
    }
    
    /**
     * Returns the elapsed time based on the time unit of this stopwatch.
     * @return The elapsed time
     */
    public double elapsed() {
        return elapsed(this.tu);
    }
    
    /**
     * Returns the elapsed time for the specified time unit.
     * @param tu The time unit
     * @return The elapsed time
     */
    public double elapsed(TimeUnit tu) {
        switch (tu) {
            case NANOSECONDS:
                return this.elapsedNanos();
            case MICROSECONDS:
                return this.elapsedMicros();
            case MILLISECONDS:
                return this.elapsedMillis();
            case SECONDS:
                return this.elapsedSeconds();
            case MINUTES:
                return this.elapsedMinutes();
            case HOURS:
                return this.elapsedHours();
            case DAYS:
                return this.elapsedDays();
            default:
                throw new UnsupportedOperationException("Unable to handle time unit " + tu);
        }
    }
    
    public boolean eq(double duration) {
        return elapsed() == duration;
    }
    
    public boolean gt(double duration) {
        return elapsed() > duration;
    }
    
    public boolean gte(double duration) {
        return elapsed() >= duration;
    }
    
    public boolean lt(double duration) {
        return elapsed() < duration;
    }
    
    public boolean lte(double duration) {
        return elapsed() <= duration;
    }
    
    
    
    public long elapsedNanos() {
        if (this.stopped) {
            return (this.stop - this.start);
        } else {
            return (System.nanoTime() - this.start);
        }  
    }
    
    /**
     * Returns the total time elapsed in microseconds. If the timer is still
     * running then this is based on current time.
     *
     * @return The total elapsed time in microseconds (mu)
     */
    public double elapsedMicros() {
        return (double)elapsedNanos() / 1000.0d;
    }
    
    /**
     * Returns the total time elapsed in milliseconds. If the timer is still
     * running then this is based on current time.
     *
     * @return The total elapsed time in milliseconds (ms)
     */
    public double elapsedMillis() {
        return (double)elapsedNanos() / 1000000.0d;
    }
    
    /**
     * Returns the total time elapsed in seconds. If the timer is still
     * running then this is based on current time.
     *
     * @return The total elapsed time in seconds (s)
     */
    public double elapsedSeconds() {
        return this.elapsedNanos() / 1000000000.0d;
    }
    
    /**
     * Returns the total time elapsed in minutes. If the timer is still
     * running then this is based on current time.
     *
     * @return The total elapsed time in minutes (m)
     */
    public double elapsedMinutes() {
        return this.elapsedSeconds() / 60.0d;
    }
    
    /**
     * Returns the total time elapsed in hours. If the timer is still
     * running then this is based on current time.
     *
     * @return The total elapsed time in hours (h)
     */
    public double elapsedHours() {
        return this.elapsedMinutes() / 60.0d;
    }
    
    /**
     * Returns the total time elapsed in days. If the timer is still
     * running then this is based on current time.
     *
     * @return The total elapsed time in days (d)
     */
    public double elapsedDays() {
        return this.elapsedHours() / 24.0d;
    }

    /**
     * Returns the current elapsed time in a format determined by the default time
     * unit of this instance.
     *
     * @return A string of the current elapsed time such as "10.1 ms" or "0.12 s"
     */
    @Override
    public String toString() {
        return toString(this.tu);
    }
    
    /**
     * Returns the number of seconds this Stopwatch has elapsed
     *
     * @return The String of the number of seconds
     */
    public String toString(TimeUnit tu) {
        Objects.requireNonNull(tu, "time unit was null");
        switch (tu) {
            case NANOSECONDS:
                return String.format("%d ns", this.elapsedNanos());
            case MICROSECONDS:
                return String.format("%.0f mu", this.elapsedMicros());
            case SECONDS:
                return String.format("%.2f s", this.elapsedSeconds());
            case MINUTES:
                return String.format("%.2f m", this.elapsedMinutes());
            case HOURS:
                return String.format("%.2f h", this.elapsedHours());
            case DAYS:
                return String.format("%.2f d", this.elapsedDays());
            case MILLISECONDS:
            default:
                // default to millis
                return String.format("%.1f ms", this.elapsedMillis());
            
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy