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

com.senzing.util.Timers Maven / Gradle / Ivy

The newest version!
package com.senzing.util;

import java.util.*;

/**
 * Provides functionality to measure timing values associated with functions
 * with {@link String} keys to assigned to identify what is being timed.
 */
public class Timers {
  /**
   * Internal method for getting {@link System#nanoTime()}.
   *
   * @return The current value for {@link System#nanoTime()}.
   */
  private static long now() {
    return System.nanoTime();
  }

  private static class TimerInfo {
    private Long    start        = null;
    private long    accumulated  = 0;

    private TimerInfo(long startTime) {
      this.start = startTime;
    }

    private TimerInfo() {
      this(now());
    }

    private TimerInfo(TimerInfo other) {
      this(other, now());
    }

    private TimerInfo(TimerInfo other, long atTime) {
      this.start        = null;
      this.accumulated  = other.getDuration(atTime);
    }

    private long getDuration() {
      return this.getDuration(now());
    }

    private long getDuration(long atTime) {
      if (this.start == null) return this.accumulated;

      return this.accumulated + ((atTime - this.start) / 1000000L);
    }

    private boolean isRunning() {
      return (this.start != null);
    }

    private boolean isPaused() {
      return (this.start == null);
    }

    private boolean pause() {
      return this.pause(now());
    }

    private boolean pause(long atTime) {
      if (this.start == null) return false;
      long duration = (atTime - this.start) / 1000000L;
      this.accumulated += duration;
      this.start = null;
      return true;
    }

    private boolean resume() {
      return this.resume(now());
    }

    private boolean resume(long atTime) {
      if (this.start != null) return false;
      this.start = atTime;
      return true;
    }

    private void mergeWith(TimerInfo timerInfo) {
      this.accumulated += timerInfo.getDuration();
    }

    private void mergeWith(TimerInfo timerInfo, long now) {
      this.accumulated += timerInfo.getDuration(now);
    }
  }

  private Map timerInfos;

  /**
   * Constructs with zero or more timer names that represent the initial
   * timer keys.  All of these timers will start immediately with the same
   * timestamp.
   *
   * @param initialTimers The zero or more names of the initial timers.  A
   *                      null array is treated like an empty
   *                      array.
   *
   * @throws NullPointerException If any of the specified parameters are
   *                              null.
   * @throws IllegalArgumentException If any of the specified timer names is
   *                                  duplicated.
   */
  public Timers(String... initialTimers)
    throws NullPointerException, IllegalArgumentException
  {
    this.timerInfos = new LinkedHashMap<>();
    long startTime = now();
    if (initialTimers != null) {
      for (String initialTimer : initialTimers) {
        // check for null
        if (initialTimer == null) {
          throw new NullPointerException(
              "Timer cannot have a null name: "
                  + (Arrays.asList(initialTimers)));
        }

        // check for a duplicate
        if (this.timerInfos.containsKey(initialTimer)) {
          throw new IllegalArgumentException(
              "At least one timer (" + initialTimer + ") is duplicated: "
              + (Arrays.asList(initialTimers)));
        }
        this.timerInfos.put(initialTimer, new TimerInfo(startTime));
      }
    }
  }

  /**
   * Checks if the specified timer exists.
   *
   * @param timerName The name of the timer.
   *
   * @return true if the timer exists, otherwise false.
   */
  public boolean hasTimer(String timerName) {
    return this.timerInfos.containsKey(timerName);
  }

  /**
   * Checks if the specified timer exists and is paused.
   *
   * @param timerName The name of the timer.
   *
   * @return true if the timer exists and is paused, otherwise
   *         false.
   */
  public boolean isPaused(String timerName) {
    TimerInfo info = this.timerInfos.get(timerName);
    return (info != null && info.isPaused());
  }

  /**
   * Checks if the specified timer exists and is running.
   *
   * @param timerName The name of the timer.
   *
   * @return true if the timer exists and is running, otherwise
   *         false.
   */
  public boolean isRunning(String timerName) {
    TimerInfo info = this.timerInfos.get(timerName);
    return (info != null && info.isRunning());
  }

  /**
   * Gets the recorded elapsed time for the specified timer name.  This returns
   * a negative number if the specified timer name is not recognized.
   *
   * @param timerName The name of the timer being requested.
   *
   * @return The accumulated elapsed number of milliseconds for the timer with
   *         the specified name or negative-one (-1) if the specified timer
   *         name is not recognized.
   */
  public long getElapsedTime(String timerName) {
    TimerInfo info = this.timerInfos.get(timerName);
    return (info != null ? info.getDuration() : -1L);
  }

  /**
   * Starts one or more new timers with the specified names.  This method
   * checks each of the timer names to see if they already exist and if a
   * timer by the specified name already exists and is running then it is
   * skipped (ignored).  If it exists and is paused then it is resumed.  This
   * method returns the number of timers that were created or resumed.
   *
   * @param timerName The name of the first timer to start.
   *
   * @param moreTimerNames Additional timer names to be started with the same
   *                       start time.
   *
   * @return The number of timer names that were for new timers that were
   *         created.
   */
  public int start(String timerName, String... moreTimerNames) {
    int count = 0;
    long now = now();
    TimerInfo info = this.timerInfos.get(timerName);
    if (info == null) {
      this.timerInfos.put(timerName, new TimerInfo(now));
      count++;
    } else if (info.resume()) {
      count++;
    }

    if (moreTimerNames != null) {
      for (String addlTimerName : moreTimerNames) {
        info = this.timerInfos.get(addlTimerName);
        if (info == null) {
          this.timerInfos.put(addlTimerName, new TimerInfo(now));
          count++;
        } else if (info.resume()) {
          count++;
        }
      }
    }

    return count;
  }

  /**
   * Pauses the one or more named timers.  If a named timer does not exist or
   * is not running it is skipped.  This method returns the number of timers
   * that were found and in a running state and therefore successfully paused.
   *
   * @param timerName The name of the timer.
   *
   * @param moreTimerNames Additional timer names to pause at the same time.
   *
   * @return The number of timers that were successfully paused.
   */
  public int pause(String timerName, String... moreTimerNames) {
    int count = 0;
    long now = now();
    TimerInfo info = this.timerInfos.get(timerName);
    if (info != null && info.pause(now)) count++;
    if (moreTimerNames != null) {
      for (String addlTimerName : moreTimerNames) {
        info = this.timerInfos.get(addlTimerName);
        if (info != null && info.pause(now)) count++;
      }
    }
    return count;
  }

  /**
   * Resumes the one or more named timers.  If a named timer does not exist or
   * is not paused it is skipped.  This method returns the number of timers
   * that were found in a paused state and therefore successfully resumed.
   *
   * @param timerName The name of the timer.
   *
   * @param moreTimerNames Additional timer names to pause at the same time.
   *
   * @return null if the timer name is not recognized, false
   *         if the timer is found, but was already running, and true
   *         if the timer is found and was paused and was successfully resumed.
   */
  public int resume(String timerName, String... moreTimerNames) {
    int count = 0;
    long now = now();
    TimerInfo info = this.timerInfos.get(timerName);
    if (info != null && info.resume(now)) count++;
    if (moreTimerNames != null) {
      for (String addlTimerName: moreTimerNames) {
        info = this.timerInfos.get(addlTimerName);
        if (info != null && info.resume(now)) count++;
      }
    }
    return count;
  }

  /**
   * Pauses all the timers that were running and returns the number of timers
   * that were running that were successfully paused.
   *
   * @return The number of timers that were running and were successfully
   *         paused.
   */
  public int pauseAll() {
    int count = 0;
    for (TimerInfo info : this.timerInfos.values()) {
      if (info.pause()) count++;
    }
    return count;
  }

  /**
   * Resumes all the timers that were paused and returns the number of timers
   * that were paused that were successfully resumed.
   *
   * @return The number of timers that were paused and were successfully
   *         resumed.
   */
  public int resumeAll() {
    int count = 0;
    for (TimerInfo info : this.timerInfos.values()) {
      if (info.resume()) count++;
    }
    return count;
  }

  /**
   * Returns a {@link Map} of all timer names to the their current durations.
   * If a timer is currently running it remains running, but the duration
   * is returned as if it was paused at the time this method was called.  If
   * the timer is currently paused it remains paused and the duration
   * accumulated at the time it was paused is returned.
   *
   * @return A {@link Map} of {@link String} timer name keys to {@link Long}
   *         values representing the current timings.
   */
  public Map getTimings() {
    Map result = new LinkedHashMap<>();
    long now = now();
    this.timerInfos.entrySet().forEach(e -> {
      result.put(e.getKey(), e.getValue().getDuration(now));
    });
    return result;
  }

  /**
   * Merges the durations from the specified {@link Timers} with this {@link
   * Timers} instance.  All the durations and timers from the specified
   * {@link Timers} instance are added to this one.
   *
   * @param timers The {@link Timers} to merge with.
   */
  public void mergeWith(Timers timers) {
    if (timers == null) return;
    long now = now();
    timers.timerInfos.entrySet().forEach(e -> {
      String    key    = e.getKey();
      TimerInfo info1  = this.timerInfos.get(key);
      TimerInfo info2  = e.getValue();
      if (info1 == null) {
        info1 = new TimerInfo(info2, now);
        this.timerInfos.put(key, info1);
      } else {
        info1.mergeWith(info2, now);
      }
    });
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy