• 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.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") {
newParser()55             @Override Parser newParser() {
56                 return new AndroidStreamParser();
57             }
58         },
59         ORG_JSON("json") {
newParser()60             @Override Parser newParser() {
61                 return new OrgJsonParser();
62             }
63         },
64         XML_PULL("xml") {
newParser()65             @Override Parser newParser() {
66                 return new GeneralXmlPullParser();
67             }
68         },
69         XML_DOM("xml") {
newParser()70             @Override Parser newParser() {
71                 return new XmlDomParser();
72             }
73         },
74         XML_SAX("xml") {
newParser()75             @Override Parser newParser() {
76                 return new XmlSaxParser();
77             }
78         };
79 
80         final String extension;
81 
Api(String extension)82         private Api(String extension) {
83             this.extension = extension;
84         }
85 
newParser()86         abstract Parser newParser();
87     }
88 
89     private String text;
90     private Parser parser;
91 
92     @BeforeExperiment
setUp()93     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 
resourceToString(String path)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 {
parse(String data)122         void parse(String data) throws Exception;
123     }
124 
125     private static class AndroidStreamParser implements Parser {
parse(String data)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 
readObject(android.util.JsonReader reader)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 
readArray(android.util.JsonReader reader)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 
readToken(android.util.JsonReader reader)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 {
parse(String data)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 {
parse(String data)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 {
parse(String data)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 {
parse(String data)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