[Redis] Perl Redis Client news
Steffen Mueller
smueller at cpan.org
Mon Nov 18 20:18:58 GMT 2013
On 11/18/2013 07:20 PM, Pedro Melo wrote:
> According to my profiling, parsing the Redis protocol is the bottlenet
> *most* of the time. Adding a way to improve that part seems to me a good
> way to improve the overall performance.
Of course, this entire exchange is valid only without considering
network latencies which at a hefty half millisecond trump most things.
But on a multi-use client machine, CPU capacity is a separate thing to
optimize for, so making things faster never hurts!
> Having a XS backend for that, with the PP fallback, seems to be the
> standard approach for a lot of CPAN modules.
Hmm. And here I was, thinking that maybe there's low hanging fruit on
the encoding side. Here's a quick snippet[2]:
void
redis_encode(...)
PREINIT:
SV *retval;
int i;
char *str;
PPCODE:
retval = sv_2mortal(newSVpvf("*%lu\r\n", (unsigned long)items));
for (i = 0; i < items; ++i) {
/* FIXME UTF8? */
sv_catpvf(retval, "$%lu\r\n", (unsigned long)SvCUR(ST(i)));
sv_catsv(retval, ST(i));
}
PUSHs(retval);
$ time perl -Mblib -MXSFun -le '@d=(qw(SET foo), "x" x 10);for
(1..1e6){$x = ""; $x .= "*" . scalar(@d) . "\r\n"; $x .=
"\$".length($_)."\r\n$_\r\n" for @d; }'
real 0m1.552s
user 0m1.536s
sys 0m0.008s
$ time perl -Mblib -MXSFun -le '@d=(qw(SET foo), "x" x 10);for
(1..1e6){$x=redis_encode(@d)}'
real 0m1.112s
user 0m1.100s
sys 0m0.008s
With a bigger value:
$ time perl -Mblib -MXSFun -le '@d=(qw(SET foo), "x" x 10000);for
(1..1e6){$x = ""; $x .= "*" . scalar(@d) . "\r\n"; $x .=
"\$".length($_)."\r\n$_\r\n" for @d; }'
real 0m2.870s
user 0m2.856s
sys 0m0.004s
$ time perl -Mblib -MXSFun -le '@d=(qw(SET foo), "x" x 10000);for
(1..1e6){$x=redis_encode(@d)}'
real 0m1.629s
user 0m1.616s
sys 0m0.004s
Meh. Just a modest win. :)
> Ok, then against RedisDB XS component…
That seems a better bet indeed.
> RedisDB (I *think* its RedisDB…) has a XS interface. We could compare it
> with our read()-based performance…
Just checked. Yes, it's RedisDB.
> What's the main benefit you'd hope for? Maybe there's an easy win?
>
> Moare speed. I have *one* use case where redis protocol parser showed up
> on my app profiling… it's a rather eavy use of Redis.
We use Redis a fair amount at work, but IIRC the miscellaneous
marshalling code of all cases is more expensive than the Redis.pm logic.
> [1] Example:
> reply = redisCommand(c,"LPUSH mylist element-%s", buf);
>
>
> YUCK!!!
I know, right?
--Steffen
[2] I tried a more slightly elaborate solution which would calculate an
upper bound on the output string length first and then allocated that
all in one go. Of course, that would have to peek at each stacked
parameter at least twice and that turned out SLOWER than pure-Perl. Rare
occasion that shaving of mallocs isn't a clear win.
More information about the Redis
mailing list