1/* 2 * Copyright (C) 2015 Google Inc. 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 benchmarks.regression; 18 19import com.google.caliper.BeforeExperiment; 20import junit.framework.Assert; 21 22/** 23 * Benchmarks to measure the performance of String.equals for Strings of varying lengths. 24 * Each benchmarks makes 5 measurements, aiming at covering cases like strings of equal length 25 * that are not equal, identical strings with different references, strings with different endings, 26 * interned strings, and strings of different lengths. 27 */ 28public class StringEqualsBenchmark { 29 private final String long1 = "Ahead-of-time compilation is possible as the compiler may just" 30 + "convert an instruction thus: dex code: add-int v1000, v2000, v3000 C code: setIntRegter" 31 + "(1000, call_dex_add_int(getIntRegister(2000), getIntRegister(3000)) This means even lid" 32 + "instructions may have code generated, however, it is not expected that code generate in" 33 + "this way will perform well. The job of AOT verification is to tell the compiler that" 34 + "instructions are sound and provide tests to detect unsound sequences so slow path code" 35 + "may be generated. Other than for totally invalid code, the verification may fail at AOr" 36 + "run-time. At AOT time it can be because of incomplete information, at run-time it can e" 37 + "that code in a different apk that the application depends upon has changed. The Dalvik" 38 + "verifier would return a bool to state whether a Class were good or bad. In ART the fail" 39 + "case becomes either a soft or hard failure. Classes have new states to represent that a" 40 + "soft failure occurred at compile time and should be re-verified at run-time."; 41 42 private final String veryLong = "Garbage collection has two phases. The first distinguishes" 43 + "live objects from garbage objects. The second is reclaiming the rage of garbage object" 44 + "In the mark-sweep algorithm used by Dalvik, the first phase is achievd by computing the" 45 + "closure of all reachable objects in a process known as tracing from theoots. After the" 46 + "trace has completed, garbage objects are reclaimed. Each of these operations can be" 47 + "parallelized and can be interleaved with the operation of the applicationTraditionally," 48 + "the tracing phase dominates the time spent in garbage collection. The greatreduction i" 49 + "pause time can be achieved by interleaving as much of this phase as possible with the" 50 + "application. If we simply ran the GC in a separate thread with no other changes, normal" 51 + "operation of an application would confound the trace. Abstractly, the GC walks the h o" 52 + "all reachable objects. When the application is paused, the object graph cannot change." 53 + "The GC can therefore walk this structure and assume that all reachable objects live." 54 + "When the application is running, this graph may be altered. New nodes may be addnd edge" 55 + "may be changed. These changes may cause live objects to be hidden and falsely recla by" 56 + "the GC. To avoid this problem a write barrier is used to intercept and record modifion" 57 + "to objects in a separate structure. After performing its walk, the GC will revisit the" 58 + "updated objects and re-validate its assumptions. Without a card table, the garbage" 59 + "collector would have to visit all objects reached during the trace looking for dirtied" 60 + "objects. The cost of this operation would be proportional to the amount of live data." 61 + "With a card table, the cost of this operation is proportional to the amount of updateat" 62 + "The write barrier in Dalvik is a card marking write barrier. Card marking is the proce" 63 + "of noting the location of object connectivity changes on a sub-page granularity. A car" 64 + "is merely a colorful term for a contiguous extent of memory smaller than a page, common" 65 + "somewhere between 128- and 512-bytes. Card marking is implemented by instrumenting all" 66 + "locations in the virtual machine which can assign a pointer to an object. After themal" 67 + "pointer assignment has occurred, a byte is written to a byte-map spanning the heap whic" 68 + "corresponds to the location of the updated object. This byte map is known as a card ta" 69 + "The garbage collector visits this card table and looks for written bytes to reckon the" 70 + "location of updated objects. It then rescans all objects located on the dirty card," 71 + "correcting liveness assumptions that were invalidated by the application. While card" 72 + "marking imposes a small burden on the application outside of a garbage collection, the" 73 + "overhead of maintaining the card table is paid for by the reduced time spent inside" 74 + "garbage collection. With the concurrent garbage collection thread and a write barrier" 75 + "supported by the interpreter, JIT, and Runtime we modify garbage collection"; 76 77 private final String[][] shortStrings = new String[][] { 78 // Equal, constant comparison 79 { "a", "a" }, 80 // Different constants, first character different 81 { ":", " :"}, 82 // Different constants, last character different, same length 83 { "ja M", "ja N"}, 84 // Different constants, different lengths 85 {"$$$", "$$"}, 86 // Force execution of code beyond reference equality check 87 {"hi", new String("hi")} 88 }; 89 90 private final String[][] mediumStrings = new String[][] { 91 // Equal, constant comparison 92 { "Hello my name is ", "Hello my name is " }, 93 // Different constants, different lengths 94 { "What's your name?", "Whats your name?" }, 95 // Force execution of code beyond reference equality check 96 { "Android Runtime", new String("Android Runtime") }, 97 // Different constants, last character different, same length 98 { "v3ry Cre@tiVe?****", "v3ry Cre@tiVe?***." }, 99 // Different constants, first character different, same length 100 { "!@#$%^&*()_++*^$#@", "0@#$%^&*()_++*^$#@" } 101 }; 102 103 private final String[][] longStrings = new String[][] { 104 // Force execution of code beyond reference equality check 105 { long1, new String(long1) }, 106 // Different constants, last character different, same length 107 { long1 + "fun!", long1 + "----" }, 108 // Equal, constant comparison 109 { long1 + long1, long1 + long1 }, 110 // Different constants, different lengths 111 { long1 + "123456789", long1 + "12345678" }, 112 // Different constants, first character different, same length 113 { "Android Runtime" + long1, "android Runtime" + long1 } 114 }; 115 116 private final String[][] veryLongStrings = new String[][] { 117 // Force execution of code beyond reference equality check 118 { veryLong, new String(veryLong) }, 119 // Different constants, different lengths 120 { veryLong + veryLong, veryLong + " " + veryLong }, 121 // Equal, constant comparison 122 { veryLong + veryLong + veryLong, veryLong + veryLong + veryLong }, 123 // Different constants, last character different, same length 124 { veryLong + "77777", veryLong + "99999" }, 125 // Different constants, first character different 126 { "Android Runtime" + veryLong, "android Runtime" + veryLong } 127 }; 128 129 private final String[][] endStrings = new String[][] { 130 // Different constants, medium but different lengths 131 { "Hello", "Hello " }, 132 // Different constants, long but different lengths 133 { long1, long1 + "x"}, 134 // Different constants, very long but different lengths 135 { veryLong, veryLong + "?"}, 136 // Different constants, same medium lengths 137 { "How are you doing today?", "How are you doing today " }, 138 // Different constants, short but different lengths 139 { "1", "1." } 140 }; 141 142 private final String tmpStr1 = "012345678901234567890" 143 + "0123456789012345678901234567890123456789" 144 + "0123456789012345678901234567890123456789" 145 + "0123456789012345678901234567890123456789" 146 + "0123456789012345678901234567890123456789"; 147 148 private final String tmpStr2 = "z012345678901234567890" 149 + "0123456789012345678901234567890123456789" 150 + "0123456789012345678901234567890123456789" 151 + "0123456789012345678901234567890123456789" 152 + "012345678901234567890123456789012345678x"; 153 154 private final String[][] nonalignedStrings = new String[][] { 155 // Different non-word aligned medium length strings 156 { tmpStr1, tmpStr1.substring(1) }, 157 // Different differently non-word aligned medium length strings 158 { tmpStr2, tmpStr2.substring(2) }, 159 // Different non-word aligned long length strings 160 { long1, long1.substring(3) }, 161 // Different non-word aligned very long length strings 162 { veryLong, veryLong.substring(1) }, 163 // Equal non-word aligned constant strings 164 { "hello", "hello".substring(1) } 165 }; 166 167 private final Object[] objects = new Object[] { 168 // Compare to Double object 169 new Double(1.5), 170 // Compare to Integer object 171 new Integer(9999999), 172 // Compare to String array 173 new String[] {"h", "i"}, 174 // Compare to int array 175 new int[] {1, 2, 3}, 176 // Compare to Character object 177 new Character('a') 178 }; 179 180 // Check assumptions about how the compiler, new String(String), and String.intern() work. 181 // Any failures here would invalidate these benchmarks. 182 @BeforeExperiment 183 protected void setUp() throws Exception { 184 // String constants are the same object 185 Assert.assertSame("abc", "abc"); 186 // new String(String) makes a copy 187 Assert.assertNotSame("abc" , new String("abc")); 188 // Interned strings are treated like constants, so it is not necessary to 189 // separately benchmark interned strings. 190 Assert.assertSame("abc", "abc".intern()); 191 Assert.assertSame("abc", new String("abc").intern()); 192 // Compiler folds constant strings into new constants 193 Assert.assertSame(long1 + long1, long1 + long1); 194 } 195 196 // Benchmark cases of String.equals(null) 197 public void timeEqualsNull(int reps) { 198 for (int rep = 0; rep < reps; ++rep) { 199 for (int i = 0; i < mediumStrings.length; i++) { 200 mediumStrings[i][0].equals(null); 201 } 202 } 203 } 204 205 // Benchmark cases with very short (<5 character) Strings 206 public void timeEqualsShort(int reps) { 207 for (int rep = 0; rep < reps; ++rep) { 208 for (int i = 0; i < shortStrings.length; i++) { 209 shortStrings[i][0].equals(shortStrings[i][1]); 210 } 211 } 212 } 213 214 // Benchmark cases with medium length (10-15 character) Strings 215 public void timeEqualsMedium(int reps) { 216 for (int rep = 0; rep < reps; ++rep) { 217 for (int i = 0; i < mediumStrings.length; i++) { 218 mediumStrings[i][0].equals(mediumStrings[i][1]); 219 } 220 } 221 } 222 223 // Benchmark cases with long (>100 character) Strings 224 public void timeEqualsLong(int reps) { 225 for (int rep = 0; rep < reps; ++rep) { 226 for (int i = 0; i < longStrings.length; i++) { 227 longStrings[i][0].equals(longStrings[i][1]); 228 } 229 } 230 } 231 232 // Benchmark cases with very long (>1000 character) Strings 233 public void timeEqualsVeryLong(int reps) { 234 for (int rep = 0; rep < reps; ++rep) { 235 for (int i = 0; i < veryLongStrings.length; i++) { 236 veryLongStrings[i][0].equals(veryLongStrings[i][1]); 237 } 238 } 239 } 240 241 // Benchmark cases with non-word aligned Strings 242 public void timeEqualsNonWordAligned(int reps) { 243 for (int rep = 0; rep < reps; ++rep) { 244 for (int i = 0; i < nonalignedStrings.length; i++) { 245 nonalignedStrings[i][0].equals(nonalignedStrings[i][1]); 246 } 247 } 248 } 249 250 // Benchmark cases with slight differences in the endings 251 public void timeEqualsEnd(int reps) { 252 for (int rep = 0; rep < reps; ++rep) { 253 for (int i = 0; i < endStrings.length; i++) { 254 endStrings[i][0].equals(endStrings[i][1]); 255 } 256 } 257 } 258 259 // Benchmark cases of comparing a string to a non-string object 260 public void timeEqualsNonString(int reps) { 261 for (int rep = 0; rep < reps; ++rep) { 262 for (int i = 0; i < mediumStrings.length; i++) { 263 mediumStrings[i][0].equals(objects[i]); 264 } 265 } 266 } 267} 268