197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes/* 297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * Copyright (C) 2011 Google Inc. 397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * 497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License"); 597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * you may not use this file except in compliance with the License. 697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * You may obtain a copy of the License at 797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * 897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * http://www.apache.org/licenses/LICENSE-2.0 997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * 1097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * Unless required by applicable law or agreed to in writing, software 1197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS, 1297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * See the License for the specific language governing permissions and 1497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * limitations under the License. 1597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes */ 1697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 1797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughespackage benchmarks.regression; 1897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 19ea13f8291a92b6f47f50011da1d5e8c107984bc3Paul Duffinimport com.google.caliper.BeforeExperiment; 2097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughesimport com.google.caliper.Param; 2197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughesimport java.io.IOException; 2297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughesimport java.io.InputStream; 2397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughesimport java.io.InputStreamReader; 2497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughesimport java.io.Reader; 2597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughesimport java.io.StringReader; 2697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughesimport java.io.StringWriter; 2797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughesimport javax.xml.parsers.DocumentBuilderFactory; 2897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughesimport javax.xml.parsers.SAXParserFactory; 2997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughesimport org.json.JSONArray; 3097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughesimport org.json.JSONObject; 3197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughesimport org.xml.sax.InputSource; 3297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughesimport org.xml.sax.helpers.DefaultHandler; 3397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughesimport org.xmlpull.v1.XmlPullParser; 3497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 3597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes/** 3697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * Measure throughput of various parsers. 3797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * 3897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * <p>This benchmark requires that ParseBenchmarkData.zip is on the classpath. 3997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * That file contains Twitter feed data, which is representative of what 4097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes * applications will be parsing. 4197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes */ 42ea13f8291a92b6f47f50011da1d5e8c107984bc3Paul Duffinpublic final class ParseBenchmark { 4397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 4497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes @Param Document document; 4597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes @Param Api api; 4697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 4797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes private enum Document { 4897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes TWEETS, 4997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes READER_SHORT, 5097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes READER_LONG 5197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 5297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 5397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes private enum Api { 5497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes ANDROID_STREAM("json") { 5597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes @Override Parser newParser() { 5697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes return new AndroidStreamParser(); 5797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 5897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes }, 5997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes ORG_JSON("json") { 6097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes @Override Parser newParser() { 6197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes return new OrgJsonParser(); 6297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 6397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes }, 6497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes XML_PULL("xml") { 6597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes @Override Parser newParser() { 6697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes return new GeneralXmlPullParser(); 6797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 6897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes }, 6997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes XML_DOM("xml") { 7097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes @Override Parser newParser() { 7197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes return new XmlDomParser(); 7297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 7397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes }, 7497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes XML_SAX("xml") { 7597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes @Override Parser newParser() { 7697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes return new XmlSaxParser(); 7797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 7897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes }; 7997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 8097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes final String extension; 8197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 8297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes private Api(String extension) { 8397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes this.extension = extension; 8497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 8597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 8697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes abstract Parser newParser(); 8797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 8897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 8997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes private String text; 9097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes private Parser parser; 9197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 92ea13f8291a92b6f47f50011da1d5e8c107984bc3Paul Duffin @BeforeExperiment 93ea13f8291a92b6f47f50011da1d5e8c107984bc3Paul Duffin protected void setUp() throws Exception { 9497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes text = resourceToString("/" + document.name() + "." + api.extension); 9597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes parser = api.newParser(); 9697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 9797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 9897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes public void timeParse(int reps) throws Exception { 9997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes for (int i = 0; i < reps; i++) { 10097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes parser.parse(text); 10197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 10297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 10397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 10497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes private static String resourceToString(String path) throws Exception { 10597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes InputStream in = ParseBenchmark.class.getResourceAsStream(path); 10697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes if (in == null) { 10797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes throw new IllegalArgumentException("No such file: " + path); 10897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 10997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 11097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes Reader reader = new InputStreamReader(in, "UTF-8"); 11197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes char[] buffer = new char[8192]; 11297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes StringWriter writer = new StringWriter(); 11397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes int count; 11497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes while ((count = reader.read(buffer)) != -1) { 11597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes writer.write(buffer, 0, count); 11697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 11797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes reader.close(); 11897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes return writer.toString(); 11997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 12097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 12197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes interface Parser { 12297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes void parse(String data) throws Exception; 12397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 12497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 12597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes private static class AndroidStreamParser implements Parser { 12697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes @Override public void parse(String data) throws Exception { 12797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes android.util.JsonReader jsonReader 12897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes = new android.util.JsonReader(new StringReader(data)); 12997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes readToken(jsonReader); 13097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes jsonReader.close(); 13197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 13297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 13397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes public void readObject(android.util.JsonReader reader) throws IOException { 13497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes reader.beginObject(); 13597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes while (reader.hasNext()) { 13697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes reader.nextName(); 13797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes readToken(reader); 13897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 13997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes reader.endObject(); 14097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 14197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 14297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes public void readArray(android.util.JsonReader reader) throws IOException { 14397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes reader.beginArray(); 14497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes while (reader.hasNext()) { 14597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes readToken(reader); 14697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 14797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes reader.endArray(); 14897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 14997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 15097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes private void readToken(android.util.JsonReader reader) throws IOException { 15197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes switch (reader.peek()) { 15297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes case BEGIN_ARRAY: 15397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes readArray(reader); 15497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes break; 15597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes case BEGIN_OBJECT: 15697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes readObject(reader); 15797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes break; 15897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes case BOOLEAN: 15997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes reader.nextBoolean(); 16097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes break; 16197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes case NULL: 16297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes reader.nextNull(); 16397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes break; 16497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes case NUMBER: 16597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes reader.nextLong(); 16697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes break; 16797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes case STRING: 16897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes reader.nextString(); 16997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes break; 17097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes default: 17197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes throw new IllegalArgumentException("Unexpected token" + reader.peek()); 17297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 17397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 17497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 17597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 17697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes private static class OrgJsonParser implements Parser { 17797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes @Override public void parse(String data) throws Exception { 17897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes if (data.startsWith("[")) { 17997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes new JSONArray(data); 18097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } else if (data.startsWith("{")) { 18197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes new JSONObject(data); 18297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } else { 18397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes throw new IllegalArgumentException(); 18497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 18597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 18697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 18797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 18897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes private static class GeneralXmlPullParser implements Parser { 18997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes @Override public void parse(String data) throws Exception { 19097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes XmlPullParser xmlParser = android.util.Xml.newPullParser(); 19197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes xmlParser.setInput(new StringReader(data)); 19297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes xmlParser.nextTag(); 19397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes while (xmlParser.next() != XmlPullParser.END_DOCUMENT) { 19497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes xmlParser.getName(); 19597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes xmlParser.getText(); 19697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 19797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 19897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 19997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 20097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes private static class XmlDomParser implements Parser { 20197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes @Override public void parse(String data) throws Exception { 20297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes DocumentBuilderFactory.newInstance().newDocumentBuilder() 20397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes .parse(new InputSource(new StringReader(data))); 20497aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 20597aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 20697aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes 20797aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes private static class XmlSaxParser implements Parser { 20897aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes @Override public void parse(String data) throws Exception { 20997aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes SAXParserFactory.newInstance().newSAXParser().parse( 21097aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes new InputSource(new StringReader(data)), new DefaultHandler()); 21197aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 21297aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes } 21397aba27f961a5a6f37dcaf7f455df371e250ede3Elliott Hughes} 214