XML parser performance in PyPy

I recently showed some benchmark results comparing the XML parser performance in CPython 3.3 to that in PyPy 1.7. Here's an update for PyPy 1.9 that also includes the current state of the lxml port to that platform, parsing a 3.4MB document style XML file.

CPython 3.3pre:

Initial Memory usage: 11332

xml.etree.ElementTree.parse done in 0.041 seconds

Memory usage: 21468 (+10136)

xml.etree.cElementTree.parse done in 0.041 seconds

Memory usage: 21464 (+10132)

xml.etree.cElementTree.XMLParser.feed(): 25317 nodes read in 0.041 seconds

Memory usage: 21736 (+10404)

lxml.etree.parse done in 0.032 seconds

Memory usage: 28324 (+16992)

drop_whitespace.parse done in 0.030 seconds

Memory usage: 25172 (+13840)

lxml.etree.XMLParser.feed(): 25317 nodes read in 0.037 seconds

Memory usage: 30608 (+19276)

minidom tree read in 0.492 seconds

Memory usage: 29852 (+18520)

PyPy without JIT warming:


Initial Memory usage: 42156

xml.etree.ElementTree.parse done in 0.452 seconds

Memory usage: 44084 (+1928)

xml.etree.cElementTree.parse done in 0.450 seconds

Memory usage: 44080 (+1924)

xml.etree.cElementTree.XMLParser.feed(): 25317 nodes read in 0.457 seconds

Memory usage: 47920 (+5768)

lxml.etree.parse done in 0.033 seconds

Memory usage: 58688 (+16536)

drop_whitespace.parse done in 0.033 seconds

Memory usage: 55536 (+13384)

lxml.etree.XMLParser.feed(): 25317 nodes read in 0.055 seconds

Memory usage: 64724 (+22564)

minidom tree read in 0.541 seconds

Memory usage: 59456 (+17296)

PyPy with JIT warmup:


Initial Memory usage: 646824

xml.etree.ElementTree.parse done in 0.341 seconds

xml.etree.cElementTree.parse done in 0.345 seconds

xml.etree.cElementTree.XMLParser.feed(): 25317 nodes read in 0.342 seconds

lxml.etree.parse done in 0.026 seconds

drop_whitespace.parse done in 0.025 seconds

lxml.etree.XMLParser.feed(): 25317 nodes read in 0.039 seconds

minidom tree read in 0.383 seconds

What you can quickly see is that lxml performs equally well on both (actually slightly faster on PyPy) and beats the other libraries on PyPy by more than an order of magnitude. The absolute numbers are fairly low, though, way below a second for the 3.4MB file. It'll be interesting to see some more complete benchmarks at some point that also take some realistic processing into account.

Remark: cElementTree is just an alias for the plain Python ElementTree on PyPy and ElementTree uses cElementTree in the background in CPython 3.3, which is why both show the same performance. The memory sizes were measured in forked processes, whereas the PyPy JIT numbers were measured in a repeatedly running process in order to take advantage of the JIT compiler. Note the substantially higher memory load of PyPy here.

Update: I originally reported the forked memory size with the non-forked performance for PyPy. The above now shows both separately. A more real-world comparison would likely yield an even higher memory usage on PyPy than the numbers above, which were mostly meant to give an idea of the memory usage of the in-memory tree (i.e. the data impact).