changeset 220:e56f65c57d68

Specialized Statistics for the high-definition histogram.
author shade
date Mon, 04 Nov 2013 11:28:41 +0100
parents a49f57481f14
children 78a68cce08d1
files jmh-core/src/main/java/org/openjdk/jmh/logic/results/AverageTimePerOp.java jmh-core/src/main/java/org/openjdk/jmh/logic/results/OpsPerTimeUnit.java jmh-core/src/main/java/org/openjdk/jmh/logic/results/Result.java jmh-core/src/main/java/org/openjdk/jmh/logic/results/SampleTimePerOp.java jmh-core/src/main/java/org/openjdk/jmh/logic/results/SingleShotTime.java jmh-core/src/main/java/org/openjdk/jmh/util/internal/AbstractStatistics.java jmh-core/src/main/java/org/openjdk/jmh/util/internal/HashMultiset.java jmh-core/src/main/java/org/openjdk/jmh/util/internal/ListStatistics.java jmh-core/src/main/java/org/openjdk/jmh/util/internal/Multiset.java jmh-core/src/main/java/org/openjdk/jmh/util/internal/MultisetStatistics.java jmh-core/src/main/java/org/openjdk/jmh/util/internal/SampleBuffer.java jmh-core/src/main/java/org/openjdk/jmh/util/internal/Statistics.java jmh-core/src/main/java/org/openjdk/jmh/util/internal/TreeMultiset.java jmh-core/src/test/java/org/openjdk/jmh/util/TestListStatistics.java jmh-core/src/test/java/org/openjdk/jmh/util/TestMultisetStatistics.java jmh-core/src/test/java/org/openjdk/jmh/util/TestStatistics.java
diffstat 16 files changed, 908 insertions(+), 455 deletions(-) [+]
line wrap: on
line diff
--- a/jmh-core/src/main/java/org/openjdk/jmh/logic/results/AverageTimePerOp.java	Sun Nov 03 13:29:40 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/logic/results/AverageTimePerOp.java	Mon Nov 04 11:28:41 2013 +0100
@@ -25,6 +25,7 @@
 package org.openjdk.jmh.logic.results;
 
 import org.openjdk.jmh.runner.parameters.TimeValue;
+import org.openjdk.jmh.util.internal.ListStatistics;
 import org.openjdk.jmh.util.internal.Statistics;
 
 import java.util.Collection;
@@ -90,7 +91,7 @@
     public static class ResultAggregator implements Aggregator<AverageTimePerOp> {
         @Override
         public AverageTimePerOp aggregate(Collection<AverageTimePerOp> results) {
-            Statistics stat = new Statistics();
+            ListStatistics stat = new ListStatistics();
             ResultRole role = null;
             String label = null;
             long operations = 0;
--- a/jmh-core/src/main/java/org/openjdk/jmh/logic/results/OpsPerTimeUnit.java	Sun Nov 03 13:29:40 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/logic/results/OpsPerTimeUnit.java	Mon Nov 04 11:28:41 2013 +0100
@@ -25,6 +25,7 @@
 package org.openjdk.jmh.logic.results;
 
 import org.openjdk.jmh.runner.parameters.TimeValue;
+import org.openjdk.jmh.util.internal.ListStatistics;
 import org.openjdk.jmh.util.internal.Statistics;
 
 import java.util.Collection;
@@ -90,7 +91,7 @@
         return new Aggregator<OpsPerTimeUnit>() {
             @Override
             public Result aggregate(Collection<OpsPerTimeUnit> results) {
-                Statistics stat = new Statistics();
+                ListStatistics stat = new ListStatistics();
                 for (OpsPerTimeUnit r : results) {
                     stat.addValue(r.getScore());
                 }
@@ -121,7 +122,7 @@
         return new Aggregator<OpsPerTimeUnit>() {
             @Override
             public Result aggregate(Collection<OpsPerTimeUnit> results) {
-                Statistics stat = new Statistics();
+                ListStatistics stat = new ListStatistics();
                 for (OpsPerTimeUnit r : results) {
                     stat.addValue(r.getScore());
                 }
--- a/jmh-core/src/main/java/org/openjdk/jmh/logic/results/Result.java	Sun Nov 03 13:29:40 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/logic/results/Result.java	Mon Nov 04 11:28:41 2013 +0100
@@ -24,13 +24,13 @@
  */
 package org.openjdk.jmh.logic.results;
 
+import org.openjdk.jmh.util.internal.ListStatistics;
 import org.openjdk.jmh.util.internal.Statistics;
 
 import java.io.PrintWriter;
 import java.io.Serializable;
 import java.io.StringWriter;
 import java.text.NumberFormat;
-import java.util.concurrent.TimeUnit;
 
 /**
  * Base class for all types of results that can be returned by a microbenchmark.
@@ -46,7 +46,7 @@
     public Result(ResultRole role, String label, Statistics statistics) {
         this.role = role;
         this.label = label;
-        this.statistics = statistics == null ? new Statistics() : statistics;
+        this.statistics = statistics == null ? new ListStatistics() : statistics;
     }
 
     /**
--- a/jmh-core/src/main/java/org/openjdk/jmh/logic/results/SampleTimePerOp.java	Sun Nov 03 13:29:40 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/logic/results/SampleTimePerOp.java	Mon Nov 04 11:28:41 2013 +0100
@@ -96,7 +96,7 @@
                 convertNs(stats.getMean()),
                 getScoreUnit()));
         sb.append(String.format(", p{0.00, 0.50, 0.90, 0.95, 0.99, 0.999, 0.9999, 1.00} = %.0f, %.0f, %.0f, %.0f, %.0f, %.0f, %.0f, %.0f %s",
-                convertNs(stats.getPercentile(Double.MIN_VALUE)),
+                convertNs(stats.getPercentile(0)),
                 convertNs(stats.getPercentile(50)),
                 convertNs(stats.getPercentile(90)),
                 convertNs(stats.getPercentile(95)),
@@ -133,7 +133,7 @@
 
         sb.append(String.format("        min = %10.3f %s\n", convertNs(stats.getMin()), getScoreUnit()));
 
-        for (double p : new double[] {Double.MIN_VALUE, 0.50, 0.90, 0.95, 0.99, 0.999, 0.9999, 1.00}) {
+        for (double p : new double[] {0.00, 0.50, 0.90, 0.95, 0.99, 0.999, 0.9999, 1.00}) {
             sb.append(String.format("  %9s = %10.3f %s\n",
                     "p(" + String.format("%.4f", p) + ")",
                     convertNs(stats.getPercentile(p*100)),
--- a/jmh-core/src/main/java/org/openjdk/jmh/logic/results/SingleShotTime.java	Sun Nov 03 13:29:40 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/logic/results/SingleShotTime.java	Mon Nov 04 11:28:41 2013 +0100
@@ -25,6 +25,7 @@
 package org.openjdk.jmh.logic.results;
 
 import org.openjdk.jmh.runner.parameters.TimeValue;
+import org.openjdk.jmh.util.internal.ListStatistics;
 import org.openjdk.jmh.util.internal.Statistics;
 
 import java.util.Collection;
@@ -88,7 +89,7 @@
         public Result aggregate(Collection<SingleShotTime> results) {
             ResultRole role = null;
             String label = null;
-            Statistics stat = new Statistics();
+            ListStatistics stat = new ListStatistics();
             long duration = 0;
             TimeUnit tu = null;
             for (SingleShotTime r : results) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/util/internal/AbstractStatistics.java	Mon Nov 04 11:28:41 2013 +0100
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.util.internal;
+
+import java.util.Iterator;
+
+public abstract class AbstractStatistics implements Statistics {
+    private static final double[][] STUDENT_T = {
+            {3.078, 6.314, 12.706, 31.821, 63.657, 318.313},
+            {1.886, 2.920, 4.303, 6.965, 9.925, 22.327},
+            {1.638, 2.353, 3.182, 4.541, 5.841, 10.215},
+            {1.533, 2.132, 2.776, 3.747, 4.604, 7.173},
+            {1.476, 2.015, 2.571, 3.365, 4.032, 5.893},
+            {1.440, 1.943, 2.447, 3.143, 3.707, 5.208},
+            {1.415, 1.895, 2.365, 2.998, 3.499, 4.782},
+            {1.397, 1.860, 2.306, 2.896, 3.355, 4.499},
+            {1.383, 1.833, 2.262, 2.821, 3.250, 4.296},
+            {1.372, 1.812, 2.228, 2.764, 3.169, 4.143},
+            {1.363, 1.796, 2.201, 2.718, 3.106, 4.024},
+            {1.356, 1.782, 2.179, 2.681, 3.055, 3.929},
+            {1.350, 1.771, 2.160, 2.650, 3.012, 3.852},
+            {1.345, 1.761, 2.145, 2.624, 2.977, 3.787},
+            {1.341, 1.753, 2.131, 2.602, 2.947, 3.733},
+            {1.337, 1.746, 2.120, 2.583, 2.921, 3.686},
+            {1.333, 1.740, 2.110, 2.567, 2.898, 3.646},
+            {1.330, 1.734, 2.101, 2.552, 2.878, 3.610},
+            {1.328, 1.729, 2.093, 2.539, 2.861, 3.579},
+            {1.325, 1.725, 2.086, 2.528, 2.845, 3.552},
+            {1.323, 1.721, 2.080, 2.518, 2.831, 3.527},
+            {1.321, 1.717, 2.074, 2.508, 2.819, 3.505},
+            {1.319, 1.714, 2.069, 2.500, 2.807, 3.485},
+            {1.318, 1.711, 2.064, 2.492, 2.797, 3.467},
+            {1.316, 1.708, 2.060, 2.485, 2.787, 3.450},
+            {1.315, 1.706, 2.056, 2.479, 2.779, 3.435},
+            {1.314, 1.703, 2.052, 2.473, 2.771, 3.421},
+            {1.313, 1.701, 2.048, 2.467, 2.763, 3.408},
+            {1.311, 1.699, 2.045, 2.462, 2.756, 3.396},
+            {1.310, 1.697, 2.042, 2.457, 2.750, 3.385},
+            {1.309, 1.696, 2.040, 2.453, 2.744, 3.375},
+            {1.309, 1.694, 2.037, 2.449, 2.738, 3.365},
+            {1.308, 1.692, 2.035, 2.445, 2.733, 3.356},
+            {1.307, 1.691, 2.032, 2.441, 2.728, 3.348},
+            {1.306, 1.690, 2.030, 2.438, 2.724, 3.340},
+            {1.306, 1.688, 2.028, 2.434, 2.719, 3.333},
+            {1.305, 1.687, 2.026, 2.431, 2.715, 3.326},
+            {1.304, 1.686, 2.024, 2.429, 2.712, 3.319},
+            {1.304, 1.685, 2.023, 2.426, 2.708, 3.313},
+            {1.303, 1.684, 2.021, 2.423, 2.704, 3.307},
+            {1.303, 1.683, 2.020, 2.421, 2.701, 3.301},
+            {1.302, 1.682, 2.018, 2.418, 2.698, 3.296},
+            {1.302, 1.681, 2.017, 2.416, 2.695, 3.291},
+            {1.301, 1.680, 2.015, 2.414, 2.692, 3.286},
+            {1.301, 1.679, 2.014, 2.412, 2.690, 3.281},
+            {1.300, 1.679, 2.013, 2.410, 2.687, 3.277},
+            {1.300, 1.678, 2.012, 2.408, 2.685, 3.273},
+            {1.299, 1.677, 2.011, 2.407, 2.682, 3.269},
+            {1.299, 1.677, 2.010, 2.405, 2.680, 3.265},
+            {1.299, 1.676, 2.009, 2.403, 2.678, 3.261},
+            {1.298, 1.675, 2.008, 2.402, 2.676, 3.258},
+            {1.298, 1.675, 2.007, 2.400, 2.674, 3.255},
+            {1.298, 1.674, 2.006, 2.399, 2.672, 3.251},
+            {1.297, 1.674, 2.005, 2.397, 2.670, 3.248},
+            {1.297, 1.673, 2.004, 2.396, 2.668, 3.245},
+            {1.297, 1.673, 2.003, 2.395, 2.667, 3.242},
+            {1.297, 1.672, 2.002, 2.394, 2.665, 3.239},
+            {1.296, 1.672, 2.002, 2.392, 2.663, 3.237},
+            {1.296, 1.671, 2.001, 2.391, 2.662, 3.234},
+            {1.296, 1.671, 2.000, 2.390, 2.660, 3.232},
+            {1.296, 1.670, 2.000, 2.389, 2.659, 3.229},
+            {1.295, 1.670, 1.999, 2.388, 2.657, 3.227},
+            {1.295, 1.669, 1.998, 2.387, 2.656, 3.225},
+            {1.295, 1.669, 1.998, 2.386, 2.655, 3.223},
+            {1.295, 1.669, 1.997, 2.385, 2.654, 3.220},
+            {1.295, 1.668, 1.997, 2.384, 2.652, 3.218},
+            {1.294, 1.668, 1.996, 2.383, 2.651, 3.216},
+            {1.294, 1.668, 1.995, 2.382, 2.650, 3.214},
+            {1.294, 1.667, 1.995, 2.382, 2.649, 3.213},
+            {1.294, 1.667, 1.994, 2.381, 2.648, 3.211},
+            {1.294, 1.667, 1.994, 2.380, 2.647, 3.209},
+            {1.293, 1.666, 1.993, 2.379, 2.646, 3.207},
+            {1.293, 1.666, 1.993, 2.379, 2.645, 3.206},
+            {1.293, 1.666, 1.993, 2.378, 2.644, 3.204},
+            {1.293, 1.665, 1.992, 2.377, 2.643, 3.202},
+            {1.293, 1.665, 1.992, 2.376, 2.642, 3.201},
+            {1.293, 1.665, 1.991, 2.376, 2.641, 3.199},
+            {1.292, 1.665, 1.991, 2.375, 2.640, 3.198},
+            {1.292, 1.664, 1.990, 2.374, 2.640, 3.197},
+            {1.292, 1.664, 1.990, 2.374, 2.639, 3.195},
+            {1.292, 1.664, 1.990, 2.373, 2.638, 3.194},
+            {1.292, 1.664, 1.989, 2.373, 2.637, 3.193},
+            {1.292, 1.663, 1.989, 2.372, 2.636, 3.191},
+            {1.292, 1.663, 1.989, 2.372, 2.636, 3.190},
+            {1.292, 1.663, 1.988, 2.371, 2.635, 3.189},
+            {1.291, 1.663, 1.988, 2.370, 2.634, 3.188},
+            {1.291, 1.663, 1.988, 2.370, 2.634, 3.187},
+            {1.291, 1.662, 1.987, 2.369, 2.633, 3.185},
+            {1.291, 1.662, 1.987, 2.369, 2.632, 3.184},
+            {1.291, 1.662, 1.987, 2.368, 2.632, 3.183},
+            {1.291, 1.662, 1.986, 2.368, 2.631, 3.182},
+            {1.291, 1.662, 1.986, 2.368, 2.630, 3.181},
+            {1.291, 1.661, 1.986, 2.367, 2.630, 3.180},
+            {1.291, 1.661, 1.986, 2.367, 2.629, 3.179},
+            {1.291, 1.661, 1.985, 2.366, 2.629, 3.178},
+            {1.290, 1.661, 1.985, 2.366, 2.628, 3.177},
+            {1.290, 1.661, 1.985, 2.365, 2.627, 3.176},
+            {1.290, 1.661, 1.984, 2.365, 2.627, 3.175},
+            {1.290, 1.660, 1.984, 2.365, 2.626, 3.175},
+            {1.290, 1.660, 1.984, 2.364, 2.626, 3.174},
+            {1.282, 1.645, 1.960, 2.326, 2.576, 3.090}
+    };
+
+    /**
+     * Returns the interval c1, c2 of which there's an 1-alpha
+     * probability of the mean being within the interval.
+     *
+     * @param alpha alpha parameter
+     * @return the confidence interval
+     */
+    @Override
+    public double[] getConfidenceInterval(double alpha) {
+        double[] interval = new double[2];
+
+        double ip = getStudentT(1 - alpha / 2.0, getN() - 1);
+        interval[0] = getMean() - ip * (getStandardDeviation() / Math.sqrt(getN()));
+        interval[1] = getMean() + ip * (getStandardDeviation() / Math.sqrt(getN()));
+
+        return interval;
+    }
+
+    protected double getStudentT(double alpha, int n) {
+        if (n <= 1) throw new IllegalStateException();
+
+        double[] indices = {0.90, 0.95, 0.975, 0.99, 0.995, 0.999};
+
+        int index = indices.length - 1;
+        for (int i = 0; i < indices.length - 1; i++) {
+            if (indices[i] <= alpha && alpha < indices[i + 1]) {
+                index = i;
+                break;
+            }
+        }
+
+        if (n > STUDENT_T.length) {
+            n = STUDENT_T.length;
+        }
+
+        return STUDENT_T[n - 1][index];
+    }
+
+    @Override
+    public double getMeanError(double alpha) {
+        double ip = getStudentT(1 - alpha / 2.0, getN() - 1);
+        return ip * (getStandardDeviation() / Math.sqrt(getN()));
+    }
+
+    @Override
+    public String toString() {
+        return "N:" + getN() + " Mean: " + getMean()
+                + " Min: " + getMin() + " Max: " + getMax()
+                + " StdDev: " + getStandardDeviation();
+    }
+
+    @Override
+    public double getMean() {
+        if (getN() > 0) {
+            return getSum() / getN();
+        } else {
+            return Double.NaN;
+        }
+    }
+
+    @Override
+    public double getStandardDeviation() {
+        return Math.sqrt(getVariance());
+    }
+
+    @Override
+    public double getVariance() {
+        if (getN() > 0) {
+            double v = 0;
+            double m = getMean();
+            for (Iterator<Double> it = valuesIterator(); it.hasNext(); ) {
+                double d = it.next();
+                v += Math.pow(d - m, 2);
+            }
+            return v / (getN() - 1);
+        } else {
+            return Double.NaN;
+        }
+    }
+
+    protected abstract Iterator<Double> valuesIterator();
+}
--- a/jmh-core/src/main/java/org/openjdk/jmh/util/internal/HashMultiset.java	Sun Nov 03 13:29:40 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/util/internal/HashMultiset.java	Mon Nov 04 11:28:41 2013 +0100
@@ -41,13 +41,22 @@
 
     @Override
     public void add(T element) {
+        add(element, 1);
+    }
+
+    @Override
+    public void add(T element, int add) {
         Integer count = map.get(element);
         if (count == null) {
             count = 0;
         }
-        count++;
-        size++;
-        map.put(element, count);
+        count += add;
+        size += add;
+        if (count != 0) {
+            map.put(element, count);
+        } else {
+            map.remove(element);
+        }
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/util/internal/ListStatistics.java	Mon Nov 04 11:28:41 2013 +0100
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.util.internal;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Calculate statistics over a list of doubles.
+ *
+ * @author staffan.friberg@oracle.com, anders.astrand@oracle.com
+ */
+public class ListStatistics extends AbstractStatistics {
+
+    private static final long serialVersionUID = -90642978235578197L;
+
+    private final List<Double> values;
+
+    public ListStatistics() {
+        values = new ArrayList<Double>();
+    }
+
+    public ListStatistics(double[] samples) {
+        this();
+        for (double d : samples) {
+            addValue(d);
+        }
+    }
+
+    public ListStatistics(long[] samples) {
+        this();
+        for (long l : samples) {
+            addValue((double) l);
+        }
+    }
+
+    public void addValue(double d) {
+        values.add(d);
+    }
+
+    @Override
+    public double getMax() {
+        if (getN() > 0) {
+            double m = Double.NEGATIVE_INFINITY;
+            for (double d : values) {
+                m = Math.max(m, d);
+            }
+            return m;
+        } else {
+            return Double.NaN;
+        }
+    }
+
+    @Override
+    public double getMin() {
+        if (getN() > 0) {
+            double m = Double.POSITIVE_INFINITY;
+            for (double d : values) {
+                m = Math.min(m, d);
+            }
+            return m;
+        } else {
+            return Double.NaN;
+        }
+    }
+
+    @Override
+    public int getN() {
+        return values.size();
+    }
+
+    @Override
+    public double getSum() {
+        if (getN() > 0) {
+            double s = 0;
+            for (double d : values) {
+                s += d;
+            }
+            return s;
+        } else {
+            return Double.NaN;
+        }
+    }
+
+    @Override
+    public double getPercentile(double rank) {
+        if (values.size() == 0) {
+            return Double.NaN;
+        }
+
+        Collections.sort(values);
+
+        int n1 = (int) Math.floor(rank / 100.0D * values.size());
+        int n2 = (int) Math.ceil(rank / 100.D * values.size());
+
+        if (n1 < 0) {
+            n1 = 0;
+        }
+
+        if (n2 < 0) {
+            n2 = 0;
+        }
+
+        if (n1 >= values.size()) {
+            n1 = values.size() - 1;
+        }
+
+        if (n2 >= values.size()) {
+            n2 = values.size() - 1;
+        }
+
+        double v1 = values.get(n1);
+        double v2 = values.get(n2);
+
+        return v1 + (v2 - v1) / 2;
+    }
+
+    @Override
+    protected Iterator<Double> valuesIterator() {
+        return values.iterator();
+    }
+}
--- a/jmh-core/src/main/java/org/openjdk/jmh/util/internal/Multiset.java	Sun Nov 03 13:29:40 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/util/internal/Multiset.java	Mon Nov 04 11:28:41 2013 +0100
@@ -42,6 +42,13 @@
     void add(T element);
 
     /**
+     * Add the element to the multiset
+     * @param element element to add
+     * @param count number of elements to add
+     */
+    void add(T element, int count);
+
+    /**
      * Count the elements in multiset
      * @param element element
      * @return number of matching elements in the set; zero, if no elements
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/util/internal/MultisetStatistics.java	Mon Nov 04 11:28:41 2013 +0100
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.util.internal;
+
+import java.util.Collections;
+import java.util.Iterator;
+
+public class MultisetStatistics extends AbstractStatistics {
+
+    private final Multiset<Double> values;
+
+    public MultisetStatistics() {
+        values = new TreeMultiset<Double>();
+    }
+
+    public void addValue(double d, int count) {
+        values.add(d, count);
+    }
+
+    @Override
+    public double getMax() {
+        double max = Double.NEGATIVE_INFINITY;
+        for (double d : values.keys()) {
+            max = Math.max(max, d);
+        }
+        return max;
+    }
+
+    @Override
+    public double getMin() {
+        double min = Double.POSITIVE_INFINITY;
+        for (double d : values.keys()) {
+            min = Math.min(min, d);
+        }
+        return min;
+    }
+
+    @Override
+    public int getN() {
+        return values.size();
+    }
+
+    @Override
+    public double getSum() {
+        double sum = 0;
+        for (double d : values.keys()) {
+            sum += d*values.count(d);
+        }
+        return sum;
+    }
+
+    @Override
+    public double getPercentile(double rank) {
+        if (rank < 0.0d || rank > 100.0d)
+            throw new IllegalArgumentException("Rank should be within [0; 100]");
+
+        long thresh = (long) (values.size() * rank / 100.0);
+        long cur = 0;
+        for (double d : values.keys()) {
+            cur += values.count(d);
+            if (cur >= thresh) return d;
+        }
+        return Double.NaN;
+    }
+
+    @Override
+    protected Iterator<Double> valuesIterator() {
+        return new Iterator<Double>() {
+            private Iterator<Double> current = values.keys().iterator();
+            private int count;
+            private Double val;
+
+            private void ensureNonEmpty() {
+                while (count == 0 && current.hasNext()) {
+                    val = current.next();
+                    count = values.count(val);
+                }
+            }
+
+            @Override
+            public boolean hasNext() {
+                ensureNonEmpty();
+                return (count > 0);
+            }
+
+            @Override
+            public Double next() {
+                ensureNonEmpty();
+                if (count > 0) {
+                    count--;
+                    return val;
+                } else {
+                    return Collections.<Double>emptyIterator().next();
+                }
+            }
+
+            @Override
+            public void remove() {
+                throw new UnsupportedOperationException("Nope.");
+            }
+        };
+    }
+}
--- a/jmh-core/src/main/java/org/openjdk/jmh/util/internal/SampleBuffer.java	Sun Nov 03 13:29:40 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/util/internal/SampleBuffer.java	Mon Nov 04 11:28:41 2013 +0100
@@ -66,13 +66,10 @@
     }
 
     public Statistics getStatistics() {
-        // TODO: This method is very memory-hungry, make the specialized Statistics
-        Statistics stat = new Statistics();
+        MultisetStatistics stat = new MultisetStatistics();
         for (int i = 0; i < hdr.length; i++) {
             for (int j = 0; j < hdr[i].length; j++) {
-                for (int c = 0; c < hdr[i][j]; c++) {
-                    stat.addValue(j << i);
-                }
+                stat.addValue((long) j << i, hdr[i][j]);
             }
         }
         return stat;
--- a/jmh-core/src/main/java/org/openjdk/jmh/util/internal/Statistics.java	Sun Nov 03 13:29:40 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/util/internal/Statistics.java	Mon Nov 04 11:28:41 2013 +0100
@@ -25,303 +25,26 @@
 package org.openjdk.jmh.util.internal;
 
 import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
 
-/**
- * Calculate statistics over a list of doubles.
- *
- * @author staffan.friberg@oracle.com, anders.astrand@oracle.com
- */
-public class Statistics implements Serializable {
+public interface Statistics extends Serializable {
 
-    private static final long serialVersionUID = -90642978235578197L;
+    double[] getConfidenceInterval(double alpha);
 
-    private final List<Double> values;
+    double getMeanError(double alpha);
 
-    public Statistics() {
-        values = new ArrayList<Double>();
-    }
+    double getStandardDeviation();
 
-    public Statistics(double[] samples) {
-        this();
-        for (double d : samples) {
-            addValue(d);
-        }
-    }
+    double getMax();
 
-    public Statistics(long[] samples) {
-        this();
-        for (long l : samples) {
-            addValue((double) l);
-        }
-    }
+    double getMin();
 
-    public void addValue(double d) {
-        values.add(d);
-    }
+    double getMean();
 
-    /**
-     * Returns the interval c1, c2 of which there's an 1-alpha
-     * probability of the mean being within the interval.
-     *
-     * @param alpha alpha parameter
-     * @return the confidence interval
-     */
-    public double[] getConfidenceInterval(double alpha) {
-        double[] interval = new double[2];
+    int getN();
 
-        double ip = getStudentT(1 - alpha / 2.0, getN() - 1);
-        interval[0] = getMean() - ip * (getStandardDeviation() / Math.sqrt(getN()));
-        interval[1] = getMean() + ip * (getStandardDeviation() / Math.sqrt(getN()));
+    double getSum();
 
-        return interval;
-    }
+    double getVariance();
 
-    public double getMeanError(double alpha) {
-        double ip = getStudentT(1 - alpha / 2.0, getN() - 1);
-        return ip * (getStandardDeviation() / Math.sqrt(getN()));
-    }
-
-    private double getStudentT(double alpha, int n) {
-        if (n <= 1) throw new IllegalStateException();
-
-        double[] indices = {0.90, 0.95, 0.975, 0.99, 0.995, 0.999};
-
-        int index = indices.length - 1;
-        for (int i = 0; i < indices.length - 1; i++) {
-            if (indices[i] <= alpha && alpha < indices[i + 1]) {
-                index = i;
-                break;
-            }
-        }
-
-        if (n > STUDENT_T.length) {
-            n = STUDENT_T.length;
-        }
-
-        return STUDENT_T[n - 1][index];
-    }
-
-    public double[] getValues() {
-        double[] r = new double[getN()];
-        for (int i = 0; i < getN(); i++) {
-            r[i] = values.get(i);
-        }
-        return r;
-    }
-
-    @Override
-    public String toString() {
-        return "N:" + getN() + " Mean: " + getMean()
-                + " Min: " + getMin() + " Max: " + getMax()
-                + " StdDev: " + getStandardDeviation();
-    }
-
-    public double getStandardDeviation() {
-        return Math.sqrt(getVariance());
-    }
-
-    public double getMax() {
-        if (getN() > 0) {
-            double m = Double.NEGATIVE_INFINITY;
-            for (double d : values) {
-                m = Math.max(m, d);
-            }
-            return m;
-        } else {
-            return Double.NaN;
-        }
-    }
-
-    public double getMin() {
-        if (getN() > 0) {
-            double m = Double.POSITIVE_INFINITY;
-            for (double d : values) {
-                m = Math.min(m, d);
-            }
-            return m;
-        } else {
-            return Double.NaN;
-        }
-    }
-
-    public double getMean() {
-        if (getN() > 0) {
-            return getSum() / getN();
-        } else {
-            return Double.NaN;
-        }
-    }
-
-    public int getN() {
-        return values.size();
-    }
-
-    public double getSum() {
-        if (getN() > 0) {
-            double s = 0;
-            for (double d : values) {
-                s += d;
-            }
-            return s;
-        } else {
-            return Double.NaN;
-        }
-    }
-
-    public double getVariance() {
-        if (getN() > 0) {
-            double v = 0;
-            double m = getMean();
-            for (double d : values) {
-                v += Math.pow(d - m, 2);
-            }
-            return v / (getN() - 1);
-        } else {
-            return Double.NaN;
-        }
-    }
-
-    public double getPercentile(double rank) {
-        return getPercentile(getValues(), rank);
-    }
-
-    static double getPercentile(double[] values, double rank) {
-        if (values.length == 0) {
-            return Double.NaN;
-        }
-
-        Arrays.sort(values);
-
-        int n1 = (int) Math.floor(rank / 100.0D * values.length);
-        int n2 = (int) Math.ceil(rank / 100.D * values.length);
-
-        if (n1 < 0) {
-            n1 = 0;
-        }
-
-        if (n2 < 0) {
-            n2 = 0;
-        }
-
-        if (n1 >= values.length) {
-            n1 = values.length - 1;
-        }
-
-        if (n2 >= values.length) {
-            n2 = values.length - 1;
-        }
-
-        double v1 = values[n1];
-        double v2 = values[n2];
-
-        return v1 + (v2 - v1) / 2;
-    }
-
-    private static final double[][] STUDENT_T = {
-            {3.078, 6.314, 12.706, 31.821, 63.657, 318.313},
-            {1.886, 2.920, 4.303, 6.965, 9.925, 22.327},
-            {1.638, 2.353, 3.182, 4.541, 5.841, 10.215},
-            {1.533, 2.132, 2.776, 3.747, 4.604, 7.173},
-            {1.476, 2.015, 2.571, 3.365, 4.032, 5.893},
-            {1.440, 1.943, 2.447, 3.143, 3.707, 5.208},
-            {1.415, 1.895, 2.365, 2.998, 3.499, 4.782},
-            {1.397, 1.860, 2.306, 2.896, 3.355, 4.499},
-            {1.383, 1.833, 2.262, 2.821, 3.250, 4.296},
-            {1.372, 1.812, 2.228, 2.764, 3.169, 4.143},
-            {1.363, 1.796, 2.201, 2.718, 3.106, 4.024},
-            {1.356, 1.782, 2.179, 2.681, 3.055, 3.929},
-            {1.350, 1.771, 2.160, 2.650, 3.012, 3.852},
-            {1.345, 1.761, 2.145, 2.624, 2.977, 3.787},
-            {1.341, 1.753, 2.131, 2.602, 2.947, 3.733},
-            {1.337, 1.746, 2.120, 2.583, 2.921, 3.686},
-            {1.333, 1.740, 2.110, 2.567, 2.898, 3.646},
-            {1.330, 1.734, 2.101, 2.552, 2.878, 3.610},
-            {1.328, 1.729, 2.093, 2.539, 2.861, 3.579},
-            {1.325, 1.725, 2.086, 2.528, 2.845, 3.552},
-            {1.323, 1.721, 2.080, 2.518, 2.831, 3.527},
-            {1.321, 1.717, 2.074, 2.508, 2.819, 3.505},
-            {1.319, 1.714, 2.069, 2.500, 2.807, 3.485},
-            {1.318, 1.711, 2.064, 2.492, 2.797, 3.467},
-            {1.316, 1.708, 2.060, 2.485, 2.787, 3.450},
-            {1.315, 1.706, 2.056, 2.479, 2.779, 3.435},
-            {1.314, 1.703, 2.052, 2.473, 2.771, 3.421},
-            {1.313, 1.701, 2.048, 2.467, 2.763, 3.408},
-            {1.311, 1.699, 2.045, 2.462, 2.756, 3.396},
-            {1.310, 1.697, 2.042, 2.457, 2.750, 3.385},
-            {1.309, 1.696, 2.040, 2.453, 2.744, 3.375},
-            {1.309, 1.694, 2.037, 2.449, 2.738, 3.365},
-            {1.308, 1.692, 2.035, 2.445, 2.733, 3.356},
-            {1.307, 1.691, 2.032, 2.441, 2.728, 3.348},
-            {1.306, 1.690, 2.030, 2.438, 2.724, 3.340},
-            {1.306, 1.688, 2.028, 2.434, 2.719, 3.333},
-            {1.305, 1.687, 2.026, 2.431, 2.715, 3.326},
-            {1.304, 1.686, 2.024, 2.429, 2.712, 3.319},
-            {1.304, 1.685, 2.023, 2.426, 2.708, 3.313},
-            {1.303, 1.684, 2.021, 2.423, 2.704, 3.307},
-            {1.303, 1.683, 2.020, 2.421, 2.701, 3.301},
-            {1.302, 1.682, 2.018, 2.418, 2.698, 3.296},
-            {1.302, 1.681, 2.017, 2.416, 2.695, 3.291},
-            {1.301, 1.680, 2.015, 2.414, 2.692, 3.286},
-            {1.301, 1.679, 2.014, 2.412, 2.690, 3.281},
-            {1.300, 1.679, 2.013, 2.410, 2.687, 3.277},
-            {1.300, 1.678, 2.012, 2.408, 2.685, 3.273},
-            {1.299, 1.677, 2.011, 2.407, 2.682, 3.269},
-            {1.299, 1.677, 2.010, 2.405, 2.680, 3.265},
-            {1.299, 1.676, 2.009, 2.403, 2.678, 3.261},
-            {1.298, 1.675, 2.008, 2.402, 2.676, 3.258},
-            {1.298, 1.675, 2.007, 2.400, 2.674, 3.255},
-            {1.298, 1.674, 2.006, 2.399, 2.672, 3.251},
-            {1.297, 1.674, 2.005, 2.397, 2.670, 3.248},
-            {1.297, 1.673, 2.004, 2.396, 2.668, 3.245},
-            {1.297, 1.673, 2.003, 2.395, 2.667, 3.242},
-            {1.297, 1.672, 2.002, 2.394, 2.665, 3.239},
-            {1.296, 1.672, 2.002, 2.392, 2.663, 3.237},
-            {1.296, 1.671, 2.001, 2.391, 2.662, 3.234},
-            {1.296, 1.671, 2.000, 2.390, 2.660, 3.232},
-            {1.296, 1.670, 2.000, 2.389, 2.659, 3.229},
-            {1.295, 1.670, 1.999, 2.388, 2.657, 3.227},
-            {1.295, 1.669, 1.998, 2.387, 2.656, 3.225},
-            {1.295, 1.669, 1.998, 2.386, 2.655, 3.223},
-            {1.295, 1.669, 1.997, 2.385, 2.654, 3.220},
-            {1.295, 1.668, 1.997, 2.384, 2.652, 3.218},
-            {1.294, 1.668, 1.996, 2.383, 2.651, 3.216},
-            {1.294, 1.668, 1.995, 2.382, 2.650, 3.214},
-            {1.294, 1.667, 1.995, 2.382, 2.649, 3.213},
-            {1.294, 1.667, 1.994, 2.381, 2.648, 3.211},
-            {1.294, 1.667, 1.994, 2.380, 2.647, 3.209},
-            {1.293, 1.666, 1.993, 2.379, 2.646, 3.207},
-            {1.293, 1.666, 1.993, 2.379, 2.645, 3.206},
-            {1.293, 1.666, 1.993, 2.378, 2.644, 3.204},
-            {1.293, 1.665, 1.992, 2.377, 2.643, 3.202},
-            {1.293, 1.665, 1.992, 2.376, 2.642, 3.201},
-            {1.293, 1.665, 1.991, 2.376, 2.641, 3.199},
-            {1.292, 1.665, 1.991, 2.375, 2.640, 3.198},
-            {1.292, 1.664, 1.990, 2.374, 2.640, 3.197},
-            {1.292, 1.664, 1.990, 2.374, 2.639, 3.195},
-            {1.292, 1.664, 1.990, 2.373, 2.638, 3.194},
-            {1.292, 1.664, 1.989, 2.373, 2.637, 3.193},
-            {1.292, 1.663, 1.989, 2.372, 2.636, 3.191},
-            {1.292, 1.663, 1.989, 2.372, 2.636, 3.190},
-            {1.292, 1.663, 1.988, 2.371, 2.635, 3.189},
-            {1.291, 1.663, 1.988, 2.370, 2.634, 3.188},
-            {1.291, 1.663, 1.988, 2.370, 2.634, 3.187},
-            {1.291, 1.662, 1.987, 2.369, 2.633, 3.185},
-            {1.291, 1.662, 1.987, 2.369, 2.632, 3.184},
-            {1.291, 1.662, 1.987, 2.368, 2.632, 3.183},
-            {1.291, 1.662, 1.986, 2.368, 2.631, 3.182},
-            {1.291, 1.662, 1.986, 2.368, 2.630, 3.181},
-            {1.291, 1.661, 1.986, 2.367, 2.630, 3.180},
-            {1.291, 1.661, 1.986, 2.367, 2.629, 3.179},
-            {1.291, 1.661, 1.985, 2.366, 2.629, 3.178},
-            {1.290, 1.661, 1.985, 2.366, 2.628, 3.177},
-            {1.290, 1.661, 1.985, 2.365, 2.627, 3.176},
-            {1.290, 1.661, 1.984, 2.365, 2.627, 3.175},
-            {1.290, 1.660, 1.984, 2.365, 2.626, 3.175},
-            {1.290, 1.660, 1.984, 2.364, 2.626, 3.174},
-            {1.282, 1.645, 1.960, 2.326, 2.576, 3.090}
-    };
-
+    double getPercentile(double rank);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/util/internal/TreeMultiset.java	Mon Nov 04 11:28:41 2013 +0100
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.util.internal;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+
+public class TreeMultiset<T extends Comparable<T>> implements Multiset<T>, Serializable {
+
+    private final Map<T, Integer> map;
+    private int size;
+
+    public TreeMultiset() {
+        map = new TreeMap<T, Integer>();
+    }
+
+    @Override
+    public void add(T element) {
+        add(element, 1);
+    }
+
+    @Override
+    public void add(T element, int add) {
+        Integer count = map.get(element);
+        if (count == null) {
+            count = 0;
+        }
+        count += add;
+        size += add;
+        if (count != 0) {
+            map.put(element, count);
+        } else {
+            map.remove(element);
+        }
+    }
+
+    @Override
+    public int count(T element) {
+        Integer count = map.get(element);
+        return (count == null) ? 0 : count;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return map.isEmpty();
+    }
+
+    @Override
+    public int size() {
+        return size;
+    }
+
+    @Override
+    public Collection<T> keys() {
+        return Collections.unmodifiableCollection(map.keySet());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/test/java/org/openjdk/jmh/util/TestListStatistics.java	Mon Nov 04 11:28:41 2013 +0100
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.util;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openjdk.jmh.util.internal.ListStatistics;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests for Statistics
+ *
+ * @author staffan.friberg@oracle.com, anders.astrand@oracle.com
+ */
+public class TestListStatistics {
+
+    private static final double[] VALUES = {
+        60.89053178, 3.589312005, 42.73638635, 85.55397805, 96.66786311,
+        29.31809699, 63.50268147, 52.24157468, 64.68049085, 2.34517545,
+        92.62435741, 7.50775664, 31.92395987, 82.68609724, 71.07171954,
+        15.78967174, 34.43339987, 65.40063304, 69.86288638, 22.55130769,
+        36.99130073, 60.17648239, 33.1484382, 56.4605944, 93.67454206
+    };
+
+    private static final ListStatistics instance = new ListStatistics();
+
+    @BeforeClass
+    public static void setUpClass() throws Exception {
+        for (double value : VALUES) {
+            instance.addValue(value);
+        }
+    }
+
+    /**
+     * Test of add method, of class Statistics.
+     */
+    @Test
+    public strictfp void testAdd_double() {
+        ListStatistics stats = new ListStatistics();
+        stats.addValue(VALUES[0]);
+        assertEquals(1, stats.getN());
+        assertEquals(VALUES[0], stats.getSum(), 0.0);
+        assertEquals(VALUES[0], stats.getMax(), 0.0);
+        assertEquals(VALUES[0], stats.getMin(), 0.0);
+        assertEquals(VALUES[0], stats.getMean(), 0.0);
+        assertEquals(Double.NaN, stats.getVariance(), 0.0);
+        assertEquals(Double.NaN, stats.getStandardDeviation(), 0.0);
+    }
+
+    /**
+     * Test of getN method, of class Statistics.
+     */
+    @Test
+    public strictfp void testGetN() {
+        assertEquals((long) VALUES.length, (long) instance.getN());
+    }
+
+    /**
+     * Test of getSum method, of class Statistics.
+     */
+    @Test
+    public strictfp void testGetSum() {
+        assertEquals(1275.829, instance.getSum(), 0.001);
+    }
+
+    /**
+     * Test of getMean method, of class Statistics.
+     */
+    @Test
+    public strictfp void testGetMean() {
+        assertEquals(51.033, instance.getMean(), 0.001);
+    }
+
+    /**
+     * Test of getMax method, of class Statistics.
+     */
+    @Test
+    public strictfp void testGetMax() {
+        assertEquals(96.66786311, instance.getMax(), 0.0);
+    }
+
+    /**
+     * Test of getMin method, of class Statistics.
+     */
+    @Test
+    public strictfp void testGetMin() {
+        assertEquals(2.34517545, instance.getMin(), 0.0);
+    }
+
+    /**
+     * Test of getVariance method, of class Statistics.
+     */
+    @Test
+    public strictfp void testGetVariance() {
+        assertEquals(816.9807, instance.getVariance(), 0.0001);
+    }
+
+    /**
+     * Test of getStandardDeviation method, of class Statistics.
+     */
+    @Test
+    public strictfp void testGetStandardDeviation() {
+        assertEquals(28.5828, instance.getStandardDeviation(), 0.0001);
+    }
+
+    /**
+     * Test of getConfidenceInterval, of class Statistics
+     */
+    @Test
+    public strictfp void testGetConfidenceInterval() {
+        double[] interval = instance.getConfidenceInterval(0.05);
+        assertEquals(39.234, interval[0], 0.002);
+        assertEquals(62.831, interval[1], 0.002);
+    }
+
+    /**
+     * Test of toString, of class Statistics
+     */
+    @Test
+    public strictfp void testToString() {
+        String expResult = "N:25 Mean: 51.03316951740001 Min: 2.34517545 Max: 96.66786311 StdDev: 28.582874479178013";
+        String result = instance.toString();
+        assertEquals(expResult, result);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/test/java/org/openjdk/jmh/util/TestMultisetStatistics.java	Mon Nov 04 11:28:41 2013 +0100
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.util;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openjdk.jmh.util.internal.ListStatistics;
+import org.openjdk.jmh.util.internal.MultisetStatistics;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests for Statistics
+ *
+ * @author staffan.friberg@oracle.com, anders.astrand@oracle.com
+ */
+public class TestMultisetStatistics {
+
+    private static final double[] VALUES = {
+        60.89053178, 3.589312005, 42.73638635, 85.55397805, 96.66786311,
+        29.31809699, 63.50268147, 52.24157468, 64.68049085, 2.34517545,
+        92.62435741, 7.50775664, 31.92395987, 82.68609724, 71.07171954,
+        15.78967174, 34.43339987, 65.40063304, 69.86288638, 22.55130769,
+        36.99130073, 60.17648239, 33.1484382, 56.4605944, 93.67454206
+    };
+
+    private static final MultisetStatistics instance = new MultisetStatistics();
+
+    @BeforeClass
+    public static void setUpClass() throws Exception {
+        for (double value : VALUES) {
+            instance.addValue(value, 1);
+        }
+    }
+
+    /**
+     * Test of add method, of class Statistics.
+     */
+    @Test
+    public strictfp void testAdd_double() {
+        ListStatistics stats = new ListStatistics();
+        stats.addValue(VALUES[0]);
+        assertEquals(1, stats.getN());
+        assertEquals(VALUES[0], stats.getSum(), 0.0);
+        assertEquals(VALUES[0], stats.getMax(), 0.0);
+        assertEquals(VALUES[0], stats.getMin(), 0.0);
+        assertEquals(VALUES[0], stats.getMean(), 0.0);
+        assertEquals(Double.NaN, stats.getVariance(), 0.0);
+        assertEquals(Double.NaN, stats.getStandardDeviation(), 0.0);
+    }
+
+    /**
+     * Test of getN method, of class Statistics.
+     */
+    @Test
+    public strictfp void testGetN() {
+        assertEquals((long) VALUES.length, (long) instance.getN());
+    }
+
+    /**
+     * Test of getSum method, of class Statistics.
+     */
+    @Test
+    public strictfp void testGetSum() {
+        assertEquals(1275.829, instance.getSum(), 0.001);
+    }
+
+    /**
+     * Test of getMean method, of class Statistics.
+     */
+    @Test
+    public strictfp void testGetMean() {
+        assertEquals(51.033, instance.getMean(), 0.001);
+    }
+
+    /**
+     * Test of getMax method, of class Statistics.
+     */
+    @Test
+    public strictfp void testGetMax() {
+        assertEquals(96.66786311, instance.getMax(), 0.0);
+    }
+
+    /**
+     * Test of getMin method, of class Statistics.
+     */
+    @Test
+    public strictfp void testGetMin() {
+        assertEquals(2.34517545, instance.getMin(), 0.0);
+    }
+
+    /**
+     * Test of getVariance method, of class Statistics.
+     */
+    @Test
+    public strictfp void testGetVariance() {
+        assertEquals(816.9807, instance.getVariance(), 0.0001);
+    }
+
+    /**
+     * Test of getStandardDeviation method, of class Statistics.
+     */
+    @Test
+    public strictfp void testGetStandardDeviation() {
+        assertEquals(28.5828, instance.getStandardDeviation(), 0.0001);
+    }
+
+    /**
+     * Test of getConfidenceInterval, of class Statistics
+     */
+    @Test
+    public strictfp void testGetConfidenceInterval() {
+        double[] interval = instance.getConfidenceInterval(0.05);
+        assertEquals(39.234, interval[0], 0.002);
+        assertEquals(62.831, interval[1], 0.002);
+    }
+
+    /**
+     * Test of toString, of class Statistics
+     */
+    @Test
+    public strictfp void testToString() {
+        String expResult = "N:25 Mean: 51.033169517400005 Min: 2.34517545 Max: 96.66786311 StdDev: 28.582874479178017";
+        String result = instance.toString();
+        assertEquals(expResult, result);
+    }
+}
--- a/jmh-core/src/test/java/org/openjdk/jmh/util/TestStatistics.java	Sun Nov 03 13:29:40 2013 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,151 +0,0 @@
-/*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.openjdk.jmh.util;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.openjdk.jmh.util.internal.Statistics;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Tests for Statistics
- *
- * @author staffan.friberg@oracle.com, anders.astrand@oracle.com
- */
-public class TestStatistics {
-
-    private static final double[] VALUES = {
-        60.89053178, 3.589312005, 42.73638635, 85.55397805, 96.66786311,
-        29.31809699, 63.50268147, 52.24157468, 64.68049085, 2.34517545,
-        92.62435741, 7.50775664, 31.92395987, 82.68609724, 71.07171954,
-        15.78967174, 34.43339987, 65.40063304, 69.86288638, 22.55130769,
-        36.99130073, 60.17648239, 33.1484382, 56.4605944, 93.67454206
-    };
-
-    private static final Statistics instance = new Statistics();
-
-    public TestStatistics() {
-    }
-
-    @BeforeClass
-    public static void setUpClass() throws Exception {
-        for (double value : VALUES) {
-            instance.addValue(value);
-        }
-    }
-
-    /**
-     * Test of add method, of class Statistics.
-     */
-    @Test
-    public strictfp void testAdd_double() {
-        Statistics stats = new Statistics();
-        stats.addValue(VALUES[0]);
-        assertEquals(1, stats.getN());
-        assertEquals(VALUES[0], stats.getSum(), 0.0);
-        assertEquals(VALUES[0], stats.getMax(), 0.0);
-        assertEquals(VALUES[0], stats.getMin(), 0.0);
-        assertEquals(VALUES[0], stats.getMean(), 0.0);
-        assertEquals(Double.NaN, stats.getVariance(), 0.0);
-        assertEquals(Double.NaN, stats.getStandardDeviation(), 0.0);
-    }
-
-    /**
-     * Test of getN method, of class Statistics.
-     */
-    @Test
-    public strictfp void testGetN() {
-        assertEquals((long) VALUES.length, (long) instance.getN());
-    }
-
-    /**
-     * Test of getSum method, of class Statistics.
-     */
-    @Test
-    public strictfp void testGetSum() {
-        assertEquals(1275.829, instance.getSum(), 0.001);
-    }
-
-    /**
-     * Test of getMean method, of class Statistics.
-     */
-    @Test
-    public strictfp void testGetMean() {
-        assertEquals(51.033, instance.getMean(), 0.001);
-    }
-
-    /**
-     * Test of getMax method, of class Statistics.
-     */
-    @Test
-    public strictfp void testGetMax() {
-        assertEquals(96.66786311, instance.getMax(), 0.0);
-    }
-
-    /**
-     * Test of getMin method, of class Statistics.
-     */
-    @Test
-    public strictfp void testGetMin() {
-        assertEquals(2.34517545, instance.getMin(), 0.0);
-    }
-
-    /**
-     * Test of getVariance method, of class Statistics.
-     */
-    @Test
-    public strictfp void testGetVariance() {
-        assertEquals(816.9807, instance.getVariance(), 0.0001);
-    }
-
-    /**
-     * Test of getStandardDeviation method, of class Statistics.
-     */
-    @Test
-    public strictfp void testGetStandardDeviation() {
-        assertEquals(28.5828, instance.getStandardDeviation(), 0.0001);
-    }
-
-    /**
-     * Test of getConfidenceInterval, of class Statistics
-     */
-    @Test
-    public strictfp void testGetConfidenceInterval() {
-        double[] interval = instance.getConfidenceInterval(0.05);
-        assertEquals(39.234, interval[0], 0.002);
-        assertEquals(62.831, interval[1], 0.002);
-    }
-
-    /**
-     * Test of toString, of class Statistics
-     */
-    @Test
-    public strictfp void testToString() {
-        String expResult = "N:25 Mean: 51.03316951740001 Min: 2.34517545 Max: 96.66786311 StdDev: 28.582874479178013";
-        String result = instance.toString();
-        assertEquals(expResult, result);
-    }
-}