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 17package com.google.common.util.concurrent; 18 19import static com.google.common.collect.Iterables.cycle; 20import static com.google.common.collect.Iterables.limit; 21 22import com.google.caliper.BeforeExperiment; 23import com.google.caliper.Benchmark; 24import com.google.caliper.Param; 25import com.google.caliper.api.Footprint; 26import com.google.caliper.api.VmOptions; 27import com.google.common.base.Supplier; 28import com.google.common.collect.ImmutableList; 29import com.google.common.primitives.Ints; 30 31import java.util.ArrayList; 32import java.util.Collections; 33import java.util.List; 34import java.util.Random; 35import java.util.concurrent.locks.Lock; 36import java.util.concurrent.locks.ReentrantLock; 37 38/** 39 * A benchmark comparing the various striped implementations. 40 */ 41@VmOptions({"-Xms12g", "-Xmx12g", "-d64"}) 42public class StripedBenchmark { 43 private static final Supplier<Lock> LOCK_SUPPLIER = new Supplier<Lock>() { 44 @Override public Lock get() { 45 return new ReentrantLock(); 46 } 47 }; 48 49 @Param({"2", "8", "64", "1024", "65536"}) int numStripes; 50 @Param Impl impl; 51 52 enum Impl { 53 EAGER { 54 @Override Striped<Lock> get(int stripes) { 55 return Striped.lock(stripes); 56 } 57 }, 58 LAZY_SMALL { 59 @Override Striped<Lock> get(int stripes) { 60 return new Striped.SmallLazyStriped<Lock>(stripes, LOCK_SUPPLIER); 61 } 62 }, 63 LAZY_LARGE { 64 @Override Striped<Lock> get(int stripes) { 65 return new Striped.LargeLazyStriped<Lock>(stripes, LOCK_SUPPLIER); 66 } 67 }; 68 69 abstract Striped<Lock> get(int stripes); 70 } 71 72 private Striped<Lock> striped; 73 private int[] stripes; 74 private List<Integer> bulkGetSet; 75 76 @BeforeExperiment void setUp() { 77 this.striped = impl.get(numStripes); 78 stripes = new int[numStripes]; 79 for (int i = 0; i < numStripes; i++) { 80 stripes[i] = i; 81 } 82 List<Integer> asList = Ints.asList(stripes); 83 Collections.shuffle(asList, new Random(0xdeadbeef)); 84 85 // do bulk gets with exactly 10 keys (possibly <10 stripes) (or less if numStripes is smaller) 86 bulkGetSet = ImmutableList.copyOf(limit(cycle(asList), 10)); 87 } 88 89 @Footprint Object sizeOfStriped() { 90 return impl.get(numStripes); 91 } 92 93 // a place to put the locks in sizeOfPopulatedStriped so they don't get GC'd before we measure 94 final List<Lock> locks = new ArrayList<Lock>(numStripes); 95 96 @Footprint Object sizeOfPopulatedStriped() { 97 locks.clear(); 98 Striped<Lock> striped = impl.get(numStripes); 99 for (int i : stripes) { 100 locks.add(striped.getAt(i)); 101 } 102 return striped; 103 } 104 105 @Benchmark long timeConstruct(long reps) { 106 long rvalue = 0; 107 int numStripesLocal = numStripes; 108 Impl implLocal = impl; 109 for (long i = 0; i < reps; i++) { 110 rvalue += implLocal.get(numStripesLocal).hashCode(); 111 } 112 return rvalue; 113 } 114 115 @Benchmark long timeGetAt(long reps) { 116 long rvalue = 0; 117 int[] stripesLocal = stripes; 118 int mask = numStripes - 1; 119 Striped<Lock> stripedLocal = striped; 120 for (long i = 0; i < reps; i++) { 121 rvalue += stripedLocal.getAt(stripesLocal[(int) (i & mask)]).hashCode(); 122 } 123 return rvalue; 124 } 125 126 @Benchmark long timeBulkGet(long reps) { 127 long rvalue = 0; 128 List<Integer> bulkGetSetLocal = bulkGetSet; 129 Striped<Lock> stripedLocal = striped; 130 for (long i = 0; i < reps; i++) { 131 rvalue += stripedLocal.bulkGet(bulkGetSetLocal).hashCode(); 132 } 133 return rvalue; 134 } 135} 136