Comments on "Performance Comparison Between SAX XML::Filter::Dispatcher and XML::Twig"
These comments refer to Tom Anderson's Performance Comparison Between SAX XML::Filter::Dispatcher and XML::Twig article.
It's an interesting article. I especially never realized that returning a short (1) value from a handler could impact performances that much (see difference between test 2 and test 3 below).
The code presented is quite simple, it could be slightly simplified by replacing $_[1] by simply $_ in handlers (from the doc "$_ is also set to the element, so it is easy to write inline handlers like para => sub { $_->change_gi( 'p'); }.
There is one problem with the code though: using $_[1]->{att}->{val}: attributes should be accessed using the provided accessor method $_[1]->att( 'val'). This impacts performances, but the faster syntax is not garanteed to work in a future version of the module (for example if I decide to pool attribute values, of course I might implement it as a tied-hash, but there is no garantee for that in the documentation of the module).
I tried to squeeze some additionnal speed on the example, using twig_roots so the tree is not build for most elements. In this case this kinda defeats the purpose of XML::Twig and turns it essentially into a rather thin layer on top of XML::Parser, but at least it takes care of dispatching the callbacks without using "large case statements".
The code for the most interesting test (test 3) is this:
#!/usr/bin/perl
#
# Program to test performance of XML::Twig
# Tom Anderson + mirod
# Thu Jan 16 22:49:24 PST 2003 + Friday March 7 2003
# same as test_perf2 except handlers return 1
#
use strict;
use warnings;
use diagnostics;
use XML::Twig;
use File::Slurp;
my $VERSION=0.02;
my $out_file= shift( @ARGV) || "$0.out";
my $less_memory=1;
my $out="";
my $xml= XML::Twig->new(
# start_tag_handlers are called when the start tag is found
# if the element is outside of the twig_roots then parameters are similar to XML::Parser's:
# the twig, the gi and a hash of attributes
start_tag_handlers =>
{
'/TRACES/NET/WIR' => sub
{ my( $t, $gi, %atts)= @_;
$out .= 'WIR '. $atts{numseg} .' '. $atts{startx} .' '. $atts{starty} .' '.
$atts{termx} .' '. $atts{termy} .' '. $atts{optgroup}."\n";
1;
},
'/TRACES/NET' => sub
{ my( $t, $gi, %atts)= @_;
$out .= "# NET '". $atts{name}."'\n";
1;
},
'/TRACES/UNITS' => sub
{ my( $t, $gi, %atts)= @_;
$out .= 'UNITS '. $atts{val}."\n";
1;
},
'/TRACES/STFIRST' => sub
{ my( $t, $gi, %atts)= @_;
$out .= 'ST '. $atts{maxx} .' '. $atts{maxy} .' '. $atts{maxroute}.' '. $atts{numconn} ."\n";
1;
},
'/TRACES/XRF' => sub
{ my( $t, $gi, %atts)= @_;
$out .= 'XRF '. $atts{num} .' '. $atts{name}."\n";
1;
},
'/TRACES/NET/WIR/SEG' => sub
{ my( $t, $gi, %atts)= @_;
$out .= 'SEG '. $atts{x} .' '. $atts{y} .' '. $atts{lay} .' '. $atts{width}."\n";
1;
},
'/TRACES/NET/GUI' => sub
{ my( $t, $gi, %atts)= @_;
$out .= 'GUI '. $atts{startx} .' '. $atts{starty} .' '. $atts{startlay}.' '.
$atts{termx} .' '. $atts{termy} .' '. $atts{termlay} .' '. $atts{optgroup}."\n";
1;
},
'/TRACES/STLAST' => sub
{ my( $t, $gi, %atts)= @_;
$out .= 'ST '. $atts{checkstat} .' '. $atts{numcomplete}.' '. $atts{numinc} .' '.
$atts{numunroute} .' '. $atts{numnotrace} .' '. $atts{numfill} ."\n";
1;
},
},
# the twig will be built only for those elements
twig_roots =>
{
'/TRACES/HEADER' => sub
{
$out .= $_->text;
$_[0]->purge if $less_memory; # not really useful in this case, there is only 1, small HEADER element
1;
},
},
);
$xml->parsefile('traces.xml');
write_file( $out_file, $out);
|
All tests: sax_twig_comments.tar.gz, using data from http://tomacorp.com/perl/xml/traces.xml (unpack, save traces.xml in the sax_twig_comments directory and run with run_test_perf)
Here are the results:
Test 1 - original version (test_perf1) 2 wallclock secs (0.00 usr 0.00 sys + 1.63 cusr 0.09 csys = 1.72 CPU) Test 2 - using twig_roots (test_perf2) 4 wallclock secs (0.00 usr 0.00 sys + 2.76 cusr 0.97 csys = 3.73 CPU) Test 3 - twig_roots + return 1 (test_perf3) 0 wallclock secs (0.01 usr 0.00 sys + 0.72 cusr 0.03 csys = 0.76 CPU) Test 4 - twig_roots + return undef (test_perf4) 1 wallclock secs (0.00 usr 0.00 sys + 0.71 cusr 0.05 csys = 0.76 CPU) Test 5 - handlers on element name (test_perf5) 1 wallclock secs (0.00 usr 0.00 sys + 0.74 cusr 0.01 csys = 0.75 CPU) Test 6 - same with partial path (test_perf6) 1 wallclock secs (0.00 usr 0.00 sys + 0.70 cusr 0.04 csys = 0.74 CPU)
Note that results for test 5 and 6 vary, sometimes one is faster than the other, sometimes it's the opposite.
© Michel Rodriguez - 2003