Add functions to stopwatch

This commit is contained in:
James Agnew 2018-02-11 19:26:03 -05:00
parent 261ecb6460
commit 18e4d85625
2 changed files with 121 additions and 39 deletions

View File

@ -2,7 +2,9 @@ package ca.uhn.fhir.jpa.util;
import org.apache.commons.lang3.time.DateUtils; import org.apache.commons.lang3.time.DateUtils;
import java.text.DecimalFormat;
import java.util.Date; import java.util.Date;
import java.util.concurrent.TimeUnit;
/* /*
* #%L * #%L
@ -37,9 +39,20 @@ public class StopWatch {
/** /**
* Constructor * Constructor
*
* @param theStart The time to record as the start for this timer
*/ */
public StopWatch(Date theNow) { public StopWatch(Date theStart) {
myStarted = theNow.getTime(); myStarted = theStart.getTime();
}
public long getMillis() {
long now = System.currentTimeMillis();
return now - myStarted;
}
public long getMillis(Date theNow) {
return theNow.getTime() - myStarted;
} }
public long getMillisAndRestart() { public long getMillisAndRestart() {
@ -49,21 +62,40 @@ public class StopWatch {
return retVal; return retVal;
} }
public long getMillis() { /**
long now = System.currentTimeMillis(); * @param theNumOperations Ok for this to be 0, it will be treated as 1
long retVal = now - myStarted; */
return retVal; public int getMillisPerOperation(int theNumOperations) {
} return (int) (((double) getMillis()) / Math.max(1.0, theNumOperations));
public long getMillis(Date theNow) {
long retVal = theNow.getTime() - myStarted;
return retVal;
} }
public Date getStartedDate() { public Date getStartedDate() {
return new Date(myStarted); return new Date(myStarted);
} }
public double getThroughput(int theNumOperations, TimeUnit theUnit) {
if (theNumOperations <= 0) {
return 0.0f;
}
long millisElapsed = Math.max(1, getMillis());
long periodMillis = theUnit.toMillis(1);
double numerator = theNumOperations;
double denominator = ((double)millisElapsed)/((double)periodMillis);
return numerator / denominator;
}
public String formatThroughput(int theNumOperations, TimeUnit theUnit) {
double throughput = getThroughput(theNumOperations, theUnit);
return new DecimalFormat("0.0").format(throughput);
}
public void restart() {
myStarted = System.currentTimeMillis();
}
/** /**
* Formats value in the format [DD d ]HH:mm:ss.SSSS * Formats value in the format [DD d ]HH:mm:ss.SSSS
*/ */
@ -72,6 +104,23 @@ public class StopWatch {
return formatMillis(getMillis()); return formatMillis(getMillis());
} }
/**
* Append a right-aligned and zero-padded numeric value to a `StringBuilder`.
*/
static private void append(StringBuilder tgt, String pfx, int dgt, long val) {
tgt.append(pfx);
if (dgt > 1) {
int pad = (dgt - 1);
for (long xa = val; xa > 9 && pad > 0; xa /= 10) {
pad--;
}
for (int xa = 0; xa < pad; xa++) {
tgt.append('0');
}
}
tgt.append(val);
}
static public String formatMillis(long val) { static public String formatMillis(long val) {
StringBuilder buf = new StringBuilder(20); StringBuilder buf = new StringBuilder(20);
if (val >= DateUtils.MILLIS_PER_DAY) { if (val >= DateUtils.MILLIS_PER_DAY) {
@ -92,27 +141,4 @@ public class StopWatch {
return buf.toString(); return buf.toString();
} }
/** Append a right-aligned and zero-padded numeric value to a `StringBuilder`. */
static private void append(StringBuilder tgt, String pfx, int dgt, long val) {
tgt.append(pfx);
if (dgt > 1) {
int pad = (dgt - 1);
for (long xa = val; xa > 9 && pad > 0; xa /= 10) {
pad--;
}
for (int xa = 0; xa < pad; xa++) {
tgt.append('0');
}
}
tgt.append(val);
}
/**
* @param theNumOperations Ok for this to be 0, it will be treated as 1
*/
public int getMillisPerOperation(int theNumOperations) {
int numOperations = Math.min(1, theNumOperations);
return (int)(((double) getMillis()) / Math.max(1.0, numOperations));
}
} }

View File

@ -1,14 +1,14 @@
package ca.uhn.fhir.jpa.util; package ca.uhn.fhir.jpa.util;
import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.lessThan;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import java.util.Date; import java.util.Date;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.time.DateUtils; import org.apache.commons.lang3.time.DateUtils;
import org.hamcrest.Matchers;
import org.junit.Test; import org.junit.Test;
public class StopWatchTest { public class StopWatchTest {
@ -37,6 +37,62 @@ public class StopWatchTest {
assertThat(sw.getStartedDate().getTime(), lessThan(System.currentTimeMillis())); assertThat(sw.getStartedDate().getTime(), lessThan(System.currentTimeMillis()));
} }
@Test
public void testRestart() throws InterruptedException {
StopWatch sw = new StopWatch();
Thread.sleep(500);
sw.restart();
assertThat(sw.getMillis(), lessThan(100L));
}
@Test
public void testMillisPerOperation() {
int minutes = 60;
StopWatch sw = new StopWatch(DateUtils.addMinutes(new Date(), -minutes));
int numOperations = 60;
int millis = sw.getMillisPerOperation(numOperations);
ourLog.info("{} operations in {}ms = {}ms / operation", numOperations, minutes*DateUtils.MILLIS_PER_MINUTE, millis);
assertThat(millis, Matchers.lessThan(62000));
assertThat(millis, Matchers.greaterThan(58000));
}
@Test
public void testOperationThroughput60Ops1Min() {
double throughput = calculateThroughput(1, 60);
assertThat(throughput, greaterThan(59.0));
assertThat(throughput, lessThan(61.0));
}
@Test
public void testOperationThroughput30Ops1Min() {
double throughput = calculateThroughput(1, 30);
assertThat(throughput, greaterThan(29.0));
assertThat(throughput, lessThan(31.0));
}
@Test
public void testOperationThroughput60Ops4Min() {
double throughput = calculateThroughput(4, 60);
assertThat(throughput, greaterThan(14.0));
assertThat(throughput, lessThan(16.0));
}
@Test
public void testFormatThroughput60Ops4Min() {
StopWatch sw = new StopWatch(DateUtils.addMinutes(new Date(), -4));
String throughput = sw.formatThroughput(60, TimeUnit.MINUTES);
ourLog.info("{} operations in {}ms = {} ops / second", 60, sw.getMillis(), throughput);
assertThat(throughput, oneOf("14.9", "15.0", "15.1"));
}
private double calculateThroughput(int theMinutesElapsed, int theNumOperations) {
StopWatch sw = new StopWatch(DateUtils.addMinutes(new Date(), -theMinutesElapsed));
double throughput = sw.getThroughput(theNumOperations, TimeUnit.MINUTES);
ourLog.info("{} operations in {}ms = {} ops / second", theNumOperations, sw.getMillis(), throughput);
return throughput;
}
@Test @Test
public void testToString() throws Exception { public void testToString() throws Exception {
StopWatch sw = new StopWatch(); StopWatch sw = new StopWatch();