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.util;
020
021import java.io.Closeable;
022import java.util.concurrent.TimeUnit;
023
024/**
025 * A simplified StopWatch implementation which can measure times in nanoseconds.
026 */
027public class StopWatch implements Closeable {
028  private final Timer timer;
029  private boolean isStarted;
030  private long startNanos;
031  private long currentElapsedNanos;
032
033  public StopWatch() {
034    this(new Timer());
035  }
036
037  /**
038   * Used for tests to be able to create a StopWatch which does not follow real
039   * time.
040   * @param timer The timer to base this StopWatch's timekeeping off of.
041   */
042  public StopWatch(Timer timer) {
043    this.timer = timer;
044  }
045
046  /**
047   * The method is used to find out if the StopWatch is started.
048   * @return boolean If the StopWatch is started.
049   */
050  public boolean isRunning() {
051    return isStarted;
052  }
053
054  /**
055   * Start to measure times and make the state of stopwatch running.
056   * @return this instance of StopWatch.
057   */
058  public StopWatch start() {
059    if (isStarted) {
060      throw new IllegalStateException("StopWatch is already running");
061    }
062    isStarted = true;
063    startNanos = timer.monotonicNowNanos();
064    return this;
065  }
066
067  /**
068   * Stop elapsed time and make the state of stopwatch stop.
069   * @return this instance of StopWatch.
070   */
071  public StopWatch stop() {
072    if (!isStarted) {
073      throw new IllegalStateException("StopWatch is already stopped");
074    }
075    long now = timer.monotonicNowNanos();
076    isStarted = false;
077    currentElapsedNanos += now - startNanos;
078    return this;
079  }
080
081  /**
082   * Reset elapsed time to zero and make the state of stopwatch stop.
083   * @return this instance of StopWatch.
084   */
085  public StopWatch reset() {
086    currentElapsedNanos = 0;
087    isStarted = false;
088    return this;
089  }
090
091  /**
092   * @return current elapsed time in specified timeunit.
093   */
094  public long now(TimeUnit timeUnit) {
095    return timeUnit.convert(now(), TimeUnit.NANOSECONDS);
096
097  }
098
099  /**
100   * @return current elapsed time in nanosecond.
101   */
102  public long now() {
103    return isStarted ?
104        timer.monotonicNowNanos() - startNanos + currentElapsedNanos :
105        currentElapsedNanos;
106  }
107
108  @Override
109  public String toString() {
110    return String.valueOf(now());
111  }
112
113  @Override
114  public void close() {
115    if (isStarted) {
116      stop();
117    }
118  }
119}