Home | History | Annotate | Download | only in regression
      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 
     17 package benchmarks.regression;
     18 
     19 import com.google.caliper.BeforeExperiment;
     20 import 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  */
     28 public 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