/** * Copyright (c) 2010 Yahoo! Inc. All rights reserved. * * 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. See accompanying * LICENSE file. */ package com.yahoo.ycsb.measurements; import java.io.IOException; import java.text.DecimalFormat; import java.util.HashMap; import java.util.Properties; import com.yahoo.ycsb.measurements.exporter.MeasurementsExporter; /** * Take measurements and maintain a histogram of a given metric, such as READ LATENCY. * * @author cooperb * */ public class OneMeasurementHistogram extends OneMeasurement { public static final String BUCKETS="histogram.buckets"; public static final String BUCKETS_DEFAULT="1000"; int _buckets; int[] histogram; int histogramoverflow; int operations; long totallatency; //keep a windowed version of these stats for printing status int windowoperations; long windowtotallatency; int min; int max; HashMap<Integer,int[]> returncodes; public OneMeasurementHistogram(String name, Properties props) { super(name); _buckets=Integer.parseInt(props.getProperty(BUCKETS, BUCKETS_DEFAULT)); histogram=new int[_buckets]; histogramoverflow=0; operations=0; totallatency=0; windowoperations=0; windowtotallatency=0; min=-1; max=-1; returncodes=new HashMap<Integer,int[]>(); } /* (non-Javadoc) * @see com.yahoo.ycsb.OneMeasurement#reportReturnCode(int) */ public synchronized void reportReturnCode(int code) { Integer Icode=code; if (!returncodes.containsKey(Icode)) { int[] val=new int[1]; val[0]=0; returncodes.put(Icode,val); } returncodes.get(Icode)[0]++; } /* (non-Javadoc) * @see com.yahoo.ycsb.OneMeasurement#measure(int) */ public synchronized void measure(int latency) { if (latency/1000>=_buckets) { histogramoverflow++; } else { histogram[latency/1000]++; } operations++; totallatency+=latency; windowoperations++; windowtotallatency+=latency; if ( (min<0) || (latency<min) ) { min=latency; } if ( (max<0) || (latency>max) ) { max=latency; } } @Override public void exportMeasurements(MeasurementsExporter exporter) throws IOException { exporter.write(getName(), "Operations", operations); exporter.write(getName(), "AverageLatency(us)", (((double)totallatency)/((double)operations))); exporter.write(getName(), "MinLatency(us)", min); exporter.write(getName(), "MaxLatency(us)", max); int opcounter=0; boolean done95th=false; for (int i=0; i<_buckets; i++) { opcounter+=histogram[i]; if ( (!done95th) && (((double)opcounter)/((double)operations)>=0.95) ) { exporter.write(getName(), "95thPercentileLatency(ms)", i); done95th=true; } if (((double)opcounter)/((double)operations)>=0.99) { exporter.write(getName(), "99thPercentileLatency(ms)", i); break; } } for (Integer I : returncodes.keySet()) { int[] val=returncodes.get(I); exporter.write(getName(), "Return="+I, val[0]); } for (int i=0; i<_buckets; i++) { exporter.write(getName(), Integer.toString(i), histogram[i]); } exporter.write(getName(), ">"+_buckets, histogramoverflow); } @Override public String getSummary() { if (windowoperations==0) { return ""; } DecimalFormat d = new DecimalFormat("#.##"); double report=((double)windowtotallatency)/((double)windowoperations); windowtotallatency=0; windowoperations=0; return "["+getName()+" AverageLatency(us)="+d.format(report)+"]"; } }