On Performance of Java XML Parsers

(when used for SOAP)
I think that it is interesting to investigate further big differences between Java native serialization / deserialization and SOAP based (or generally XML based), For example from results fom our paper on performance of RMI we had XML based serialization about 100-1000 slower than native Java (for linked lists of different sizes):
  %%  test type  : serialize_deserialize/minisoap
  %%  test class : class tests.serialize_deserialize.MiniSOAP
  %%
  %%  size  link_ser  link_deser
  %%  [items] [sec]   [sec]
    1000  0.681000006 1.535200000
    100 0.040159999 0.135700001
    10  0.005327000 0.026158000

  %%  test type  : serialize_deserialize/sun
  %%  test class : class tests.serialize_deserialize.Sun
  %%
  %%  size  link_ser  link_deser
  %%  [items] [sec]   [sec]
    1000  0.000050000 0.000080000
    100 0.000005000 0.000004000
    10  0.000004000 0.000002810
I wondered what part of this time is spent on actual XML parsing and if it can be improved. I created some tests (available at into http://www.extreme.indiana.edu/~aslom/exxp/) and compared SAX2 performance of Xerces 1.1.2 and AElfred with SAX2 interface. I have also tested MinML a minimal XML parser that is not only small (with footprint about 15 KB) but supporting SAX1 and is also the fastest as it turned out in testing except for James Clark XP that beats all other competition. I have also checked interesting new parser - alpha version of KXML that is using pull event model and NanoXML that has extremely low footprint (two files about 10 KB).
As a bottom line in comparison I have used dummy_parser which is very fast and simple string scanner (see additional note that discusses different tradeoffs such as buffering on scanner performance).

[Results plot]
 

Test results below have following columns:

  tp600_jdk13     count   nanoxml_sax     list10k 71.513000011
  tp600_jdk13     count   nanoxml_sax     list100 0.063490000
  tp600_jdk13     count   nanoxml_sax     list1   0.001151700

  tp600_jdk13     count   xerces_sax2     list10k 4.455999970
  tp600_jdk13     count   xerces_sax2     list100 0.056680000
  tp600_jdk13     count   xerces_sax2     list1   0.011488500

  tp600_jdk13     count   xerces_sax      list10k 4.104999900
  tp600_jdk13     count   xerces_sax      list100 0.053480000
  tp600_jdk13     count   xerces_sax      list1   0.011462500

  tp600_jdk13     count   aelfred_sax2    list10k 4.175999999
  tp600_jdk13     count   aelfred_sax2    list100 0.042659999
  tp600_jdk13     count   aelfred_sax2    list1   0.001999900

  tp600_jdk13     count   kxml_alpha      list10k 4.116000056
  tp600_jdk13     count   kxml_alpha      list100 0.041460000
  tp600_jdk13     count   kxml_alpha      list1   0.000834200

  tp600_jdk13     count   minml_sax       list10k 4.026000023
  tp600_jdk13     count   minml_sax       list100 0.040660000
  tp600_jdk13     count   minml_sax       list1   0.000668000

  tp600_jdk13     count   dummy_parser    list10k 0.361000061
  tp600_jdk13     count   dummy_parser    list100 0.002900000
  tp600_jdk13     count   dummy_parser    list1   0.000052100

  tp600_jdk13      count    jclark_xp     list10k 1.692999959
  tp600_jdk13      count    jclark_xp     list100 0.017620001
  tp600_jdk13      count    jclark_xp     list1   0.000754000
First observation from results (see plot): for bigger sizes differences between parsers become less important (except for NanoXML as it is building document structure in memory similar to DOM).

MinML is very small but it is also the fastest parser for small sizes and performs very reasonably for big documents.

NanoXML is the slowest for big documents as it is very memory intensive (basically constructing all tree in memory like DOM and walking it through SAX interface) but it indeed has the smallest footprint.

Xerces JAR is considerably bigger than any other parser and as expected is considerably slower for small sizes (both SAX1 and SAX2 interfaces) than much more lightweight AElfred. AElfred is one of the fastest SAX parser although the margin is not very big.

KXML is experimental pull parser and although it shows promising performance for small sizes due to implementation that allocates new object for each event it is not taking full advantage of more efficient design - for bigger sizes it is not much faster than AELfred.

JCLARK_XP beats all concurence especially for bigger sizes of documents as it is using very efficient string caching to prevent unnecessary memory allocation for Strings.

From profiling of existing parser I have concluded that memory allocations are affecting performance the most. To check this assumption I have written Simple XML Tokenizer (sxt) that keeps memory allocations to minimum. Then on top of this tokenizer I have created XML Pull Parser (xpp) which provides event based interface to XML parsing and supports optionally namespaces.

  tp600_jdk13     count   xpp             list10k 1.823000073
  tp600_jdk13     count   xpp             list100 0.016919999
  tp600_jdk13     count   xpp             list1   0.000338500

  tp600_jdk13     count   sxt             list10k 1.382000089
  tp600_jdk13     count   sxt             list100 0.013119999
  tp600_jdk13     count   sxt             list1   0.000198300
Both XML tokenizer and pull parser were designed to work with SOAP as fast as possible. For this reason XML pull parser is not supporting entities declaration and does not enforce attribute uniqueness. Adding those feature is not difficult but they are not needed for SOAP applications (as we can assume that input XML is already valid).

From the results above it seems that XML pull parser is at least two times faster than any existing XML parser (although for small sizes they are 30 times faster than Xerces SAX). It seems that it is actual limit on XML parsers performance as both xpp and sxt were designed and coded to be as fast as possible (for example all parsing is done in one big switch loop).
 
 

Aleksander Slominski

 

 



Additional resources: