1 /*
2  * Copyright (C) 2011 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.primitives;
18 
19 import com.google.caliper.BeforeExperiment;
20 import com.google.caliper.Benchmark;
21 
22 import java.util.Random;
23 
24 /**
25  * Benchmarks for certain methods of {@code UnsignedLongs}.
26  *
27  * @author Eamonn McManus
28  */
29 public class UnsignedLongsBenchmark {
30   private static final int ARRAY_SIZE = 0x10000;
31   private static final int ARRAY_MASK = 0x0ffff;
32   private static final Random RANDOM_SOURCE = new Random(314159265358979L);
33   private static final long[] longs = new long[ARRAY_SIZE];
34   private static final long[] divisors = new long[ARRAY_SIZE];
35   private static final String[] decimalStrings = new String[ARRAY_SIZE];
36   private static final String[] binaryStrings = new String[ARRAY_SIZE];
37   private static final String[] hexStrings = new String[ARRAY_SIZE];
38   private static final String[] prefixedHexStrings = new String[ARRAY_SIZE];
39 
40   @BeforeExperiment
setUp()41   void setUp() {
42     for (int i = 0; i < ARRAY_SIZE; i++) {
43       longs[i] = random();
44       divisors[i] = randomDivisor(longs[i]);
45       decimalStrings[i] = UnsignedLongs.toString(longs[i]);
46       binaryStrings[i] = UnsignedLongs.toString(longs[i], 2);
47       hexStrings[i] = UnsignedLongs.toString(longs[i], 16);
48       prefixedHexStrings[i] = "0x" + hexStrings[i];
49     }
50   }
51 
divide(int reps)52   @Benchmark long divide(int reps) {
53     long tmp = 0;
54     for (int i = 0; i < reps; i++) {
55       int j = i & ARRAY_MASK;
56       tmp += UnsignedLongs.divide(longs[j], divisors[j]);
57     }
58     return tmp;
59   }
60 
remainder(int reps)61   @Benchmark long remainder(int reps) {
62     long tmp = 0;
63     for (int i = 0; i < reps; i++) {
64       int j = i & ARRAY_MASK;
65       tmp += UnsignedLongs.remainder(longs[j], divisors[j]);
66     }
67     return tmp;
68   }
69 
parseUnsignedLong(int reps)70   @Benchmark long parseUnsignedLong(int reps) {
71     long tmp = 0;
72     // Given that we make three calls per pass, we scale reps down in order
73     // to do a comparable amount of work to other measurements.
74     int scaledReps = reps / 3 + 1;
75     for (int i = 0; i < scaledReps; i++) {
76       int j = i & ARRAY_MASK;
77       tmp += UnsignedLongs.parseUnsignedLong(decimalStrings[j]);
78       tmp += UnsignedLongs.parseUnsignedLong(hexStrings[j], 16);
79       tmp += UnsignedLongs.parseUnsignedLong(binaryStrings[j], 2);
80     }
81     return tmp;
82   }
83 
parseDecode10(int reps)84   @Benchmark long parseDecode10(int reps) {
85     long tmp = 0;
86     for (int i = 0; i < reps; i++) {
87       int j = i & ARRAY_MASK;
88       tmp += UnsignedLongs.decode(decimalStrings[j]);
89     }
90     return tmp;
91   }
92 
parseDecode16(int reps)93   @Benchmark long parseDecode16(int reps) {
94     long tmp = 0;
95     for (int i = 0; i < reps; i++) {
96       int j = i & ARRAY_MASK;
97       tmp += UnsignedLongs.decode(prefixedHexStrings[j]);
98     }
99     return tmp;
100   }
101 
toString(int reps)102   @Benchmark int toString(int reps) {
103     int tmp = 0;
104     // Given that we make three calls per pass, we scale reps down in order
105     // to do a comparable amount of work to other measurements.
106     int scaledReps = reps / 3 + 1;
107     for (int i = 0; i < scaledReps; i++) {
108       int j = i & ARRAY_MASK;
109       long x = longs[j];
110       tmp += UnsignedLongs.toString(x).length();
111       tmp += UnsignedLongs.toString(x, 16).length();
112       tmp += UnsignedLongs.toString(x, 2).length();
113     }
114     return tmp;
115   }
116 
random()117   private static long random() {
118     return RANDOM_SOURCE.nextLong();
119   }
120 
121   // A random value that cannot be 0 and that is unsigned-less-than or equal
122   // to the given dividend, so that we don't have half of our divisions being
123   // trivial because the divisor is bigger than the dividend.
124   // Using remainder here does not give us a uniform distribution but it should
125   // not have a big impact on the measurement.
randomDivisor(long dividend)126   private static long randomDivisor(long dividend) {
127     long r = RANDOM_SOURCE.nextLong();
128     if (dividend == -1) {
129       return r;
130     } else {
131       return UnsignedLongs.remainder(r, dividend + 1);
132     }
133   }
134 }
135