tokuhirom
9/27/2010 - 11:38 PM

.gitignore

use strict;
use warnings;
use local::lib 'extlib';
use Benchmark ':all';
use Plack::Request;
use Plack::Builder;

# -------------------------------------------------------------------------
# RPC::XML

use RPC::XML;
use RPC::XML::ParserFactory;

my %dispatch_table = (
    'MyRPC.sum' => sub {
        return RPC::XML::response->new(0 + $_[0]->value + $_[1]->value);
    },
);

my $parser = RPC::XML::ParserFactory->new(class => 'XML::LibXML');
my $rpc_xml_app = sub {
    my $req = Plack::Request->new(@_);
    my $q = $parser->parse($req->content);
    my $method_name = $q->name;
    my $code = $dispatch_table{$method_name} or return [404, [], ["not found: $method_name"]];
    my $rpc_res = $code->(@{$q->args});
    return [ 200, [ 'Content-Type', 'text/xml' ], [ $rpc_res->as_string ] ];
};

# -------------------------------------------------------------------------
# RPC::XML::Server::PSGI
use RPC::XML::Server::PSGI;
my $rpc_xml_server_psgi_app = do {
    my $server = RPC::XML::Server::PSGI->new();
    $server->add_proc(
        {
            name => 'MyRPC.sum',
            code => sub {
                return 0 + $_[0] + $_[1];
            },
            signature => ['string int int'],
        }
    );
    $server->to_app();
};
# -------------------------------------------------------------------------
# XMLRPC::Lite

use XMLRPC::Lite;
use XMLRPC::Transport::HTTP::PSGI;
{
    package MyRPC;
    sub sum {
        my ($class, $arg1, $arg2) = @_;
        return $arg1 + $arg2;
    }
}

my $xmlrpc_lite_app = XMLRPC::Transport::HTTP::PSGI->dispatch_to("MyRPC")->handle;

# -------------------------------------------------------------------------
# XML::RPC
use XML::RPC;

my %xmlrpc_dispatch_table = (
    'MyRPC.sum' => sub {
        return 0+$_[0]+$_[1];
    },
);
my $xmlrpc = XML::RPC->new();
my $xml_rpc_app = sub {
    my $req = Plack::Request->new(@_);
    my $xml = $xmlrpc->receive($req->content, sub {
        my $method_name = shift;
        $xmlrpc_dispatch_table{$method_name}->(@_);
    });
    return [ 200, [ 'Content-Type', 'text/xml' ], [ $xml ] ];
};

# -------------------------------------------------------------------------
# XML::RPC::Fast
use XML::RPC::Fast;
use XML::RPC::Enc::LibXML;

my $xml_rpc_fast = XML::RPC::Fast->new(undef, encoder => XML::RPC::Enc::LibXML->new);
my $xml_rpc_fast_app = sub {
    my $req = Plack::Request->new(@_);
    my $xml = $xml_rpc_fast->receive($req->content, sub {
        my $method_name = shift;
        $xmlrpc_dispatch_table{$method_name}->(@_);
    });
    return [ 200, [ 'Content-Type', 'text/xml' ], [ $xml ] ];
};

# -------------------------------------------------------------------------
# RESTful JSON
use JSON::XS qw/encode_json/;
my %rest_dispatch_table = (
    '/sum' => sub {
        return 0+$_[0]->param('a')+$_[0]->param('b');
    },
);
my $json_xs_app = sub {
    my $req = Plack::Request->new(@_);
    my $code = $rest_dispatch_table{$req->path_info} or return [404, [], []];
    my $json = encode_json(+{result => scalar($code->($req))});
    return [200, ['Content-Type', 'text/json'], [$json]];
};

# -------------------------------------------------------------------------
# benchmark
use HTTP::Request;
use HTTP::Message::PSGI;

my $rpc_req     = RPC::XML::request->new( 'MyRPC.sum', 18, 22 );
my $rpc_content = $rpc_req->as_string;
my $req         = HTTP::Request->new(
    POST => 'http://localhost/',
    [
        'Content-Length' => length($rpc_content),
        'Content-Type'   => 'text/xml'
    ],
    $rpc_content
);

my $rest_req = HTTP::Request->new(POST => 'http://localhost/sum?a=18&b=22');

print "RPC::XML: $RPC::XML::VERSION\n";
print "XMLRPC::Lite: $XMLRPC::Lite::VERSION\n";
print "XML::RPC: $XML::RPC::VERSION\n";
print "XML::RPC::Fast: $XML::RPC::VERSION\n";

print "-"x60, $/;

print $xmlrpc_lite_app->($req->to_psgi)->[2]->[0], $/;
print $xml_rpc_app->($req->to_psgi)->[2]->[0], $/;
print $rpc_xml_app->($req->to_psgi)->[2]->[0], $/;
print $xml_rpc_fast_app->($req->to_psgi)->[2]->[0], $/;
print $rpc_xml_server_psgi_app->($req->to_psgi)->[2]->[0], $/ for 1..10;

print "-"x60, $/;

my $x = timethese(
    5000, {
#       'XMLRPC::Lite' => sub {
#           $xmlrpc_lite_app->($req->to_psgi);
#       },
        'RPC::XML' => sub {
            $rpc_xml_app->($req->to_psgi);
        },
#       'RPC::XML::S::PSGI' => sub {
#           $rpc_xml_server_psgi_app->($req->to_psgi);
#       },
#       'XML::RPC' => sub {
#           $xml_rpc_app->($req->to_psgi);
#       },
        'XML::RPC::Fast' => sub {
            $xml_rpc_fast_app->($req->to_psgi);
        },
#       'rest json' => sub {
#           $json_xs_app->($rest_req->to_psgi);
#       },
    },
);
cmpthese($x);

RPC::XML: 1.5
XMLRPC::Lite: 0.712
XML::RPC: 0.9
XML::RPC::Fast: 0.9
------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?><methodResponse><params><param><value><int>40</int></value></param></params></methodResponse>
<?xml version="1.0" encoding="UTF-8" ?>
<methodResponse>
<params>
<param>
<value>
<i4>40</i4>
</value>
</param>
</params>
</methodResponse>

<?xml version="1.0" encoding="us-ascii"?><methodResponse><params><param><value><int>40</int></value></param></params></methodResponse>
<?xml version="1.0" encoding="utf-8"?>
<methodResponse><params><param><value><i4>40</i4></value></param></params></methodResponse>

------------------------------------------------------------
Benchmark: timing 5000 iterations of RPC::XML, XML::RPC, XML::RPC::Fast, XMLRPC::Lite, rest json...
  RPC::XML:  2 wallclock secs ( 1.73 usr +  0.00 sys =  1.73 CPU) @ 2890.17/s (n=5000)
  XML::RPC:  4 wallclock secs ( 4.51 usr +  0.00 sys =  4.51 CPU) @ 1108.65/s (n=5000)
XML::RPC::Fast:  2 wallclock secs ( 1.78 usr +  0.00 sys =  1.78 CPU) @ 2808.99/s (n=5000)
XMLRPC::Lite: 16 wallclock secs (15.49 usr +  0.01 sys = 15.50 CPU) @ 322.58/s (n=5000)
 rest json:  0 wallclock secs ( 0.12 usr +  0.00 sys =  0.12 CPU) @ 41666.67/s (n=5000)
            (warning: too few iterations for a reliable count)
                  Rate XMLRPC::Lite  XML::RPC XML::RPC::Fast  RPC::XML rest json
XMLRPC::Lite     323/s           --      -71%           -89%      -89%      -99%
XML::RPC        1109/s         244%        --           -61%      -62%      -97%
XML::RPC::Fast  2809/s         771%      153%             --       -3%      -93%
RPC::XML        2890/s         796%      161%             3%        --      -93%
rest json      41667/s       12817%     3658%          1383%     1342%        --
foo.pl
nytprof.out
extlib/