• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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