1 /*
2  * Copyright (C) 2010 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.base;
18 
19 import com.google.caliper.BeforeExperiment;
20 import com.google.caliper.Benchmark;
21 import com.google.caliper.Param;
22 import com.google.common.base.Ascii;
23 import com.google.common.collect.Lists;
24 import com.google.common.primitives.Chars;
25 
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Locale;
29 import java.util.Random;
30 
31 /**
32  * Benchmarks for the ASCII class.
33  *
34  * @author Kevin Bourrillion
35  */
36 public class AsciiBenchmark {
37   private static String ALPHA =
38       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
39   private static String NONALPHA =
40       "0123456789`~-_=+[]{}|;:',.<>/?!@#$%^&*()\"\\";
41 
42   @Param({"20", "2000"}) int size;
43   @Param({"2", "20"}) int nonAlphaRatio; // one non-alpha char per this many chars
44   @Param boolean noWorkToDo;
45 
46   Random random;
47   String testString;
48 
setUp()49   @BeforeExperiment void setUp() {
50     random = new Random();
51 
52     int nonAlpha = size / nonAlphaRatio;
53     int alpha = size - nonAlpha;
54 
55     List<Character> chars = Lists.newArrayListWithCapacity(size);
56     for (int i = 0; i < alpha; i++) {
57       chars.add(randomAlpha());
58     }
59     for (int i = 0; i < nonAlpha; i++) {
60       chars.add(randomNonAlpha());
61     }
62     Collections.shuffle(chars, random);
63     char[] array = Chars.toArray(chars);
64     this.testString = new String(array);
65   }
66 
randomAlpha()67   private char randomAlpha() {
68     return ALPHA.charAt(random.nextInt(ALPHA.length()));
69   }
70 
randomNonAlpha()71   private char randomNonAlpha() {
72     return NONALPHA.charAt(random.nextInt(NONALPHA.length()));
73   }
74 
asciiStringToUpperCase(int reps)75   @Benchmark int asciiStringToUpperCase(int reps) {
76     String string = noWorkToDo
77         ? Ascii.toUpperCase(testString)
78         : testString;
79 
80     int dummy = 0;
81     for (int i = 0; i < reps; i++) {
82       dummy += Ascii.toUpperCase(string).length();
83     }
84     return dummy;
85   }
86 
asciiCharSequenceToUpperCase(int reps)87   @Benchmark int asciiCharSequenceToUpperCase(int reps) {
88     String string = noWorkToDo
89         ? charSequenceToUpperCase(testString)
90         : testString;
91 
92     int dummy = 0;
93     for (int i = 0; i < reps; i++) {
94       dummy += charSequenceToUpperCase(string).length();
95     }
96     return dummy;
97   }
98 
stringToUpperCase(int reps)99   @Benchmark int stringToUpperCase(int reps) {
100     String string = noWorkToDo
101         ? testString.toUpperCase(Locale.US)
102         : testString;
103 
104     int dummy = 0;
105     for (int i = 0; i < reps; i++) {
106       dummy += string.toUpperCase(Locale.US).length();
107     }
108     return dummy;
109   }
110 
equalsIgnoreCaseCharSequence(int reps)111   @Benchmark boolean equalsIgnoreCaseCharSequence(int reps) {
112     // This benchmark has no concept of "noWorkToDo".
113     String upperString = testString.toUpperCase();
114     CharSequence testSeq = new StringBuilder(testString);
115     CharSequence upperSeq = new StringBuilder(upperString);
116     CharSequence[] lhs = new CharSequence[] { testString, testSeq, testString, testSeq };
117     CharSequence[] rhs = new CharSequence[] { upperString, upperString, upperSeq, upperSeq };
118 
119     boolean dummy = false;
120     for (int i = 0; i < reps; i++) {
121       dummy ^= Ascii.equalsIgnoreCase(lhs[i & 0x3], rhs[i & 0x3]);
122     }
123     return dummy;
124   }
125 
equalsIgnoreCaseStringOnly(int reps)126   @Benchmark boolean equalsIgnoreCaseStringOnly(int reps) {
127     // This benchmark has no concept of "noWorkToDo".
128     String lhs = testString;
129     String rhs = testString.toUpperCase();
130 
131     boolean dummy = false;
132     for (int i = 0; i < reps; i++) {
133       dummy ^= Ascii.equalsIgnoreCase(lhs, rhs);
134     }
135     return dummy;
136   }
137 
equalsIgnoreCaseJDK(int reps)138   @Benchmark boolean equalsIgnoreCaseJDK(int reps) {
139     // This benchmark has no concept of "noWorkToDo".
140     String lhs = testString;
141     String rhs = testString.toUpperCase();
142 
143     boolean dummy = false;
144     for (int i = 0; i < reps; i++) {
145         dummy ^= lhs.equalsIgnoreCase(rhs);
146     }
147     return dummy;
148   }
149 
isUpperCase(int reps)150   @Benchmark boolean isUpperCase(int reps) {
151     // This benchmark has no concept of "noWorkToDo".
152     char[] chars = testString.toCharArray();
153 
154     boolean dummy = false;
155     for (int i = 0; i < reps; i++) {
156       for (int n = 0; n < chars.length; n++) {
157         dummy ^= Ascii.isUpperCase(chars[n]);
158       }
159     }
160     return dummy;
161   }
162 
charSequenceToUpperCase(CharSequence chars)163   static String charSequenceToUpperCase(CharSequence chars) {
164     int length = chars.length();
165     StringBuilder builder = new StringBuilder(length);
166     for (int i = 0; i < length; i++) {
167       builder.append(Ascii.toUpperCase(chars.charAt(i)));
168     }
169     return builder.toString();
170   }
171 }
172