1 /*
   2  * Copyright (c) 2020, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.openjdk.bench.java.util;
  24 
  25 import org.openjdk.jmh.annotations.Benchmark;
  26 import org.openjdk.jmh.annotations.BenchmarkMode;
  27 import org.openjdk.jmh.annotations.Fork;
  28 import org.openjdk.jmh.annotations.Measurement;
  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 import org.openjdk.jmh.annotations.Warmup;
  36 import org.openjdk.jmh.infra.Blackhole;
  37 
  38 import java.util.Arrays;
  39 import java.util.Collections;
  40 import java.util.Comparator;
  41 import java.util.Map;
  42 import java.util.Random;
  43 import java.util.TreeMap;
  44 import java.util.concurrent.TimeUnit;
  45 import java.util.function.Function;
  46 import java.util.function.Supplier;
  47 import java.util.stream.Collectors;
  48 import java.util.stream.IntStream;
  49 
  50 @BenchmarkMode(Mode.AverageTime)
  51 @OutputTimeUnit(TimeUnit.NANOSECONDS)
  52 @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
  53 @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
  54 @Fork(3)
  55 @State(Scope.Thread)
  56 public class TreeMapUpdate {
  57     @Param({"10", "1000", "100000"})
  58     public int size;
  59 
  60     @Param({"true", "false"})
  61     public boolean comparator;
  62     
  63     @Param({"true", "false"})
  64     public boolean preFill;
  65     
  66     @Param({"0"})
  67     public long seed;
  68 
  69     private Supplier<TreeMap<Integer, Integer>> supplier;
  70     
  71     private Integer[] keys;
  72 
  73     @Setup
  74     public void setUp() {
  75         supplier = comparator ? () -> new TreeMap<>(Comparator.reverseOrder()) : TreeMap::new;
  76         keys = IntStream.range(0, size).boxed().toArray(Integer[]::new);
  77         Random rnd = seed == 0 ? new Random() : new Random(seed);
  78         Collections.shuffle(Arrays.asList(keys, rnd));
  79         if (preFill) {
  80             TreeMap<Integer, Integer> template = Arrays.stream(keys)
  81                 .collect(Collectors.toMap(Function.identity(), Function.identity(), (a, b) -> a, supplier));
  82             supplier = () -> new TreeMap<>(template);
  83         }
  84     }
  85 
  86     @Benchmark
  87     public Map<Integer, Integer> baseline() {
  88         // Just create map (empty or pre-filled)
  89         return supplier.get();
  90     }
  91 
  92     @Benchmark
  93     public Map<Integer, Integer> put(Blackhole bh) {
  94         Map<Integer, Integer> map = supplier.get();
  95         Integer[] keys = this.keys;
  96         for (Integer key : keys) {
  97             bh.consume(map.put(key, key));
  98         }
  99         return map;
 100     }
 101 
 102     @Benchmark
 103     public Map<Integer, Integer> putIfAbsent(Blackhole bh) {
 104         Map<Integer, Integer> map = supplier.get();
 105         Integer[] keys = this.keys;
 106         for (Integer key : keys) {
 107             bh.consume(map.putIfAbsent(key, key));
 108         }
 109         return map;
 110     }
 111 
 112     @Benchmark
 113     public Map<Integer, Integer> computeIfAbsent(Blackhole bh) {
 114         Map<Integer, Integer> map = supplier.get();
 115         Integer[] keys = this.keys;
 116         for (Integer key : keys) {
 117             bh.consume(map.computeIfAbsent(key, k -> k));
 118         }
 119         return map;
 120     }
 121 
 122     @Benchmark
 123     public Map<Integer, Integer> compute(Blackhole bh) {
 124         Map<Integer, Integer> map = supplier.get();
 125         Integer[] keys = this.keys;
 126         for (Integer key : keys) {
 127             bh.consume(map.compute(key, (k, old) -> k));
 128         }
 129         return map;
 130     }
 131 
 132     @Benchmark
 133     public Map<Integer, Integer> computeIfPresent(Blackhole bh) {
 134         Map<Integer, Integer> map = supplier.get();
 135         Integer[] keys = this.keys;
 136         for (Integer key : keys) {
 137             bh.consume(map.computeIfPresent(key, (k, old) -> k));
 138         }
 139         return map;
 140     }
 141 
 142     @Benchmark
 143     public Map<Integer, Integer> merge(Blackhole bh) {
 144         Map<Integer, Integer> map = supplier.get();
 145         Integer[] keys = this.keys;
 146         for (Integer key : keys) {
 147             bh.consume(map.merge(key, key, (k1, k2) -> k1));
 148         }
 149         return map;
 150     }
 151 }