1 /*
   2  * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package org.openjdk.bench.java.util.stream.pipeline;
  26 
  27 import org.openjdk.jmh.annotations.Benchmark;
  28 import org.openjdk.jmh.annotations.BenchmarkMode;
  29 import org.openjdk.jmh.annotations.Mode;
  30 import org.openjdk.jmh.annotations.OutputTimeUnit;
  31 import org.openjdk.jmh.annotations.Param;
  32 import org.openjdk.jmh.annotations.Scope;
  33 import org.openjdk.jmh.annotations.Setup;
  34 import org.openjdk.jmh.annotations.State;
  35 
  36 import java.util.Iterator;
  37 import java.util.concurrent.TimeUnit;
  38 import java.util.concurrent.atomic.LongAdder;
  39 import java.util.function.LongConsumer;
  40 import java.util.stream.LongStream;
  41 
  42 /**
  43  * Benchmark for forEach()/iterator()/into() operations;
  44  * Testing which one is faster for semantically-equvalent operations.
  45  */
  46 @BenchmarkMode(Mode.Throughput)
  47 @OutputTimeUnit(TimeUnit.SECONDS)
  48 @State(Scope.Thread)
  49 public class Terminal {
  50 
  51     /**
  52      * Implementation notes:
  53      *   - parallel version requires thread-safe sink, we use the same for sequential version for better comparison
  54      *   - operations are explicit inner classes to untangle unwanted lambda effects
  55      */
  56 
  57     @Param("100000")
  58     private int size;
  59 
  60     private LongAdder sink;
  61     private LongConsumer block;
  62 
  63     @Setup
  64     public void setup() {
  65         sink = new LongAdder();
  66         block = new LongConsumer() {
  67             @Override
  68             public void accept(long v) {
  69                 sink.add(v);
  70             }
  71         };
  72     }
  73 
  74     @Benchmark
  75     public long baseline_prim_acc() {
  76         long s = 0;
  77         for (long l = 0L; l < size; l++) {
  78             s += l;
  79         }
  80         sink.add(s);
  81         return sink.sum();
  82     }
  83 
  84     @Benchmark
  85     public long baseline_prim_sink() {
  86         for (long l = 0L; l < size; l++) {
  87             sink.add(l);
  88         }
  89         return sink.sum();
  90     }
  91 
  92     @Benchmark
  93     public long baseline_iterator_acc() {
  94         long s = 0;
  95         for (Iterator<Long> iterator = LongStream.range(0, size).boxed().iterator(); iterator.hasNext(); ) {
  96             Long l = iterator.next();
  97             s += l;
  98         }
  99         sink.add(s);
 100         return sink.sum();
 101     }
 102 
 103     @Benchmark
 104     public long baseline_iterator_sink() {
 105         for (Iterator<Long> iterator = LongStream.range(0, size).boxed().iterator(); iterator.hasNext(); ) {
 106             sink.add(iterator.next());
 107         }
 108         return sink.sum();
 109     }
 110 
 111     @Benchmark
 112     public long seq_iterator() {
 113         Iterator<Long> i = LongStream.range(0, size).boxed().iterator();
 114         while (i.hasNext()) {
 115             sink.add(i.next());
 116         }
 117         return sink.sum();
 118     }
 119 
 120     @Benchmark
 121     public long par_iterator() {
 122         Iterator<Long> i = LongStream.range(0, size).parallel().boxed().iterator();
 123         while (i.hasNext()) {
 124             sink.add(i.next());
 125         }
 126         return sink.sum();
 127     }
 128 
 129     @Benchmark
 130     public long seq_forEach() {
 131         LongStream.range(1, size).forEach(block);
 132         return sink.sum();
 133     }
 134 
 135     @Benchmark
 136     public long par_forEach() {
 137         LongStream.range(1, size).parallel().forEach(block);
 138         return sink.sum();
 139     }
 140 
 141     @Benchmark
 142     public long seq_into() {
 143         return LongStream.range(1, size)
 144                 .collect(LongAdder::new, LongAdder::add, (la1, la2) -> la1.add(la2.sum())).sum();
 145     }
 146 
 147     @Benchmark
 148     public long par_into() {
 149         return LongStream.range(1, size).parallel()
 150                 .collect(LongAdder::new, LongAdder::add, (la1, la2) -> la1.add(la2.sum())).sum();
 151     }
 152 
 153 }