Home | History | Annotate | Download | only in regression
      1 /*
      2  * Copyright (C) 2011 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 com.google.caliper.Param;
     21 import java.io.IOException;
     22 import java.io.InputStream;
     23 import java.io.InputStreamReader;
     24 import java.io.Reader;
     25 import java.io.StringReader;
     26 import java.io.StringWriter;
     27 import javax.xml.parsers.DocumentBuilderFactory;
     28 import javax.xml.parsers.SAXParserFactory;
     29 import org.json.JSONArray;
     30 import org.json.JSONObject;
     31 import org.xml.sax.InputSource;
     32 import org.xml.sax.helpers.DefaultHandler;
     33 import org.xmlpull.v1.XmlPullParser;
     34 
     35 /**
     36  * Measure throughput of various parsers.
     37  *
     38  * <p>This benchmark requires that ParseBenchmarkData.zip is on the classpath.
     39  * That file contains Twitter feed data, which is representative of what
     40  * applications will be parsing.
     41  */
     42 public final class ParseBenchmark {
     43 
     44     @Param Document document;
     45     @Param Api api;
     46 
     47     private enum Document {
     48         TWEETS,
     49         READER_SHORT,
     50         READER_LONG
     51     }
     52 
     53     private enum Api {
     54         ANDROID_STREAM("json") {
     55             @Override Parser newParser() {
     56                 return new AndroidStreamParser();
     57             }
     58         },
     59         ORG_JSON("json") {
     60             @Override Parser newParser() {
     61                 return new OrgJsonParser();
     62             }
     63         },
     64         XML_PULL("xml") {
     65             @Override Parser newParser() {
     66                 return new GeneralXmlPullParser();
     67             }
     68         },
     69         XML_DOM("xml") {
     70             @Override Parser newParser() {
     71                 return new XmlDomParser();
     72             }
     73         },
     74         XML_SAX("xml") {
     75             @Override Parser newParser() {
     76                 return new XmlSaxParser();
     77             }
     78         };
     79 
     80         final String extension;
     81 
     82         private Api(String extension) {
     83             this.extension = extension;
     84         }
     85 
     86         abstract Parser newParser();
     87     }
     88 
     89     private String text;
     90     private Parser parser;
     91 
     92     @BeforeExperiment
     93     protected void setUp() throws Exception {
     94         text = resourceToString("/" + document.name() + "." + api.extension);
     95         parser = api.newParser();
     96     }
     97 
     98     public void timeParse(int reps) throws Exception {
     99         for (int i = 0; i < reps; i++) {
    100             parser.parse(text);
    101         }
    102     }
    103 
    104     private static String resourceToString(String path) throws Exception {
    105         InputStream in = ParseBenchmark.class.getResourceAsStream(path);
    106         if (in == null) {
    107             throw new IllegalArgumentException("No such file: " + path);
    108         }
    109 
    110         Reader reader = new InputStreamReader(in, "UTF-8");
    111         char[] buffer = new char[8192];
    112         StringWriter writer = new StringWriter();
    113         int count;
    114         while ((count = reader.read(buffer)) != -1) {
    115             writer.write(buffer, 0, count);
    116         }
    117         reader.close();
    118         return writer.toString();
    119     }
    120 
    121     interface Parser {
    122         void parse(String data) throws Exception;
    123     }
    124 
    125     private static class AndroidStreamParser implements Parser {
    126         @Override public void parse(String data) throws Exception {
    127             android.util.JsonReader jsonReader
    128                     = new android.util.JsonReader(new StringReader(data));
    129             readToken(jsonReader);
    130             jsonReader.close();
    131         }
    132 
    133         public void readObject(android.util.JsonReader reader) throws IOException {
    134             reader.beginObject();
    135             while (reader.hasNext()) {
    136                 reader.nextName();
    137                 readToken(reader);
    138             }
    139             reader.endObject();
    140         }
    141 
    142         public void readArray(android.util.JsonReader reader) throws IOException {
    143             reader.beginArray();
    144             while (reader.hasNext()) {
    145                 readToken(reader);
    146             }
    147             reader.endArray();
    148         }
    149 
    150         private void readToken(android.util.JsonReader reader) throws IOException {
    151             switch (reader.peek()) {
    152             case BEGIN_ARRAY:
    153                 readArray(reader);
    154                 break;
    155             case BEGIN_OBJECT:
    156                 readObject(reader);
    157                 break;
    158             case BOOLEAN:
    159                 reader.nextBoolean();
    160                 break;
    161             case NULL:
    162                 reader.nextNull();
    163                 break;
    164             case NUMBER:
    165                 reader.nextLong();
    166                 break;
    167             case STRING:
    168                 reader.nextString();
    169                 break;
    170             default:
    171                 throw new IllegalArgumentException("Unexpected token" + reader.peek());
    172             }
    173         }
    174     }
    175 
    176     private static class OrgJsonParser implements Parser {
    177         @Override public void parse(String data) throws Exception {
    178             if (data.startsWith("[")) {
    179                 new JSONArray(data);
    180             } else if (data.startsWith("{")) {
    181                 new JSONObject(data);
    182             } else {
    183                 throw new IllegalArgumentException();
    184             }
    185         }
    186     }
    187 
    188     private static class GeneralXmlPullParser implements Parser {
    189         @Override public void parse(String data) throws Exception {
    190             XmlPullParser xmlParser = android.util.Xml.newPullParser();
    191             xmlParser.setInput(new StringReader(data));
    192             xmlParser.nextTag();
    193             while (xmlParser.next() != XmlPullParser.END_DOCUMENT) {
    194                 xmlParser.getName();
    195                 xmlParser.getText();
    196             }
    197         }
    198     }
    199 
    200     private static class XmlDomParser implements Parser {
    201         @Override public void parse(String data) throws Exception {
    202             DocumentBuilderFactory.newInstance().newDocumentBuilder()
    203                     .parse(new InputSource(new StringReader(data)));
    204         }
    205     }
    206 
    207     private static class XmlSaxParser implements Parser {
    208         @Override public void parse(String data) throws Exception {
    209             SAXParserFactory.newInstance().newSAXParser().parse(
    210                     new InputSource(new StringReader(data)), new DefaultHandler());
    211         }
    212     }
    213 }
    214