diff --git a/core/src/main/java/com/yahoo/ycsb/measurements/Measurements.java b/core/src/main/java/com/yahoo/ycsb/measurements/Measurements.java
index c082db4dddc6cd3efc09f7c3cd0f60987305e4e3..45f4e725cde4d550f81c4a9726c0cc7a9abd25af 100644
--- a/core/src/main/java/com/yahoo/ycsb/measurements/Measurements.java
+++ b/core/src/main/java/com/yahoo/ycsb/measurements/Measurements.java
@@ -20,6 +20,7 @@ package com.yahoo.ycsb.measurements;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
 
 import com.yahoo.ycsb.measurements.exporter.MeasurementsExporter;
 
@@ -56,8 +57,8 @@ public class Measurements
 		return singleton;
 	}
 
-	HashMap<String,OneMeasurement> data;
-	boolean histogram=true;
+	final ConcurrentHashMap<String,OneMeasurement> data;
+	int measurementType=0;
 
 	private Properties _props;
 	
@@ -66,50 +67,57 @@ public class Measurements
        */
 	public Measurements(Properties props)
 	{
-		data=new HashMap<String,OneMeasurement>();
+		data=new ConcurrentHashMap<String,OneMeasurement>();
 		
 		_props=props;
 		
-		if (_props.getProperty(MEASUREMENT_TYPE_PROPERTY, MEASUREMENT_TYPE_PROPERTY_DEFAULT).compareTo("histogram")==0)
+		String mTypeString = _props.getProperty(MEASUREMENT_TYPE_PROPERTY, MEASUREMENT_TYPE_PROPERTY_DEFAULT);
+        if (mTypeString.equals("histogram"))
 		{
-			histogram=true;
+		    measurementType=0;
 		}
-		else
-		{
-			histogram=false;
-		}
-	}
-	
-	OneMeasurement constructOneMeasurement(String name)
-	{
-		if (histogram)
+		else if (mTypeString.equals("hdrhistogram"))
 		{
-			return new OneMeasurementHistogram(name,_props);
-		}
+            measurementType=1;
+        }
 		else
 		{
-			return new OneMeasurementTimeSeries(name,_props);
+		    measurementType=2;
 		}
 	}
+	
+    OneMeasurement constructOneMeasurement(String name)
+    {
+        switch (measurementType)
+        {
+        case 0:
+            return new OneMeasurementHistogram(name, _props);
+        case 1:
+            return new OneMeasurementHdrHistogram(name, _props);
+
+        default:
+            return new OneMeasurementTimeSeries(name, _props);
+        }
+    }
 
       /**
        * Report a single value of a single metric. E.g. for read latency, operation="READ" and latency is the measured value.
        */
-	public synchronized void measure(String operation, int latency)
+	public void measure(String operation, int latency)
 	{
-		if (!data.containsKey(operation))
-		{
-			synchronized(this)
-			{
-				if (!data.containsKey(operation))
-				{
-					data.put(operation,constructOneMeasurement(operation));
-				}
-			}
-		}
+		
 		try
 		{
-			data.get(operation).measure(latency);
+			OneMeasurement m = data.get(operation);
+			if(m == null) {
+			    m = constructOneMeasurement(operation);
+			    OneMeasurement oldM = data.putIfAbsent(operation, m);
+			    if(oldM != null)
+			    {
+			        m = oldM;
+			    }
+			}
+            m.measure(latency);
 		}
 		catch (java.lang.ArrayIndexOutOfBoundsException e)
 		{
diff --git a/core/src/main/java/com/yahoo/ycsb/measurements/OneMeasurementHdrHistogram.java b/core/src/main/java/com/yahoo/ycsb/measurements/OneMeasurementHdrHistogram.java
new file mode 100644
index 0000000000000000000000000000000000000000..1265a65c140ebd7e2bf4c6a1b7539cc8e1d5475b
--- /dev/null
+++ b/core/src/main/java/com/yahoo/ycsb/measurements/OneMeasurementHdrHistogram.java
@@ -0,0 +1,134 @@
+/**                                                                                                                                                                                
+ * 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.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.HdrHistogram.ConcurrentHistogram;
+import org.HdrHistogram.Histogram;
+import org.HdrHistogram.Recorder;
+
+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 OneMeasurementHdrHistogram extends OneMeasurement {
+
+    Recorder histogram = new Recorder(3);
+    
+    final ConcurrentHashMap<Integer, AtomicInteger> returncodes;
+
+    Histogram totalHistogram;
+
+    public OneMeasurementHdrHistogram(String name, Properties props) {
+        super(name);
+        returncodes = new ConcurrentHashMap<Integer, AtomicInteger>();
+    }
+
+    /**
+     * No need for synchronization, using CHM to deal with that
+     * 
+     * @see com.yahoo.ycsb.OneMeasurement#reportReturnCode(int)
+     */
+    public void reportReturnCode(int code) {
+        Integer Icode = code;
+        AtomicInteger counter = returncodes.get(Icode);
+        if (counter == null) {
+            AtomicInteger other = returncodes.putIfAbsent(Icode, counter = new AtomicInteger());
+            if (other != null) {
+                counter = other;
+            }
+        }
+
+        counter.incrementAndGet();
+    }
+
+    /**
+     * It appears latency is reported in micros.
+     * Using {@link ConcurrentHistogram} to support concurrent updates to histogram.
+     * 
+     * @see com.yahoo.ycsb.OneMeasurement#measure(int)
+     */
+    public void measure(int latencyInMicros) {
+        histogram.recordValue(latencyInMicros);
+    }
+
+    /**
+     * This is called from a main thread, on orderly termination.
+     * 
+     * @see com.yahoo.ycsb.measurements.OneMeasurement#exportMeasurements(com.yahoo.ycsb.measurements.exporter.MeasurementsExporter)
+     */
+    @Override
+    public void exportMeasurements(MeasurementsExporter exporter) throws IOException {
+        Histogram lastIntervalHistogram = histogram.getIntervalHistogram();
+        // add this to the total time histogram.
+        if (totalHistogram == null) {
+            totalHistogram = lastIntervalHistogram; 
+        }
+        else {
+            totalHistogram.add(lastIntervalHistogram);
+        }
+        exporter.write(getName(), "Operations", totalHistogram.getTotalCount());
+        exporter.write(getName(), "AverageLatency(us)", totalHistogram.getMean());
+        exporter.write(getName(), "MinLatency(us)", totalHistogram.getMinValue());
+        exporter.write(getName(), "MaxLatency(us)", totalHistogram.getMaxValue());
+        exporter.write(getName(), "95thPercentileLatency(ms)", totalHistogram.getValueAtPercentile(90)/1000);
+        exporter.write(getName(), "99thPercentileLatency(ms)", totalHistogram.getValueAtPercentile(99)/1000);
+
+        for (Map.Entry<Integer, AtomicInteger> entry : returncodes.entrySet()) {
+            exporter.write(getName(), "Return=" + entry.getKey(), entry.getValue().get());
+        }
+
+    }
+
+    /**
+     * This is called periodically from the StatusThread. There's a single StatusThread per Client process.
+     * @see com.yahoo.ycsb.measurements.OneMeasurement#getSummary()
+     */
+    @Override
+    public String getSummary() {
+        Histogram intervalHistogram = histogram.getIntervalHistogram();
+        // add this to the total time histogram.
+        if (totalHistogram == null) {
+            totalHistogram = intervalHistogram; 
+        }
+        else {
+            totalHistogram.add(intervalHistogram);
+        }
+        DecimalFormat d = new DecimalFormat("#.##");
+        return "[" + getName() + 
+                ": Count=" + intervalHistogram.getTotalCount() + 
+                ", Max=" + intervalHistogram.getMaxValue() + 
+                ", Min=" + intervalHistogram.getMinValue() +
+                ", Avg=" + d.format(intervalHistogram.getMean()) +
+                ", 90=" + d.format(intervalHistogram.getValueAtPercentile(90)) +
+                ", 99=" + d.format(intervalHistogram.getValueAtPercentile(99)) +
+                ", 99.9=" + d.format(intervalHistogram.getValueAtPercentile(99.9)) +
+                ", 99.99=" + d.format(intervalHistogram.getValueAtPercentile(99.99)) +"]";
+    }
+
+}