/*
* Copyright (c)2005-2008 Mark Logic Corporation
*
* 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.
*
* The use of the Apache License does not indicate that this project is
* affiliated with the Apache Software Foundation.
*/
package com.marklogic.ps.timing;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
/*
* @author Michael Blakeley <michael.blakeley@marklogic.com>
*
*/
public class Timer {
public static final int BYTES_PER_KILOBYTE = 1024;
public static final int MILLISECONDS_PER_SECOND = 1000;
public static final int NANOSECONDS_PER_MICROSECOND = MILLISECONDS_PER_SECOND;
public static final int MICROSECONDS_PER_MILLISECOND = MILLISECONDS_PER_SECOND;
public static final int NANOSECONDS_PER_MILLISECOND = NANOSECONDS_PER_MICROSECOND
* MICROSECONDS_PER_MILLISECOND;
public static final int NANOSECONDS_PER_SECOND = NANOSECONDS_PER_MILLISECOND
* MILLISECONDS_PER_SECOND;
private volatile long errors = 0;
private volatile long bytes = 0;
private long duration = -1;
private volatile ArrayList<TimedEvent> events = new ArrayList<TimedEvent>();
private long start;
private volatile long eventCount;
public Timer() {
start = System.nanoTime();
eventCount = 0;
}
public void add(TimedEvent event) {
add(event, true);
}
public void add(TimedEvent event, boolean _keepEvent) {
// in case the user forgot to call stop(): note that bytes won't be
// counted!
event.stop();
synchronized (events) {
bytes += event.getBytes();
if (event.isError()) {
errors++;
}
if (_keepEvent) {
events.add(event);
}
eventCount++;
}
}
/**
* @param _timer
*/
public void add(Timer _timer) {
add(_timer, true);
}
/**
* @param _timer
* @param _keep
*/
public void add(Timer _timer, boolean _keep) {
_timer.stop();
synchronized (events) {
bytes += _timer.getBytes();
errors += _timer.getErrorCount();
if (_keep) {
events.addAll(_timer.events);
}
eventCount += _timer.eventCount;
}
}
/**
* @return
*/
public long getBytes() {
return bytes;
}
/**
* @return
*/
public long getEventCount() {
return eventCount;
}
/**
* @return
*/
public long getSuccessfulEventCount() {
return eventCount - errors;
}
/**
* @return
*/
public long getErrorCount() {
return errors;
}
/**
* @return
*/
public long getDuration() {
if (duration < 0)
return (System.nanoTime() - start);
return duration;
}
/**
* @return
*/
public long getMeanOfEvents() {
if (eventCount < 1)
return 0;
long sum = 0;
for (int i = 0; i < eventCount; i++) {
sum += events.get(i).getDuration();
}
return Math.round((double) sum / eventCount);
}
/**
* @return
*/
public long getPercentileDuration(int p) {
if (eventCount < 1)
return 0;
double size = eventCount;
Comparator<TimedEvent> c = new TimedEventDurationComparator();
Collections.sort(events, c);
int pidx = (int) (p * size * .01);
return events.get(pidx).getDuration();
}
/**
* @return
*/
public long getMaxDuration() {
long max = 0;
for (int i = 0; i < eventCount; i++)
max = Math.max(max, events.get(i).getDuration());
return max;
}
/**
* @return
*/
public long getMinDuration() {
long min = Integer.MAX_VALUE;
for (int i = 0; i < eventCount; i++)
min = Math.min(min, events.get(i).getDuration());
return min;
}
/**
* @return
*/
public long getMeanOverall() {
return getDuration() / eventCount;
}
/**
* @return
*/
public long getStart() {
return start;
}
/**
* @return
*/
public long getKiloBytes() {
return (long) ((double) bytes / BYTES_PER_KILOBYTE);
}
public double getKilobytesPerSecond() {
return ((double) bytes / BYTES_PER_KILOBYTE)
/ getDurationSeconds();
}
public double getEventsPerSecond() {
// events per second
return eventCount / getDurationSeconds();
}
/**
* @param l
*/
public long stop() {
return stop(System.nanoTime());
}
/**
* @param l
*/
public synchronized long stop(long l) {
if (duration < 0) {
duration = l - start;
}
return duration;
}
/**
*
*/
public void incrementEventCount() {
eventCount++;
}
/**
* @param count
*/
public void incrementEventCount(int count) {
eventCount += count;
}
/**
* @return
*/
public double getDurationMilliseconds() {
// ns to seconds
return ((double) getDuration())
/ ((double) NANOSECONDS_PER_MILLISECOND);
}
/**
* @return
*/
public double getDurationSeconds() {
// ns to seconds
return ((double) getDuration())
/ ((double) NANOSECONDS_PER_SECOND);
}
public String getProgressMessage(boolean rawValues) {
return (rawValues ? getBytes() + " B in " + getDurationSeconds()
+ " s, " : "")
+ Math.round(getEventsPerSecond())
+ " tps, "
+ Math.round(getKilobytesPerSecond()) + " kB/s";
}
/**
* @return
*/
public String getProgressMessage() {
return getProgressMessage(false);
}
/**
* @return
*/
public int getBytesPerSecond() {
return (int) (bytes / getDurationSeconds());
}
}