Skip to content
Snippets Groups Projects
Commit d6f1eae5 authored by Sean Busbey's avatar Sean Busbey
Browse files

[core] Merge Pull Request #371 from 'YCSB-hdr-default/master'

- *incompatible* Default measurement changed from histogram to hdrhistogram
  Users who want previous behavior can set the 'measurementtype' property to 'histogram'

- *incompatible* Reported 95th and 99th percentile latencies now in microseconds (previously in milliseconds)

Conflicts:
	core/src/main/java/com/yahoo/ycsb/measurements/OneMeasurementHdrHistogram.java

closes #371
parents 9a6bb424 5adc3ddd
No related branches found
No related tags found
No related merge requests found
...@@ -33,8 +33,8 @@ public class Measurements ...@@ -33,8 +33,8 @@ public class Measurements
{ {
public static final String MEASUREMENT_TYPE_PROPERTY = "measurementtype"; public static final String MEASUREMENT_TYPE_PROPERTY = "measurementtype";
private static final String MEASUREMENT_TYPE_PROPERTY_DEFAULT = "hdrhistogram";
private static final String MEASUREMENT_TYPE_PROPERTY_DEFAULT = "histogram";
public static final String MEASUREMENT_INTERVAL = "measurement.interval"; public static final String MEASUREMENT_INTERVAL = "measurement.interval";
private static final String MEASUREMENT_INTERVAL_DEFAULT = "op"; private static final String MEASUREMENT_INTERVAL_DEFAULT = "op";
......
...@@ -29,8 +29,8 @@ import com.yahoo.ycsb.measurements.exporter.MeasurementsExporter; ...@@ -29,8 +29,8 @@ import com.yahoo.ycsb.measurements.exporter.MeasurementsExporter;
*/ */
public abstract class OneMeasurement { public abstract class OneMeasurement {
String _name; private final String _name;
final ConcurrentHashMap<Integer, AtomicInteger> returncodes; private final ConcurrentHashMap<Integer, AtomicInteger> _returncodes;
public String getName() { public String getName() {
return _name; return _name;
...@@ -41,7 +41,7 @@ public abstract class OneMeasurement { ...@@ -41,7 +41,7 @@ public abstract class OneMeasurement {
*/ */
public OneMeasurement(String _name) { public OneMeasurement(String _name) {
this._name = _name; this._name = _name;
this.returncodes = new ConcurrentHashMap<Integer, AtomicInteger>(); this._returncodes = new ConcurrentHashMap<Integer, AtomicInteger>();
} }
public abstract void measure(int latency); public abstract void measure(int latency);
...@@ -53,10 +53,10 @@ public abstract class OneMeasurement { ...@@ -53,10 +53,10 @@ public abstract class OneMeasurement {
*/ */
public void reportReturnCode(int code) { public void reportReturnCode(int code) {
Integer Icode = code; Integer Icode = code;
AtomicInteger counter = returncodes.get(Icode); AtomicInteger counter = _returncodes.get(Icode);
if (counter == null) { if (counter == null) {
AtomicInteger other = returncodes.putIfAbsent(Icode, counter = new AtomicInteger()); AtomicInteger other = _returncodes.putIfAbsent(Icode, counter = new AtomicInteger());
if (other != null) { if (other != null) {
counter = other; counter = other;
} }
...@@ -73,4 +73,9 @@ public abstract class OneMeasurement { ...@@ -73,4 +73,9 @@ public abstract class OneMeasurement {
*/ */
public abstract void exportMeasurements(MeasurementsExporter exporter) throws IOException; public abstract void exportMeasurements(MeasurementsExporter exporter) throws IOException;
protected final void exportReturnCodes(MeasurementsExporter exporter) throws IOException {
for (Map.Entry<Integer, AtomicInteger> entry : _returncodes.entrySet()) {
exporter.write(getName(), "Return=" + entry.getKey(), entry.getValue().get());
}
}
} }
...@@ -34,8 +34,8 @@ import org.HdrHistogram.Recorder; ...@@ -34,8 +34,8 @@ import org.HdrHistogram.Recorder;
import com.yahoo.ycsb.measurements.exporter.MeasurementsExporter; import com.yahoo.ycsb.measurements.exporter.MeasurementsExporter;
/** /**
* Take measurements and maintain a HdrHistogram of a given metric, such as * Take measurements and maintain a HdrHistogram of a given metric, such as READ
* READ LATENCY. * LATENCY.
* *
* @author nitsanw * @author nitsanw
* *
...@@ -92,7 +92,7 @@ public class OneMeasurementHdrHistogram extends OneMeasurement { ...@@ -92,7 +92,7 @@ public class OneMeasurementHdrHistogram extends OneMeasurement {
public void exportMeasurements(MeasurementsExporter exporter) throws IOException { public void exportMeasurements(MeasurementsExporter exporter) throws IOException {
// accumulate the last interval which was not caught by status thread // accumulate the last interval which was not caught by status thread
Histogram intervalHistogram = getIntervalHistogramAndAccumulate(); Histogram intervalHistogram = getIntervalHistogramAndAccumulate();
if(histogramLogWriter != null) { if (histogramLogWriter != null) {
histogramLogWriter.outputIntervalHistogram(intervalHistogram); histogramLogWriter.outputIntervalHistogram(intervalHistogram);
// we can close now // we can close now
log.close(); log.close();
...@@ -101,49 +101,45 @@ public class OneMeasurementHdrHistogram extends OneMeasurement { ...@@ -101,49 +101,45 @@ public class OneMeasurementHdrHistogram extends OneMeasurement {
exporter.write(getName(), "AverageLatency(us)", totalHistogram.getMean()); exporter.write(getName(), "AverageLatency(us)", totalHistogram.getMean());
exporter.write(getName(), "MinLatency(us)", totalHistogram.getMinValue()); exporter.write(getName(), "MinLatency(us)", totalHistogram.getMinValue());
exporter.write(getName(), "MaxLatency(us)", totalHistogram.getMaxValue()); exporter.write(getName(), "MaxLatency(us)", totalHistogram.getMaxValue());
exporter.write(getName(), "95thPercentileLatency(ms)", totalHistogram.getValueAtPercentile(90)/1000); exporter.write(getName(), "95thPercentileLatency(us)", totalHistogram.getValueAtPercentile(90));
exporter.write(getName(), "99thPercentileLatency(ms)", totalHistogram.getValueAtPercentile(99)/1000); exporter.write(getName(), "99thPercentileLatency(us)", totalHistogram.getValueAtPercentile(99));
for (Map.Entry<Integer, AtomicInteger> entry : returncodes.entrySet()) { exportReturnCodes(exporter);
exporter.write(getName(), "Return=" + entry.getKey(), entry.getValue().get());
}
} }
/** /**
* This is called periodically from the StatusThread. There's a single StatusThread per Client process. * This is called periodically from the StatusThread. There's a single
* We optionally serialize the interval to log on this opportunity. * StatusThread per Client process. We optionally serialize the interval to
* @see com.yahoo.ycsb.measurements.OneMeasurement#getSummary() * log on this opportunity.
*/ *
@Override * @see com.yahoo.ycsb.measurements.OneMeasurement#getSummary()
public String getSummary() { */
Histogram intervalHistogram = getIntervalHistogramAndAccumulate(); @Override
// we use the summary interval as the histogram file interval. public String getSummary() {
if(histogramLogWriter != null) { Histogram intervalHistogram = getIntervalHistogramAndAccumulate();
histogramLogWriter.outputIntervalHistogram(intervalHistogram); // we use the summary interval as the histogram file interval.
} if (histogramLogWriter != null) {
histogramLogWriter.outputIntervalHistogram(intervalHistogram);
}
DecimalFormat d = new DecimalFormat("#.##"); DecimalFormat d = new DecimalFormat("#.##");
return "[" + getName() + return "[" + getName() + ": Count=" + intervalHistogram.getTotalCount() + ", Max="
": Count=" + intervalHistogram.getTotalCount() + + intervalHistogram.getMaxValue() + ", Min=" + intervalHistogram.getMinValue() + ", Avg="
", Max=" + intervalHistogram.getMaxValue() + + d.format(intervalHistogram.getMean()) + ", 90=" + d.format(intervalHistogram.getValueAtPercentile(90))
", Min=" + intervalHistogram.getMinValue() + + ", 99=" + d.format(intervalHistogram.getValueAtPercentile(99)) + ", 99.9="
", Avg=" + d.format(intervalHistogram.getMean()) + + d.format(intervalHistogram.getValueAtPercentile(99.9)) + ", 99.99="
", 90=" + d.format(intervalHistogram.getValueAtPercentile(90)) + + d.format(intervalHistogram.getValueAtPercentile(99.99)) + "]";
", 99=" + d.format(intervalHistogram.getValueAtPercentile(99)) + }
", 99.9=" + d.format(intervalHistogram.getValueAtPercentile(99.9)) +
", 99.99=" + d.format(intervalHistogram.getValueAtPercentile(99.99)) +"]";
}
private Histogram getIntervalHistogramAndAccumulate() { private Histogram getIntervalHistogramAndAccumulate() {
Histogram intervalHistogram = histogram.getIntervalHistogram(); Histogram intervalHistogram = histogram.getIntervalHistogram();
// add this to the total time histogram. // add this to the total time histogram.
if (totalHistogram == null) { if (totalHistogram == null) {
totalHistogram = intervalHistogram; totalHistogram = intervalHistogram;
} } else {
else { totalHistogram.add(intervalHistogram);
totalHistogram.add(intervalHistogram); }
} return intervalHistogram;
return intervalHistogram; }
}
} }
...@@ -109,19 +109,17 @@ public class OneMeasurementHistogram extends OneMeasurement ...@@ -109,19 +109,17 @@ public class OneMeasurementHistogram extends OneMeasurement
opcounter+=histogram[i]; opcounter+=histogram[i];
if ( (!done95th) && (((double)opcounter)/((double)operations)>=0.95) ) if ( (!done95th) && (((double)opcounter)/((double)operations)>=0.95) )
{ {
exporter.write(getName(), "95thPercentileLatency(ms)", i); exporter.write(getName(), "95thPercentileLatency(us)", i*1000);
done95th=true; done95th=true;
} }
if (((double)opcounter)/((double)operations)>=0.99) if (((double)opcounter)/((double)operations)>=0.99)
{ {
exporter.write(getName(), "99thPercentileLatency(ms)", i); exporter.write(getName(), "99thPercentileLatency(us)", i*1000);
break; break;
} }
} }
for (Map.Entry<Integer, AtomicInteger> entry : returncodes.entrySet()) { exportReturnCodes(exporter);
exporter.write(getName(), "Return=" + entry.getKey(), entry.getValue().get());
}
for (int i=0; i<_buckets; i++) for (int i=0; i<_buckets; i++)
{ {
......
...@@ -125,24 +125,18 @@ public class OneMeasurementTimeSeries extends OneMeasurement ...@@ -125,24 +125,18 @@ public class OneMeasurementTimeSeries extends OneMeasurement
@Override @Override
public void exportMeasurements(MeasurementsExporter exporter) throws IOException public void exportMeasurements(MeasurementsExporter exporter) throws IOException {
{
checkEndOfUnit(true); checkEndOfUnit(true);
exporter.write(getName(), "Operations", operations); exporter.write(getName(), "Operations", operations);
exporter.write(getName(), "AverageLatency(us)", (((double)totallatency)/((double)operations))); exporter.write(getName(), "AverageLatency(us)", (((double) totallatency) / ((double) operations)));
exporter.write(getName(), "MinLatency(us)", min); exporter.write(getName(), "MinLatency(us)", min);
exporter.write(getName(), "MaxLatency(us)", max); exporter.write(getName(), "MaxLatency(us)", max);
//TODO: 95th and 99th percentile latency // TODO: 95th and 99th percentile latency
for (Map.Entry<Integer, AtomicInteger> entry : returncodes.entrySet()) { exportReturnCodes(exporter);
exporter.write(getName(), "Return=" + entry.getKey(), entry.getValue().get()); for (SeriesUnit unit : _measurements) {
}
for (SeriesUnit unit : _measurements)
{
exporter.write(getName(), Long.toString(unit.time), unit.average); exporter.write(getName(), Long.toString(unit.time), unit.average);
} }
} }
......
...@@ -32,7 +32,9 @@ import static org.testng.AssertJUnit.assertTrue; ...@@ -32,7 +32,9 @@ import static org.testng.AssertJUnit.assertTrue;
public class TestMeasurementsExporter { public class TestMeasurementsExporter {
@Test @Test
public void testJSONArrayMeasurementsExporter() throws IOException { public void testJSONArrayMeasurementsExporter() throws IOException {
Measurements mm = new Measurements(new Properties()); Properties props = new Properties();
props.put(Measurements.MEASUREMENT_TYPE_PROPERTY, "histogram");
Measurements mm = new Measurements(props);
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
JSONArrayMeasurementsExporter export = new JSONArrayMeasurementsExporter(out); JSONArrayMeasurementsExporter export = new JSONArrayMeasurementsExporter(out);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment