1 /* 2 * Copyright (C) 2014 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.util.concurrent; 18 19 import static com.google.common.collect.Iterables.cycle; 20 import static com.google.common.collect.Iterables.limit; 21 22 import com.google.caliper.BeforeExperiment; 23 import com.google.caliper.Benchmark; 24 import com.google.caliper.Param; 25 import com.google.caliper.api.Footprint; 26 import com.google.caliper.api.VmOptions; 27 import com.google.common.base.Supplier; 28 import com.google.common.collect.ImmutableList; 29 import com.google.common.primitives.Ints; 30 import java.util.ArrayList; 31 import java.util.Collections; 32 import java.util.List; 33 import java.util.Random; 34 import java.util.concurrent.locks.Lock; 35 import java.util.concurrent.locks.ReentrantLock; 36 37 /** A benchmark comparing the various striped implementations. */ 38 @VmOptions({"-Xms12g", "-Xmx12g", "-d64"}) 39 public class StripedBenchmark { 40 private static final Supplier<Lock> LOCK_SUPPLIER = 41 new Supplier<Lock>() { 42 @Override 43 public Lock get() { 44 return new ReentrantLock(); 45 } 46 }; 47 48 @Param({"2", "8", "64", "1024", "65536"}) 49 int numStripes; 50 51 @Param Impl impl; 52 53 enum Impl { 54 EAGER { 55 @Override get(int stripes)56 Striped<Lock> get(int stripes) { 57 return Striped.lock(stripes); 58 } 59 }, 60 LAZY_SMALL { 61 @Override get(int stripes)62 Striped<Lock> get(int stripes) { 63 return new Striped.SmallLazyStriped<>(stripes, LOCK_SUPPLIER); 64 } 65 }, 66 LAZY_LARGE { 67 @Override get(int stripes)68 Striped<Lock> get(int stripes) { 69 return new Striped.LargeLazyStriped<>(stripes, LOCK_SUPPLIER); 70 } 71 }; 72 get(int stripes)73 abstract Striped<Lock> get(int stripes); 74 } 75 76 private Striped<Lock> striped; 77 private int[] stripes; 78 private List<Integer> bulkGetSet; 79 80 @BeforeExperiment setUp()81 void setUp() { 82 this.striped = impl.get(numStripes); 83 stripes = new int[numStripes]; 84 for (int i = 0; i < numStripes; i++) { 85 stripes[i] = i; 86 } 87 List<Integer> asList = Ints.asList(stripes); 88 Collections.shuffle(asList, new Random(0xdeadbeef)); 89 90 // do bulk gets with exactly 10 keys (possibly <10 stripes) (or less if numStripes is smaller) 91 bulkGetSet = ImmutableList.copyOf(limit(cycle(asList), 10)); 92 } 93 94 @Footprint sizeOfStriped()95 Object sizeOfStriped() { 96 return impl.get(numStripes); 97 } 98 99 // a place to put the locks in sizeOfPopulatedStriped so they don't get GC'd before we measure 100 final List<Lock> locks = new ArrayList<>(numStripes); 101 102 @Footprint sizeOfPopulatedStriped()103 Object sizeOfPopulatedStriped() { 104 locks.clear(); 105 Striped<Lock> striped = impl.get(numStripes); 106 for (int i : stripes) { 107 locks.add(striped.getAt(i)); 108 } 109 return striped; 110 } 111 112 @Benchmark timeConstruct(long reps)113 long timeConstruct(long reps) { 114 long rvalue = 0; 115 int numStripesLocal = numStripes; 116 Impl implLocal = impl; 117 for (long i = 0; i < reps; i++) { 118 rvalue += implLocal.get(numStripesLocal).hashCode(); 119 } 120 return rvalue; 121 } 122 123 @Benchmark timeGetAt(long reps)124 long timeGetAt(long reps) { 125 long rvalue = 0; 126 int[] stripesLocal = stripes; 127 int mask = numStripes - 1; 128 Striped<Lock> stripedLocal = striped; 129 for (long i = 0; i < reps; i++) { 130 rvalue += stripedLocal.getAt(stripesLocal[(int) (i & mask)]).hashCode(); 131 } 132 return rvalue; 133 } 134 135 @Benchmark timeBulkGet(long reps)136 long timeBulkGet(long reps) { 137 long rvalue = 0; 138 List<Integer> bulkGetSetLocal = bulkGetSet; 139 Striped<Lock> stripedLocal = striped; 140 for (long i = 0; i < reps; i++) { 141 rvalue += stripedLocal.bulkGet(bulkGetSetLocal).hashCode(); 142 } 143 return rvalue; 144 } 145 } 146