/* * Copyright (c) 2014, 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 test; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.GenerateMicroBenchmark; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import java.util.OptionalDouble; import java.util.concurrent.TimeUnit; import java.util.stream.DoubleStream; import java.util.stream.IntStream; @State(Scope.Thread) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MILLISECONDS) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Fork(1) public class AverageTest { static int N = Integer.getInteger("N", 10_000_000); double[] source; @Setup public void setup() { source = IntStream.range(0, N).mapToDouble(i -> 1.0).toArray(); } static double[] sumWithCompensation(double[] intermediateSum, double value) { double tmp = value - intermediateSum[1]; double sum = intermediateSum[0]; double velvel = sum + tmp; // Little wolf of rounding error intermediateSum[1] = (velvel - sum) - tmp; intermediateSum[0] = velvel; return intermediateSum; } static double computeFinalSum(double[] summands) { // Better error bounds to add both terms as the final sum double tmp = summands[0] + summands[1]; double simpleSum = summands[summands.length - 1]; if (Double.isNaN(tmp) && Double.isInfinite(simpleSum)) return simpleSum; else return tmp; } @GenerateMicroBenchmark public OptionalDouble for_seq() throws Throwable { double sum = 0.0; for (double e : source) { sum += e; } return OptionalDouble.of(sum / source.length); } @GenerateMicroBenchmark public OptionalDouble for_seq_sumc() throws Throwable { double[] sum = new double[4]; for (double e : source) { sumWithCompensation(sum, e); sum[2]++; sum[3] += e; } return OptionalDouble.of(computeFinalSum(sum) / sum[2]); } @GenerateMicroBenchmark public OptionalDouble for_seq_sumc_only() throws Throwable { double[] sum = new double[2]; for (double e : source) { sumWithCompensation(sum, e); } return OptionalDouble.of((sum[0] + sum[1]) / source.length); } @GenerateMicroBenchmark public OptionalDouble reduce_seq() throws Throwable { double a = DoubleStream.of(source) .reduce(0, Double::sum) / source.length; return OptionalDouble.of(a); } @GenerateMicroBenchmark public OptionalDouble reduce_par() throws Throwable { double a = DoubleStream.of(source).parallel() .reduce(0, Double::sum) / source.length; return OptionalDouble.of(a); } @GenerateMicroBenchmark public OptionalDouble average_seq() { return DoubleStream.of(source) .average(); } @GenerateMicroBenchmark public OptionalDouble average_par() { return DoubleStream.of(source).parallel() .average(); } }