001: /*
002: * Copyright (c) 2000-2001 Sosnoski Software Solutions, Inc.
003: *
004: * Permission is hereby granted, free of charge, to any person obtaining a copy
005: * of this software and associated documentation files (the "Software"), to deal
006: * in the Software without restriction, including without limitation the rights
007: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
008: * copies of the Software, and to permit persons to whom the Software is
009: * furnished to do so, subject to the following conditions:
010: *
011: * The above copyright notice and this permission notice shall be included in
012: * all copies or substantial portions of the Software.
013: *
014: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
017: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
019: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
020: * IN THE SOFTWARE.
021: */
022:
023: package com.sosnoski.xmlbench;
024:
025: import java.io.*;
026: import java.util.*;
027:
028: import javax.xml.parsers.*;
029:
030: import org.xml.sax.*;
031: import org.xml.sax.helpers.*;
032:
033: /**
034: * SAX parser benchmark test class. This class defines a single test for a
035: * SAX parser, parsing the document text and accumulating document
036: * characteristics.
037: *
038: * @author Dennis M. Sosnoski
039: * @version 1.2
040: */
041:
042: public class BenchSAX extends BenchBase {
043: /** Flag for first time through build method, used for get class name. */
044: private boolean m_firstTime = true;
045:
046: /**
047: * Inner class for handling SAX notifications.
048: */
049:
050: protected class InnerHandler extends DefaultHandler {
051: /** Summary information accumulated for document. */
052: private DocumentSummary m_summary;
053:
054: /**
055: * Getter for document summary information.
056: *
057: * @return document summary information
058: */
059:
060: public DocumentSummary getSummary() {
061: return m_summary;
062: }
063:
064: /**
065: * Setter for document summary information.
066: *
067: * @param summary document summary information
068: */
069:
070: public void setSummary(DocumentSummary summary) {
071: m_summary = summary;
072: }
073:
074: /**
075: * Start of document handler. Clears the accumulated document
076: * summary information.
077: */
078:
079: public void startDocument() {
080: m_summary.reset();
081: }
082:
083: /**
084: * Start of element handler. Counts the element and attributes.
085: *
086: * @param space namespace URI
087: * @param name local name of element
088: * @param raw raw element name
089: * @param atts attributes for element
090: */
091:
092: public void startElement(String space, String name, String raw,
093: Attributes atts) {
094: m_summary.addElements(1);
095: for (int i = 0; i < atts.getLength(); i++) {
096: m_summary.addAttribute(atts.getValue(i).length());
097: }
098: }
099:
100: /**
101: * Character data handler. Counts the characters in total for
102: * document.
103: *
104: * @param ch array supplying character data
105: * @param start starting offset in array
106: * @param length number of characters
107: */
108:
109: public void characters(char[] ch, int start, int length) {
110: m_summary.addContent(length);
111: }
112:
113: /**
114: * Ignorable whitespace handler. Counts the characters in total for
115: * document.
116: *
117: * @param ch array supplying character data
118: * @param start starting offset in array
119: * @param length number of characters
120: */
121:
122: public void ignorableWhitespace(char[] ch, int start, int length) {
123: m_summary.addContent(length);
124: }
125: }
126:
127: /**
128: * Constructor.
129: *
130: * @param print test results listing destination (<code>null</code> if not
131: * to be printed)
132: */
133:
134: public BenchSAX() {
135: super ("SAX");
136: }
137:
138: /**
139: * Main time test method. This implementation of the abstract base class
140: * method just parses the document texts repeatedly, accumulating summary
141: * information for the documents which can be compared to that obtained
142: * from the documents representation tests.
143: *
144: * @param passes number of passes of each test
145: * @param excludes number of initialization passes excluded from averages
146: * @param texts document texts for test
147: * @return result times array
148: */
149:
150: public int[] runTimeTest(int passes, int excludes, byte[][] texts) {
151:
152: // allocate array for result values
153: int[] results = new int[TIME_RESULT_COUNT];
154: for (int i = 0; i < results.length; i++) {
155: results[i] = Integer.MIN_VALUE;
156: }
157:
158: // create the input objects
159: int doccnt = texts.length;
160: ByteArrayInputStream[][] ins = new ByteArrayInputStream[passes][];
161: for (int i = 0; i < passes; i++) {
162: ins[i] = new ByteArrayInputStream[doccnt];
163: for (int j = 0; j < doccnt; j++) {
164: ins[i][j] = new ByteArrayInputStream(texts[j]);
165: }
166: }
167: InputSource source = new InputSource();
168:
169: // set start time for tests
170: initTime();
171:
172: // parse the documents the specified number of times
173: DocumentSummary first = new DocumentSummary();
174: DocumentSummary next = new DocumentSummary();
175: SAXParserFactory spf = SAXParserFactory.newInstance();
176: spf.setValidating(false);
177: try {
178: SAXParser parser = spf.newSAXParser();
179: XMLReader reader = parser.getXMLReader();
180: if (m_firstTime) {
181: setVariant(reader.getClass().getPackage().getName());
182: m_firstTime = false;
183: }
184: InnerHandler handler = new InnerHandler();
185: reader.setContentHandler(handler);
186: handler.setSummary(first);
187: int best = Integer.MAX_VALUE;
188: int sum = 0;
189: for (int i = 0; i < passes; i++) {
190: for (int j = 0; j < doccnt; j++) {
191: source.setByteStream(ins[i][j]);
192: reader.parse(source);
193: }
194: int time = testPassTime();
195: if (m_printPass) {
196: reportValue("Parse document pass " + i, time);
197: }
198: if (best > time) {
199: best = time;
200: }
201: if (i >= excludes) {
202: sum += time;
203: }
204: if (i == 0) {
205: handler.setSummary(next);
206: } else if (!first.equals(handler.getSummary())) {
207: throw new RuntimeException(
208: "Document summary information mismatch");
209: }
210: }
211: results[BUILD_MIN_INDEX] = best;
212: results[BUILD_AVERAGE_INDEX] = sum / (passes - excludes);
213:
214: } catch (Exception ex) {
215: ex.printStackTrace(System.err);
216: System.exit(0);
217: }
218:
219: // copy document summary values for return
220: results[ELEMENT_COUNT_INDEX] = first.getElementCount();
221: results[ATTRIBUTE_COUNT_INDEX] = first.getAttributeCount();
222: results[CONTENT_COUNT_INDEX] = first.getContentCount();
223: results[TEXTCHAR_COUNT_INDEX] = first.getTextCharCount();
224: results[ATTRCHAR_COUNT_INDEX] = first.getAttrCharCount();
225:
226: // print summary for document
227: if (m_printSummary) {
228: printSummary(" Document", first, m_printStream);
229: }
230: return results;
231: }
232:
233: /**
234: * Main space test method. This implementation of the abstract base class
235: * method just parses the documents repeatedly to check memory usage by the
236: * parser.
237: *
238: * @param count number of units of test to run in this pass
239: * @param excludes number of initialization passes excluded from averages
240: * @param texts document texts for test
241: * @return result times array
242: */
243:
244: public int[] runSpaceTest(int passes, int excludes, byte[][] texts) {
245:
246: // allocate array for result values
247: int doccnt = texts.length;
248: int[] results = new int[SPACE_RESULT_COUNT];
249: for (int i = 0; i < results.length; i++) {
250: results[i] = Integer.MIN_VALUE;
251: }
252:
253: // create the reusable objects
254: ByteArrayInputStream[][] ins = new ByteArrayInputStream[passes][];
255: for (int i = 0; i < passes; i++) {
256: ins[i] = new ByteArrayInputStream[doccnt];
257: for (int j = 0; j < doccnt; j++) {
258: ins[i][j] = new ByteArrayInputStream(texts[j]);
259: }
260: }
261: InputSource source = new InputSource();
262: DocumentSummary first = new DocumentSummary();
263: DocumentSummary next = new DocumentSummary();
264: InnerHandler handler = new InnerHandler();
265:
266: // initialize memory information for tests
267: initMemory();
268: results[INITIAL_MEMORY_INDEX] = (int) m_lastMemory;
269:
270: // parse the documents the specified number of times
271: SAXParserFactory spf = SAXParserFactory.newInstance();
272: spf.setValidating(false);
273: try {
274: SAXParser parser = spf.newSAXParser();
275: XMLReader reader = parser.getXMLReader();
276: if (m_firstTime) {
277: setVariant(reader.getClass().getPackage().getName());
278: m_firstTime = false;
279: }
280: reader.setContentHandler(handler);
281: handler.setSummary(first);
282: int base = (int) m_lastMemory;
283: for (int i = 0; i < passes; i++) {
284: for (int j = 0; j < doccnt; j++) {
285: source.setByteStream(ins[i][j]);
286: reader.parse(source);
287: }
288: if (i == 0) {
289: results[FIRST_SPACE_INDEX] = testPassSpace();
290: handler.setSummary(next);
291: if (excludes == 1) {
292: base = (int) m_lastMemory;
293: }
294: } else {
295: if (!first.equals(handler.getSummary())) {
296: throw new RuntimeException(
297: "Document summary information mismatch");
298: }
299: if ((i + 1) == excludes) {
300: testPassSpace();
301: base = (int) m_lastMemory;
302: }
303: }
304: if (m_printPass) {
305: reportValue("Parse pass " + i, testPassSpace());
306: }
307: }
308: results[AVERAGE_SPACE_INDEX] = ((int) m_lastMemory - base)
309: / (passes - excludes);
310: } catch (Exception ex) {
311: ex.printStackTrace(System.err);
312: System.exit(0);
313: }
314:
315: // free all constructed objects to find final space
316: spf = null;
317: initMemory();
318: results[DELTA_MEMORY_INDEX] = (int) m_lastMemory
319: - results[INITIAL_MEMORY_INDEX];
320: return results;
321: }
322: }
|