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 e91375849e09c018bdd8f61bfa69f4e308086e17..6c84f80a1a00e0e1b0a176b6f2d0d49488bb6b7d 100644
--- a/core/src/main/java/com/yahoo/ycsb/measurements/Measurements.java
+++ b/core/src/main/java/com/yahoo/ycsb/measurements/Measurements.java
@@ -29,8 +29,18 @@ import com.yahoo.ycsb.measurements.exporter.MeasurementsExporter;
  * @author cooperb
  *
  */
-public class Measurements
-{
+public class Measurements {
+  /**
+   * All supported measurement types are defined in this enum.
+   *
+   */
+  public enum MeasurementType {
+    HISTOGRAM,
+    HDRHISTOGRAM,
+    HDRHISTOGRAM_AND_HISTOGRAM,
+    TIMESERIES,
+    RAW
+  }
 
   public static final String MEASUREMENT_TYPE_PROPERTY = "measurementtype";
   private static final String MEASUREMENT_TYPE_PROPERTY_DEFAULT = "hdrhistogram";
@@ -60,7 +70,7 @@ public class Measurements
 
   final ConcurrentHashMap<String,OneMeasurement> _opToMesurementMap;
   final ConcurrentHashMap<String,OneMeasurement> _opToIntendedMesurementMap;
-  final int _measurementType;
+  final MeasurementType _measurementType;
   final int _measurementInterval;
   private Properties _props;
 
@@ -77,19 +87,23 @@ public class Measurements
     String mTypeString = _props.getProperty(MEASUREMENT_TYPE_PROPERTY, MEASUREMENT_TYPE_PROPERTY_DEFAULT);
     if (mTypeString.equals("histogram"))
     {
-      _measurementType = 0;
+      _measurementType = MeasurementType.HISTOGRAM;
     }
     else if (mTypeString.equals("hdrhistogram"))
     {
-      _measurementType = 1;
+      _measurementType = MeasurementType.HDRHISTOGRAM;
     }
     else if (mTypeString.equals("hdrhistogram+histogram"))
     {
-      _measurementType = 2;
+      _measurementType = MeasurementType.HDRHISTOGRAM_AND_HISTOGRAM;
     }
     else if (mTypeString.equals("timeseries"))
     {
-      _measurementType = 3;
+      _measurementType = MeasurementType.TIMESERIES;
+    }
+    else if (mTypeString.equals("raw"))
+    {
+      _measurementType = MeasurementType.RAW;
     }
     else {
       throw new IllegalArgumentException("unknown "+MEASUREMENT_TYPE_PROPERTY+"="+mTypeString);
@@ -117,16 +131,20 @@ public class Measurements
   {
     switch (_measurementType)
     {
-    case 0:
+    case HISTOGRAM:
       return new OneMeasurementHistogram(name, _props);
-    case 1:
+    case HDRHISTOGRAM:
       return new OneMeasurementHdrHistogram(name, _props);
-    case 2:
+    case HDRHISTOGRAM_AND_HISTOGRAM:
       return new TwoInOneMeasurement(name,
               new OneMeasurementHdrHistogram("Hdr"+name, _props),
               new OneMeasurementHistogram("Bucket"+name, _props));
-    default:
+    case TIMESERIES:
       return new OneMeasurementTimeSeries(name, _props);
+    case RAW:
+      return new OneMeasurementRaw(name, _props);
+    default:
+      throw new AssertionError("Impossible to be here. Dead code reached. Bugs?");
     }
   }
 
diff --git a/core/src/main/java/com/yahoo/ycsb/measurements/OneMeasurementRaw.java b/core/src/main/java/com/yahoo/ycsb/measurements/OneMeasurementRaw.java
new file mode 100644
index 0000000000000000000000000000000000000000..b401b42f083760188a18228f67f6a3e67ffc254b
--- /dev/null
+++ b/core/src/main/java/com/yahoo/ycsb/measurements/OneMeasurementRaw.java
@@ -0,0 +1,192 @@
+/**
+ * Copyright (c) 2015 Google 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.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Properties;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import com.yahoo.ycsb.measurements.exporter.MeasurementsExporter;
+
+/**
+ * Record a series of measurements as raw data points without down sampling,
+ * optionally write to an output file when configured.
+ *
+ * @author stfeng
+ *
+ */
+public class OneMeasurementRaw extends OneMeasurement {
+  /**
+   * One raw data point, two fields: timestamp (ms) when the datapoint is
+   * inserted, and the value.
+   */
+  class RawDataPoint {
+    private final long timestamp;
+    private final int value;
+
+    public RawDataPoint(int value) {
+      this.timestamp = System.currentTimeMillis();
+      this.value = value;
+    }
+
+    public long timeStamp() {
+      return timestamp;
+    }
+
+    public int value() {
+      return value;
+    }
+  }
+
+  class RawDataPointComparator implements Comparator<RawDataPoint> {
+    @Override
+    public int compare(RawDataPoint p1, RawDataPoint p2){
+      if (p1.value() < p2.value()){
+        return -1;
+      } else if (p1.value() == p2.value()) {
+        return 0;
+      } else {
+        return 1;
+      }
+    }
+  }
+
+  /**
+   * Optionally, user can configure an output file to save the raw data points.
+   * Default is none, raw results will be written to stdout.
+   *
+   */
+  public static final String OUTPUT_FILE_PATH = "measurement.raw.output_file";
+  public static final String OUTPUT_FILE_PATH_DEFAULT = "";
+  private String outputFilePath = "";
+  private final PrintStream outputStream;
+
+  private ArrayList<RawDataPoint> measurements;
+  private long totalLatency = 0;
+
+  // A window of stats to print summary for at the next getSummary() call.
+  // It's supposed to be a one line summary, so we will just print count and 
+  // average.
+  private int windowOperations = 0;
+  private long windowTotalLatency = 0;
+
+  public OneMeasurementRaw(String name, Properties props) {
+    super(name);
+
+    outputFilePath = props.getProperty(OUTPUT_FILE_PATH,
+        OUTPUT_FILE_PATH_DEFAULT);
+    if (!outputFilePath.isEmpty()) {
+      System.out.println("Raw data measurement: will output to result file: " +
+          outputFilePath);
+
+      try {
+        outputStream = new PrintStream(
+            new FileOutputStream(outputFilePath, true),
+            true);
+      } catch (FileNotFoundException e) {
+        throw new RuntimeException("Failed to open raw data output file", e);
+      }
+
+    } else{
+      System.out.println("Raw data measurement: will output to stdout.");
+      outputStream = System.out;
+
+    }
+    measurements = new ArrayList<RawDataPoint>(1000);
+  }
+
+  @Override
+  public synchronized void measure(int latency) {
+    totalLatency += latency;
+    windowTotalLatency += latency;
+    windowOperations++;
+
+    measurements.add(new RawDataPoint(latency));
+  }
+
+  @Override
+  public void exportMeasurements(MeasurementsExporter exporter)
+      throws IOException {
+    // Output raw data points first then print out a summary of percentiles to
+    // stdout.
+
+    outputStream.println(getName() +
+        " latency raw data: op, timestamp(ms), latency(us)");
+    for (RawDataPoint point : measurements) {
+      outputStream.println(
+          String.format("%s,%d,%d", getName(), point.timeStamp(),
+              point.value()));
+    }
+    if (outputStream != System.out) {
+      outputStream.close();
+    }
+
+    int totalOps = measurements.size();
+    exporter.write(getName(), "Total Operations", totalOps);
+    if (totalOps > 0) {
+      exporter.write(getName(),
+          "Below is a summary of latency in microseconds:", -1);
+      exporter.write(getName(), "Average",
+          (double)totalLatency / (double)totalOps);
+
+      Collections.sort(measurements, new RawDataPointComparator());
+
+      exporter.write(getName(), "Min", measurements.get(0).value());
+      exporter.write(
+          getName(), "Max", measurements.get(totalOps - 1).value());
+      exporter.write(
+          getName(), "p1", measurements.get((int)(totalOps*0.01)).value());
+      exporter.write(
+          getName(), "p5", measurements.get((int)(totalOps*0.05)).value());
+      exporter.write(
+          getName(), "p50", measurements.get((int)(totalOps*0.5)).value());
+      exporter.write(
+          getName(), "p90", measurements.get((int)(totalOps*0.9)).value());
+      exporter.write(
+          getName(), "p95", measurements.get((int)(totalOps*0.95)).value());
+      exporter.write(
+          getName(), "p99", measurements.get((int)(totalOps*0.99)).value());
+      exporter.write(getName(), "p99.9",
+          measurements.get((int)(totalOps*0.999)).value());
+      exporter.write(getName(), "p99.99",
+          measurements.get((int)(totalOps*0.9999)).value());
+    }
+
+    exportReturnCodes(exporter);
+  }
+
+  @Override
+  public synchronized String getSummary() {
+    if (windowOperations == 0) {
+      return "";
+    }
+
+    String toReturn = String.format("%s count: %d, average latency(us): %.2f",
+        getName(), windowOperations,
+        (double)windowTotalLatency / (double)windowOperations);
+
+    windowTotalLatency=0;
+    windowOperations=0;
+
+    return toReturn;
+  }
+}
diff --git a/workloads/workload_template b/workloads/workload_template
index e59bace12a24c3180e585a737537684f0e3e7cd7..f95d1d4804e0aeb08bf1c300033cbbc6a9bb3f9d 100644
--- a/workloads/workload_template
+++ b/workloads/workload_template
@@ -115,6 +115,23 @@ table=usertable
 # How the latency measurements are presented
 measurementtype=histogram
 #measurementtype=timeseries
+#measurementtype=raw
+# When measurementtype is set to raw, measurements will be output
+# as RAW datapoints in the following csv format:
+# "operation, timestamp of the measurement, latency in us"
+#
+# Raw datapoints are collected in-memory while the test is running. Each
+# data point consumes about 20 bytes (including java object overhead).
+# For a typical run of 1 million to 10 million operations, this should
+# easily fit into memory. If you plan to do a run with 100s of millions of
+# operations, consider increasing your jvm heap size before you enable the
+# RAW measurement type, or split the run into multiple runs.
+#
+# Optionally, you can specify an output file to save raw datapoints.
+# Otherwise, raw datapoints will be written to stdout.
+# The output file will be appended to if it already exists, otherwise
+# a new output file will be created.
+#measurement.raw.output_file = /tmp/your_output_file_for_this_run
 
 # The range of latencies to track in the histogram (milliseconds)
 histogram.buckets=1000