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