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