SlideShare a Scribd company logo
1 of 86
Download to read offline
Adventures in
Optimization
David Golden • @xdg!
NY.pm • July 2014
The problem…
Perl hashes are
unordered maps
Perl hashes are random

unordered maps
Perl 5.16 Perl 5.18
1 => 2
3 => 4
7 => 8
9 => 10
5 => 6
!
1 => 2
3 => 4
7 => 8
9 => 10
5 => 6
!
1 => 2
3 => 4
7 => 8
9 => 10
5 => 6
5 => 6
9 => 10
7 => 8
3 => 4
1 => 2
!
7 => 8
3 => 4
5 => 6
1 => 2
9 => 10
!
9 => 10
1 => 2
3 => 4
7 => 8
5 => 6
$ perl -wE 'my %h = 1 .. 10; say "$_ => $h{$_}" for keys %h'
Perl 5.16 Perl 5.18
1 => 2
3 => 4
7 => 8
9 => 10
5 => 6
!
1 => 2
3 => 4
7 => 8
9 => 10
5 => 6
!
1 => 2
3 => 4
7 => 8
9 => 10
5 => 6
5 => 6
9 => 10
7 => 8
3 => 4
1 => 2
!
7 => 8
3 => 4
5 => 6
1 => 2
9 => 10
!
9 => 10
1 => 2
3 => 4
7 => 8
5 => 6
$ perl -wE 'my %h = 1 .. 10; say "$_ => $h{$_}" for keys %h'
Perl 5.16 Perl 5.18
1 => 2
3 => 4
7 => 8
9 => 10
5 => 6
!
1 => 2
3 => 4
7 => 8
9 => 10
5 => 6
!
1 => 2
3 => 4
7 => 8
9 => 10
5 => 6
5 => 6
9 => 10
7 => 8
3 => 4
1 => 2
!
7 => 8
3 => 4
5 => 6
1 => 2
9 => 10
!
9 => 10
1 => 2
3 => 4
7 => 8
5 => 6
$ perl -wE 'my %h = 1 .. 10; say "$_ => $h{$_}" for keys %h'
What if order matters?
# MongoDB

$db->run_command(

{ insert => $collection, … }

);







# some web apps

http://example.com/?p1=one&p2=two
Order isn’t free
• Arrays of pairs — no quick random access!
• Objects — method call overhead!
• Tied hashes — tie + method overhead
Tie::IxHash?
# Tie interface
$t = tie( %myhash, ‘Tie::IxHash’,
first => 1, second => 2
);
$myhash{third} = 3;
say $myhash{first};
!
# OO interface
$t = Tie::IxHash->new(
first => 1, second => 2
);
$t->Push(third => 3);
say $t->FETCH(‘third’);
Tie::IxHash problems
• tied!! → very slow!
• OO ! → ugly (“FETCH”)!
• OO ! → expensive copy!
• OO ! → no iterator
Maybe I could patch it
Tie::IxHash guts
sub TIEHASH {
my($c) = shift;
my($s) = [];
$s->[0] = {}; # hashkey index
$s->[1] = []; # array of keys
$s->[2] = []; # array of data
$s->[3] = 0; # iter count
bless $s, $c;
$s->Push(@_) if @_;
return $s;
}
sub TIEHASH {
my($c) = shift;
my($s) = [];
$s->[0] = {}; # hashkey index
$s->[1] = []; # array of keys
$s->[2] = []; # array of data
$s->[3] = 0; # iter count
bless $s, $c;
$s->Push(@_) if @_;
return $s;
}
WTF???
Tie::IxHash->new( a=>1, b=>2, c=>3, d=>4 );
sub FETCH {
my($s, $k) = (shift, shift);
return exists( $s->[0]{$k} ) ? $s->[2][ $s->[0]{$k} ] : undef;
}
Expensive fetch
• exists call!
• ternary op!
• 6 dereferences!
sub STORE {
my($s, $k, $v) = (shift, shift, shift);
if (exists $s->[0]{$k}) {
my($i) = $s->[0]{$k};
$s->[1][$i] = $k;
$s->[2][$i] = $v;
$s->[0]{$k} = $i;
}
else {
push(@{$s->[1]}, $k);
push(@{$s->[2]}, $v);
$s->[0]{$k} = $#{$s->[1]};
}
}
Expensive store
sub STORE {
my($s, $k, $v) = (shift, shift, shift);
if (exists $s->[0]{$k}) {
my($i) = $s->[0]{$k};
$s->[1][$i] = $k;
$s->[2][$i] = $v;
$s->[0]{$k} = $i;
}
else {
push(@{$s->[1]}, $k);
push(@{$s->[2]}, $v);
$s->[0]{$k} = $#{$s->[1]};
}
}
Anyone notice this?
Alternatives?
Tie::LLHash
tie %h, "Tie::LLHash", a=>1, b=>2, c=>3, d=>4;
sub last {
my $self = shift;
!
if (@_) { # Set it
my $newkey = shift;
my $newvalue = shift;
!
croak ("'$newkey' already exists") if $self->EXISTS($newkey);
!
# Create the new node
$self->{'nodes'}{$newkey} =
{
'next' => undef,
'value' => $newvalue,
'prev' => undef,
};
!
# Put it in its relative place
if (defined $self->{'last'}) {
$self->{'nodes'}{$newkey}{'prev'} = $self->{'last'};
$self->{'nodes'}{ $self->{'last'} }{'next'} = $newkey;
}
!
# Finally, make this node the last node
$self->{'last'} = $newkey;
!
# If this is an empty hash, make it the first node too
$self->{'first'} = $newkey unless (defined $self->{'first'});
}
Memory allocation per key!
Array::AsHash
Array::AsHash->new({array =>[a=>1,b=>2,c=>3,d=>4]});
sub get {
my ( $self, @keys ) = @_;
my @get;
foreach my $key (@keys) {
$key = $self->$_actual_key($key);
next unless defined $key;
my $exists = $self->exists($key);
if ( $self->{is_strict} && !$exists ) {
$self->$_croak("Cannot get non-existent key ($key)");
}
if ($exists) {
CORE::push @get, $self->{array_for}[ $self->$_index($key) + 1 ];
}
elsif ( @keys > 1 ) {
CORE::push @get, undef;
}
else {
return;
}
}
return wantarray ? @get
: @keys > 1 ? @get
: $get[0];
}
!
my $_actual_key = sub {
my ( $self, $key ) = @_;
if ( ref $key ) {
my $new_key = $self->{curr_key_of}{ refaddr $key};
return refaddr $key unless defined $new_key;
$key = $new_key;
}
return $key;
};
Subroutine call per key!
sub get {
my ( $self, @keys ) = @_;
my @get;
foreach my $key (@keys) {
$key = $self->$_actual_key($key);
next unless defined $key;
my $exists = $self->exists($key);
if ( $self->{is_strict} && !$exists ) {
$self->$_croak("Cannot get non-existent key ($key)");
}
if ($exists) {
CORE::push @get, $self->{array_for}[ $self->$_index($key) + 1 ];
}
elsif ( @keys > 1 ) {
CORE::push @get, undef;
}
else {
return;
}
}
return wantarray ? @get
: @keys > 1 ? @get
: $get[0];
}
!
my $_actual_key = sub {
my ( $self, $key ) = @_;
if ( ref $key ) {
my $new_key = $self->{curr_key_of}{ refaddr $key};
return refaddr $key unless defined $new_key;
$key = $new_key;
}
return $key;
};
Single key fetch overhead!
Tie::Hash::Indexed
XS, but flawed
• Opaque data: Perl hash of doubly-linked list
of C structs !
• Fails tests since Perl 5.18 randomization!
• Actually, not all that fast (benchmarks later)
What else?
Special-purpose or weird
• Tie::Array::AsHash — array elements split with separator; tie API only!
• Tie::Hash::Array — ordered alphabetically; tie API only!
• Tie::InsertOrderHash — ordered by insertion; tie API only!
• Tie::StoredOrderHash — ordered by last update; tie API only!
• Array::Assign — arrays with named access; restricted keys!
• Array::OrdHash — overloads array/hash deref and uses internal tied data!
• Data::Pairs — array of key-value hashrefs; allows duplicate keys!
• Data::OMap — array of key-value hashrefs; no duplicate keys!
• Data::XHash — blessed, tied hashref with doubly-linked-list!
!
Complexity → Bad
What is the simplest
thing that could work?
• Hash of keys and values!
• Array of key order
bless { {a=>1, b=>2}, [‘a’, ‘b’] }
I couldn’t find it on CPAN
So I wrote it
Hash::Ordered
Hash::Ordered->new(a=>1,b=>2,c=>3,d=>4);
sub get {
my ( $self, $key ) = @_;
return $self->[_DATA]{$key};
}
Cheap get
• only 2 dereferences!
• no need to test exists()
sub set {
my ( $self, $key, $value ) = @_;
if ( !exists $self->[_DATA]{$key} ) {
push @{ $self->[_KEYS] }, $key;
}
return $self->[_DATA]{$key} = $value;
}
Cheap-ish set
• exists plus 4-6 dereferences and maybe push!
• comparable toTie::IxHash::FETCH
sub clone {
my ( $self, @keys ) = @_;
my $clone;
if (@keys) {
my %subhash;
@subhash{@keys} = @{ $self->[_DATA] }{@keys};
$clone = [ %subhash, @keys ];
}
else {
$clone = [ { %{ $self->[_DATA] } }, [ @{ $self->[_KEYS] } ] ];
}
return bless $clone, ref $self;
}
Got my shallow copy
sub iterator {
my ( $self, @keys ) = @_;
@keys = @{ $self->[_KEYS] } unless @keys;
my $data = $self->[_DATA];
return sub {
return unless @keys;
my $key = CORE::shift(@keys);
return ( $key => $data->{$key} );
};
}
Got my iterator
sub delete {
my ( $self, $key ) = @_;
if ( exists $self->[_DATA]{$key} ) {
my $r = $self->[_KEYS];
my $i = List::Util::first { $r->[$_] eq $key } 0 .. $#$r;
splice @$r, $i, 1;
return delete $self->[_DATA]{$key};
}
return undef;
}
But, delete is expensive
Good tradeoffs?
• It’s ::Tiny — only about 130 SLOC!
• Faster get and set!
• Faster copy!
• Slower delete
But is it actually fast?
Benchmarking is

not profiling
Profiling!! ! ! → ! finding hot spots in code!
Benchmarking! → ! comparing different code

! ! ! ! ! ! ! ! to do the same thing
Scale can reveal ‘Big-O’
issues in algorithms
Constants matter!
even for O(1)
Combinations
• Different ordered hash modules!
• Different operations (create, get, set)!
• Different scales (10, 100, 1000 elements)
Benchmarking tools
• Benchmark.pm!
• Dumbbench!
• Other stuff on CPAN
Don’t make timing
distribution assumptions
Kolmogorov–Smirnov test
• Compare empirical CDFs!
• Non-parametric!
• Unequal-variance!
• Sensitive to CDF location and shape
Doesn’t exist on CPAN
I haven’t written it
yet
KISS → Benchmark.pm
Benchmark: running a, b, each for at least 5 CPU seconds...
a: 10 wallclock secs ( 5.14 usr + 0.13 sys = 5.27 CPU) @ 3835055.60/s (n=20210743)
b: 5 wallclock secs ( 5.41 usr + 0.00 sys = 5.41 CPU) @ 1574944.92/s (n=8520452)
Rate b a
b 1574945/s -- -59%
a 3835056/s 144% --
Benchmark.pm is verbose
!
• Big test matrix is unreadable!
• Lots of detail I don’t care about
Approach
• Given a hash of test labels and code refs!
• Output timings in descending order!
• Repeat at different scales
use Benchmark qw( countit );
!
use constant COUNT => 5; # CPU seconds
!
sub time_them {
my (%mark) = @_;
my %results;
!
for my $k ( sort keys %mark ) {
my $res = countit( COUNT, $mark{$k} );
my $iter_s = $res->iters / ( $res->cpu_a + 1e-9 );
$results{$k} = $iter_s;
}
!
printf( "%20s %d/sn", $_, $results{$_} )
for sort { $results{$b} <=> $results{$a} }
keys %results;
!
say "";
}
Use varied, but constant!
test data across runs
use Math::Random::MT::Auto qw/irand/;
!
use constant NUMS => [ 10, 100, 1000 ];
!
my %PAIRS = (
map {
$_ => [ map { irand() => irand() } 1 .. $_ ]
} @{ NUMS() }
);
for my $size ( @{ NUMS() } ) {
!
say my $title = "Results for ordered hash creation for $size elements";
!
my %mark;
!
$mark{"h:o"} = sub { my $h = Hash::Ordered->new( @{ $PAIRS{$size} } ) };
!
$mark{"t:ix_oo"} = sub { my $h = Tie::IxHash->new( @{ $PAIRS{$size} } ) };
!
$mark{"t:ix_th"} = sub { tie my %h, 'Tie::IxHash', @{ $PAIRS{$size} } };
!
$mark{"t:llh"} = sub { tie my %h, 'Tie::LLHash', @{ $PAIRS{$size} } };
!
# …
!
time_them(%mark);
!
}
Example: hash creation
for my $size ( @{ NUMS() } ) {
!
say my $title = "Results for ordered hash creation for $size elements";
!
my %mark;
!
$mark{"h:o"} = sub { my $h = Hash::Ordered->new( @{ $PAIRS{$size} } ) };
!
$mark{"t:ix_oo"} = sub { my $h = Tie::IxHash->new( @{ $PAIRS{$size} } ) };
!
$mark{"t:ix_th"} = sub { tie my %h, 'Tie::IxHash', @{ $PAIRS{$size} } };
!
$mark{"t:llh"} = sub { tie my %h, 'Tie::LLHash', @{ $PAIRS{$size} } };
!
# …
!
time_them(%mark);
!
}
Includes variations
for my $size ( @{ NUMS() } ) {
!
say my $title = "Results for fetching ~10% of $size elements";
!
my $oh = Hash::Ordered->new( @{ $PAIRS{$size} } );
my $tix_oo = Tie::IxHash->new( @{ $PAIRS{$size} } );
tie my %tix_th, 'Tie::IxHash', @{ $PAIRS{$size} };
tie my %tllh, 'Tie::LLHash', @{ $PAIRS{$size} };
# …
!
my ( %mark, $v );
my @keys = keys %{ { @{ $PAIRS{$size} } } };
!
my $n = int( .1 * scalar @keys ) || 1;
my @lookup = map { $keys[ int( rand( scalar @keys ) ) ] } 1 .. $n;
!
$mark{"h:o"} = sub { $v = $oh->get($_) for @lookup };
$mark{"t:ix_oo"} = sub { $v = $tix_oo->FETCH($_) for @lookup };
$mark{"t:ix_th"} = sub { $v = $tix_th{$_} for @lookup };
$mark{"t:llh"} = sub { $v = $tllh{$_} for @lookup };
# …
!
time_them(%mark);
}
!
Example: fetch elements
for my $size ( @{ NUMS() } ) {
!
say my $title = "Results for fetching ~10% of $size elements";
!
my $oh = Hash::Ordered->new( @{ $PAIRS{$size} } );
my $tix_oo = Tie::IxHash->new( @{ $PAIRS{$size} } );
tie my %tix_th, 'Tie::IxHash', @{ $PAIRS{$size} };
tie my %tllh, 'Tie::LLHash', @{ $PAIRS{$size} };
# …
!
my ( %mark, $v );
my @keys = keys %{ { @{ $PAIRS{$size} } } };
!
my $n = int( .1 * scalar @keys ) || 1;
my @lookup = map { $keys[ int( rand( scalar @keys ) ) ] } 1 .. $n;
!
$mark{"h:o"} = sub { $v = $oh->get($_) for @lookup };
$mark{"t:ix_oo"} = sub { $v = $tix_oo->FETCH($_) for @lookup };
$mark{"t:ix_th"} = sub { $v = $tix_th{$_} for @lookup };
$mark{"t:llh"} = sub { $v = $tllh{$_} for @lookup };
# …
!
time_them(%mark);
}
!
Pre-generates hashes
for my $size ( @{ NUMS() } ) {
!
say my $title = "Results for fetching ~10% of $size elements";
!
my $oh = Hash::Ordered->new( @{ $PAIRS{$size} } );
my $tix_oo = Tie::IxHash->new( @{ $PAIRS{$size} } );
tie my %tix_th, 'Tie::IxHash', @{ $PAIRS{$size} };
tie my %tllh, 'Tie::LLHash', @{ $PAIRS{$size} };
# …
!
my ( %mark, $v );
my @keys = keys %{ { @{ $PAIRS{$size} } } };
!
my $n = int( .1 * scalar @keys ) || 1;
my @lookup = map { $keys[ int( rand( scalar @keys ) ) ] } 1 .. $n;
!
$mark{"h:o"} = sub { $v = $oh->get($_) for @lookup };
$mark{"t:ix_oo"} = sub { $v = $tix_oo->FETCH($_) for @lookup };
$mark{"t:ix_th"} = sub { $v = $tix_th{$_} for @lookup };
$mark{"t:llh"} = sub { $v = $tllh{$_} for @lookup };
# …
!
time_them(%mark);
}
!
Pre-generates test keys
for my $size ( @{ NUMS() } ) {
!
say my $title = "Results for fetching ~10% of $size elements";
!
my $oh = Hash::Ordered->new( @{ $PAIRS{$size} } );
my $tix_oo = Tie::IxHash->new( @{ $PAIRS{$size} } );
tie my %tix_th, 'Tie::IxHash', @{ $PAIRS{$size} };
tie my %tllh, 'Tie::LLHash', @{ $PAIRS{$size} };
# …
!
my ( %mark, $v );
my @keys = keys %{ { @{ $PAIRS{$size} } } };
!
my $n = int( .1 * scalar @keys ) || 1;
my @lookup = map { $keys[ int( rand( scalar @keys ) ) ] } 1 .. $n;
!
$mark{"h:o"} = sub { $v = $oh->get($_) for @lookup };
$mark{"t:ix_oo"} = sub { $v = $tix_oo->FETCH($_) for @lookup };
$mark{"t:ix_th"} = sub { $v = $tix_th{$_} for @lookup };
$mark{"t:llh"} = sub { $v = $tllh{$_} for @lookup };
# …
!
time_them(%mark);
}
!
Benchmark just the fetch
for my $size ( @{ NUMS() } ) {
!
say my $title = "Results for creating $size element hash then deleting ~10%";
!
my ( %mark, $v );
my @keys = keys %{ { @{ $PAIRS{$size} } } };
!
my $n = int( .1 * scalar @keys ) || 1;
my @lookup = map { $keys[ int( rand( scalar @keys ) ) ] } 1 .. $n;
!
$mark{"h:o"} = sub {
my $oh = Hash::Ordered->new( @{ $PAIRS{$size} } );
$oh->delete($_) for @lookup;
};
!
$mark{"t:ix_oo"} = sub {
my $tix_oo = Tie::IxHash->new( @{ $PAIRS{$size} } );
$tix_oo->DELETE($_) for @lookup;
};
!
# …
!
time_them(%mark);
}
!
Example: deleting elements
for my $size ( @{ NUMS() } ) {
!
say my $title = "Results for creating $size element hash then deleting ~10%";
!
my ( %mark, $v );
my @keys = keys %{ { @{ $PAIRS{$size} } } };
!
my $n = int( .1 * scalar @keys ) || 1;
my @lookup = map { $keys[ int( rand( scalar @keys ) ) ] } 1 .. $n;
!
$mark{"h:o"} = sub {
my $oh = Hash::Ordered->new( @{ $PAIRS{$size} } );
$oh->delete($_) for @lookup;
};
!
$mark{"t:ix_oo"} = sub {
my $tix_oo = Tie::IxHash->new( @{ $PAIRS{$size} } );
$tix_oo->DELETE($_) for @lookup;
};
!
# …
!
time_them(%mark);
}
!
But, we can’t isolate delete
Results…
https://www.flickr.com/photos/tarikb/111831472/
Don’t web-surf while
benchmarking!
Modules & abbreviations
• Hash::Ordered ! ! → h:o! ! [data hash + keys array]!
!
• Array::AsHash ! ! → a:ah! ! [data array + index hash]!
!
• Tie::IxHash ! ! ! → t:ix! ! [tie + hash + 2 x array]!
!
• Tie::LLHash ! ! ! → t:llh! ! [tie + hash + 2LL]!
!
• Tie::Hash::Indexed !! → t:h:i! ! [XS + tie + hash + 2LL]!
!
• Array::OrdHash! ! → a:oh!! [overloaded + private ties]!
!
• Data::XHash! ! ! → d:xh!! [tie + double linked list]!
!
Creation
10 elements 100 elements 1000 elements
t:h:i 129713/s
a:ah_rf 104034/s
h:o 94121/s
a:ah_cp 62539/s
t:ix_th 60136/s
t:ix_oo 59895/s
a:oh 49399/s
t:llh 32122/s
d:xh_rf 13288/s
d:xh_ls 13223/s
t:h:i 15026/s
a:ah_rf 14304/s
h:o 10931/s
a:ah_cp 7512/s
t:ix_oo 7368/s
t:ix_th 7161/s
a:oh 6572/s
t:llh 3306/s
d:xh_ls 1498/s
d:xh_rf 1491/s
a:ah_rf 1410/s
t:h:i 1285/s
h:o 1022/s
a:ah_cp 763/s
t:ix_oo 703/s
t:ix_th 697/s
a:oh 694/s
t:llh 290/s
d:xh_rf 147/s
d:xh_ls 146/s
Fetch 10% of elements
10 elements 100 elements 1000 elements
h:o 1417712/s
d:xh_oo 1231973/s
t:ix_oo 1120271/s
t:h:i 792250/s
d:xh_rf 722683/s
t:ix_th 624603/s
a:oh 553755/s
t:llh 504533/s
a:ah 246063/s
h:o 244800/s
d:xh_oo 181520/s
t:ix_oo 175981/s
t:h:i 132963/s
d:xh_rf 93519/s
t:ix_th 82154/s
a:oh 68270/s
t:llh 57013/s
a:ah 28280/s
h:o 24871/s
d:xh_oo 19125/s
t:ix_oo 17655/s
t:h:i 13407/s
d:xh_rf 9590/s
t:ix_th 8455/s
a:oh 6995/s
t:llh 5781/s
a:ah 2219/s
Set 10% of elements
10 elements 100 elements 1000 elements
h:o 1353795/s
d:xh_oo 952485/s
t:h:i 943983/s
t:ix_oo 923874/s
t:llh 600717/s
d:xh_rf 568693/s
a:oh 547233/s
t:ix_th 519939/s
a:ah 164170/s
h:o 197232/s
t:h:i 131238/s
d:xh_oo 121692/s
t:ix_oo 114869/s
t:llh 71720/s
d:xh_rf 67130/s
a:oh 63634/s
t:ix_th 59784/s
a:ah 16843/s
h:o 20364/s
t:h:i 13254/s
d:xh_oo 12512/s
t:ix_oo 11542/s
t:llh 7295/s
d:xh_rf 7004/s
a:oh 6376/s
t:ix_th 6175/s
a:ah 1635/s
Adding elements to empty
10 elements 100 elements 1000 elements
h:o 367588/s
t:h:i 300357/s
t:ix_oo 263158/s
t:ix_th 214085/s
t:llh 187981/s
a:oh 141308/s
a:ah 96523/s
d:xh_oo 87498/s
d:xh_rf 84316/s
h:o 66495/s
t:h:i 57307/s
t:ix_oo 49676/s
t:ix_th 38222/s
a:oh 35476/s
t:llh 27998/s
d:xh_oo 24371/s
d:xh_rf 22326/s
a:ah 14114/s
h:o 7217/s
t:h:i 6244/s
t:ix_oo 5671/s
a:oh 4335/s
t:ix_th 4313/s
d:xh_oo 2977/s
t:llh 2899/s
d:xh_rf 2683/s
a:ah 1466/s
Deleting* 10% of keys
10 elements 100 elements 1000 elements
t:h:i 139517/s
h:o 95284/s
a:ah 66495/s
t:ix_oo 52892/s
t:ix_th 50254/s
a:oh 45609/s
t:llh 28599/s
d:xh_rf 13223/s
d:xh_oo 13173/s
t:h:i 16745/s
h:o 6924/s
t:ix_oo 4063/s
a:oh 3963/s
t:ix_th 3590/s
a:ah 3014/s
t:llh 2459/s
d:xh_oo 1449/s
d:xh_rf 1434/s
t:h:i 1604/s
t:llh 269/s
a:oh 171/s
d:xh_rf 146/s
h:o 144/s
d:xh_oo 130/s
t:ix_oo 85/s
t:ix_th 77/s
a:ah 36/s
Output hash as a list
10 elements 100 elements 1000 elements
a:ah 290725/s
h:o 170187/s
t:ix_oo 92118/s
t:h:i 80408/s
t:ix_th 48756/s
t:llh 38509/s
a:oh 36126/s
d:xh 35766/s
a:ah 39222/s
h:o 18839/s
t:ix_oo 9525/s
t:h:i 7742/s
a:oh 5081/s
t:ix_th 5014/s
d:xh 4160/s
t:llh 3841/s
a:ah 3703/s
h:o 1877/s
t:ix_oo 961/s
t:h:i 768/s
a:oh 508/s
t:ix_th 505/s
d:xh 413/s
t:llh 385/s
Conclusions…
Tying sucks
Module choice matters a lot
• 7 CPAN modules tested!
• 10x performance difference on some tasks!
• Look inside modules before you use them!
Simplicity pays off
• Less indirection!
• Less memory allocation!
• Fewer ops per call
Hash::Ordered::XS!
might really rock!
Questions?

More Related Content

What's hot

PHP Language Trivia
PHP Language TriviaPHP Language Trivia
PHP Language TriviaNikita Popov
 
An Elephant of a Different Colour: Hack
An Elephant of a Different Colour: HackAn Elephant of a Different Colour: Hack
An Elephant of a Different Colour: HackVic Metcalfe
 
The Perl6 Type System
The Perl6 Type SystemThe Perl6 Type System
The Perl6 Type Systemabrummett
 
DBIx::Class introduction - 2010
DBIx::Class introduction - 2010DBIx::Class introduction - 2010
DBIx::Class introduction - 2010leo lapworth
 
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Masahiro Nagano
 
The Joy of Smartmatch
The Joy of SmartmatchThe Joy of Smartmatch
The Joy of SmartmatchAndrew Shitov
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Kris Wallsmith
 
Text in search queries with examples in Perl 6
Text in search queries with examples in Perl 6Text in search queries with examples in Perl 6
Text in search queries with examples in Perl 6Andrew Shitov
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP GeneratorsMark Baker
 
Models and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsRoss Tuck
 
Command Bus To Awesome Town
Command Bus To Awesome TownCommand Bus To Awesome Town
Command Bus To Awesome TownRoss Tuck
 
Things I Believe Now That I'm Old
Things I Believe Now That I'm OldThings I Believe Now That I'm Old
Things I Believe Now That I'm OldRoss Tuck
 
Refactor like a boss
Refactor like a bossRefactor like a boss
Refactor like a bossgsterndale
 
PHP 7 – What changed internally? (PHP Barcelona 2015)
PHP 7 – What changed internally? (PHP Barcelona 2015)PHP 7 – What changed internally? (PHP Barcelona 2015)
PHP 7 – What changed internally? (PHP Barcelona 2015)Nikita Popov
 
Introduction to Perl
Introduction to PerlIntroduction to Perl
Introduction to Perlworr1244
 
New SPL Features in PHP 5.3
New SPL Features in PHP 5.3New SPL Features in PHP 5.3
New SPL Features in PHP 5.3Matthew Turland
 
(Parameterized) Roles
(Parameterized) Roles(Parameterized) Roles
(Parameterized) Rolessartak
 

What's hot (20)

PHP Language Trivia
PHP Language TriviaPHP Language Trivia
PHP Language Trivia
 
Nubilus Perl
Nubilus PerlNubilus Perl
Nubilus Perl
 
An Elephant of a Different Colour: Hack
An Elephant of a Different Colour: HackAn Elephant of a Different Colour: Hack
An Elephant of a Different Colour: Hack
 
Neatly folding-a-tree
Neatly folding-a-treeNeatly folding-a-tree
Neatly folding-a-tree
 
The Perl6 Type System
The Perl6 Type SystemThe Perl6 Type System
The Perl6 Type System
 
DBIx::Class introduction - 2010
DBIx::Class introduction - 2010DBIx::Class introduction - 2010
DBIx::Class introduction - 2010
 
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
 
The Joy of Smartmatch
The Joy of SmartmatchThe Joy of Smartmatch
The Joy of Smartmatch
 
Perl Web Client
Perl Web ClientPerl Web Client
Perl Web Client
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)
 
Text in search queries with examples in Perl 6
Text in search queries with examples in Perl 6Text in search queries with examples in Perl 6
Text in search queries with examples in Perl 6
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP Generators
 
Models and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and Hobgoblins
 
Command Bus To Awesome Town
Command Bus To Awesome TownCommand Bus To Awesome Town
Command Bus To Awesome Town
 
Things I Believe Now That I'm Old
Things I Believe Now That I'm OldThings I Believe Now That I'm Old
Things I Believe Now That I'm Old
 
Refactor like a boss
Refactor like a bossRefactor like a boss
Refactor like a boss
 
PHP 7 – What changed internally? (PHP Barcelona 2015)
PHP 7 – What changed internally? (PHP Barcelona 2015)PHP 7 – What changed internally? (PHP Barcelona 2015)
PHP 7 – What changed internally? (PHP Barcelona 2015)
 
Introduction to Perl
Introduction to PerlIntroduction to Perl
Introduction to Perl
 
New SPL Features in PHP 5.3
New SPL Features in PHP 5.3New SPL Features in PHP 5.3
New SPL Features in PHP 5.3
 
(Parameterized) Roles
(Parameterized) Roles(Parameterized) Roles
(Parameterized) Roles
 

Similar to Adventures in Optimization

Learning Perl 6 (NPW 2007)
Learning Perl 6 (NPW 2007)Learning Perl 6 (NPW 2007)
Learning Perl 6 (NPW 2007)brian d foy
 
Learning Perl 6
Learning Perl 6 Learning Perl 6
Learning Perl 6 brian d foy
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Kang-min Liu
 
Zend Certification Preparation Tutorial
Zend Certification Preparation TutorialZend Certification Preparation Tutorial
Zend Certification Preparation TutorialLorna Mitchell
 
Scripting3
Scripting3Scripting3
Scripting3Nao Dara
 
PHP Functions & Arrays
PHP Functions & ArraysPHP Functions & Arrays
PHP Functions & ArraysHenry Osborne
 
Php 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the GoodPhp 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the GoodJeremy Kendall
 
Creating a compiler in Perl 6
Creating a compiler in Perl 6Creating a compiler in Perl 6
Creating a compiler in Perl 6Andrew Shitov
 
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014Cliff Seal
 
php programming.pptx
php programming.pptxphp programming.pptx
php programming.pptxrani marri
 
Introduction à CoffeeScript pour ParisRB
Introduction à CoffeeScript pour ParisRB Introduction à CoffeeScript pour ParisRB
Introduction à CoffeeScript pour ParisRB jhchabran
 
The Magic Of Tie
The Magic Of TieThe Magic Of Tie
The Magic Of Tiebrian d foy
 
Hidden treasures of Ruby
Hidden treasures of RubyHidden treasures of Ruby
Hidden treasures of RubyTom Crinson
 
Php tips-and-tricks4128
Php tips-and-tricks4128Php tips-and-tricks4128
Php tips-and-tricks4128PrinceGuru MS
 

Similar to Adventures in Optimization (20)

Learning Perl 6 (NPW 2007)
Learning Perl 6 (NPW 2007)Learning Perl 6 (NPW 2007)
Learning Perl 6 (NPW 2007)
 
Learning Perl 6
Learning Perl 6 Learning Perl 6
Learning Perl 6
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
 
Zend Certification Preparation Tutorial
Zend Certification Preparation TutorialZend Certification Preparation Tutorial
Zend Certification Preparation Tutorial
 
Scripting3
Scripting3Scripting3
Scripting3
 
PHP Functions & Arrays
PHP Functions & ArraysPHP Functions & Arrays
PHP Functions & Arrays
 
Perl object ?
Perl object ?Perl object ?
Perl object ?
 
Php 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the GoodPhp 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the Good
 
Modern Perl
Modern PerlModern Perl
Modern Perl
 
Creating a compiler in Perl 6
Creating a compiler in Perl 6Creating a compiler in Perl 6
Creating a compiler in Perl 6
 
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014
 
php programming.pptx
php programming.pptxphp programming.pptx
php programming.pptx
 
PHP and MySQL
PHP and MySQLPHP and MySQL
PHP and MySQL
 
Introduction à CoffeeScript pour ParisRB
Introduction à CoffeeScript pour ParisRB Introduction à CoffeeScript pour ParisRB
Introduction à CoffeeScript pour ParisRB
 
The Magic Of Tie
The Magic Of TieThe Magic Of Tie
The Magic Of Tie
 
PHP PPT FILE
PHP PPT FILEPHP PPT FILE
PHP PPT FILE
 
wget.pl
wget.plwget.pl
wget.pl
 
Hidden treasures of Ruby
Hidden treasures of RubyHidden treasures of Ruby
Hidden treasures of Ruby
 
Web 8 | Introduction to PHP
Web 8 | Introduction to PHPWeb 8 | Introduction to PHP
Web 8 | Introduction to PHP
 
Php tips-and-tricks4128
Php tips-and-tricks4128Php tips-and-tricks4128
Php tips-and-tricks4128
 

More from David Golden

Slice Recycling Performance and Pitfalls
Slice Recycling Performance and PitfallsSlice Recycling Performance and Pitfalls
Slice Recycling Performance and PitfallsDavid Golden
 
Eversion 101: An Introduction to Inside-Out Objects
Eversion 101: An Introduction to Inside-Out ObjectsEversion 101: An Introduction to Inside-Out Objects
Eversion 101: An Introduction to Inside-Out ObjectsDavid Golden
 
One BSON to Rule Them
One BSON to Rule ThemOne BSON to Rule Them
One BSON to Rule ThemDavid Golden
 
Make Comments Stand Out
Make Comments Stand OutMake Comments Stand Out
Make Comments Stand OutDavid Golden
 
State of the Velociraptor Mini-Keynote: Perl Toolchain
State of the Velociraptor Mini-Keynote: Perl ToolchainState of the Velociraptor Mini-Keynote: Perl Toolchain
State of the Velociraptor Mini-Keynote: Perl ToolchainDavid Golden
 
Practical Consistency
Practical ConsistencyPractical Consistency
Practical ConsistencyDavid Golden
 
How I get to the ☞
How I get to the ☞How I get to the ☞
How I get to the ☞David Golden
 
Real World Optimization
Real World OptimizationReal World Optimization
Real World OptimizationDavid Golden
 
Safer Chainsaw Juggling (Lightning Talk)
Safer Chainsaw Juggling (Lightning Talk)Safer Chainsaw Juggling (Lightning Talk)
Safer Chainsaw Juggling (Lightning Talk)David Golden
 
Taking Perl to Eleven with Higher-Order Functions
Taking Perl to Eleven with Higher-Order FunctionsTaking Perl to Eleven with Higher-Order Functions
Taking Perl to Eleven with Higher-Order FunctionsDavid Golden
 
Juggling Chainsaws: Perl and MongoDB
Juggling Chainsaws: Perl and MongoDBJuggling Chainsaws: Perl and MongoDB
Juggling Chainsaws: Perl and MongoDBDavid Golden
 
Cooking Perl with Chef: Real World Tutorial with Jitterbug
Cooking Perl with Chef: Real World Tutorial with JitterbugCooking Perl with Chef: Real World Tutorial with Jitterbug
Cooking Perl with Chef: Real World Tutorial with JitterbugDavid Golden
 
Cooking Perl with Chef: Hello World Tutorial
Cooking Perl with Chef: Hello World TutorialCooking Perl with Chef: Hello World Tutorial
Cooking Perl with Chef: Hello World TutorialDavid Golden
 
Cooking Perl with Chef
Cooking Perl with ChefCooking Perl with Chef
Cooking Perl with ChefDavid Golden
 

More from David Golden (17)

Slice Recycling Performance and Pitfalls
Slice Recycling Performance and PitfallsSlice Recycling Performance and Pitfalls
Slice Recycling Performance and Pitfalls
 
Free QA!
Free QA!Free QA!
Free QA!
 
Eversion 101: An Introduction to Inside-Out Objects
Eversion 101: An Introduction to Inside-Out ObjectsEversion 101: An Introduction to Inside-Out Objects
Eversion 101: An Introduction to Inside-Out Objects
 
Perl 5 Version 13
Perl 5 Version 13Perl 5 Version 13
Perl 5 Version 13
 
IsTrue(true)?
IsTrue(true)?IsTrue(true)?
IsTrue(true)?
 
One BSON to Rule Them
One BSON to Rule ThemOne BSON to Rule Them
One BSON to Rule Them
 
Make Comments Stand Out
Make Comments Stand OutMake Comments Stand Out
Make Comments Stand Out
 
State of the Velociraptor Mini-Keynote: Perl Toolchain
State of the Velociraptor Mini-Keynote: Perl ToolchainState of the Velociraptor Mini-Keynote: Perl Toolchain
State of the Velociraptor Mini-Keynote: Perl Toolchain
 
Practical Consistency
Practical ConsistencyPractical Consistency
Practical Consistency
 
How I get to the ☞
How I get to the ☞How I get to the ☞
How I get to the ☞
 
Real World Optimization
Real World OptimizationReal World Optimization
Real World Optimization
 
Safer Chainsaw Juggling (Lightning Talk)
Safer Chainsaw Juggling (Lightning Talk)Safer Chainsaw Juggling (Lightning Talk)
Safer Chainsaw Juggling (Lightning Talk)
 
Taking Perl to Eleven with Higher-Order Functions
Taking Perl to Eleven with Higher-Order FunctionsTaking Perl to Eleven with Higher-Order Functions
Taking Perl to Eleven with Higher-Order Functions
 
Juggling Chainsaws: Perl and MongoDB
Juggling Chainsaws: Perl and MongoDBJuggling Chainsaws: Perl and MongoDB
Juggling Chainsaws: Perl and MongoDB
 
Cooking Perl with Chef: Real World Tutorial with Jitterbug
Cooking Perl with Chef: Real World Tutorial with JitterbugCooking Perl with Chef: Real World Tutorial with Jitterbug
Cooking Perl with Chef: Real World Tutorial with Jitterbug
 
Cooking Perl with Chef: Hello World Tutorial
Cooking Perl with Chef: Hello World TutorialCooking Perl with Chef: Hello World Tutorial
Cooking Perl with Chef: Hello World Tutorial
 
Cooking Perl with Chef
Cooking Perl with ChefCooking Perl with Chef
Cooking Perl with Chef
 

Recently uploaded

Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension AidPhilip Schwarz
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplatePresentation.STUDIO
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...kalichargn70th171
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesVictorSzoltysek
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfVishalKumarJha10
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdfPearlKirahMaeRagusta1
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfproinshot.com
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
How to Choose the Right Laravel Development Partner in New York City_compress...
How to Choose the Right Laravel Development Partner in New York City_compress...How to Choose the Right Laravel Development Partner in New York City_compress...
How to Choose the Right Laravel Development Partner in New York City_compress...software pro Development
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionOnePlan Solutions
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 

Recently uploaded (20)

Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
How to Choose the Right Laravel Development Partner in New York City_compress...
How to Choose the Right Laravel Development Partner in New York City_compress...How to Choose the Right Laravel Development Partner in New York City_compress...
How to Choose the Right Laravel Development Partner in New York City_compress...
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 

Adventures in Optimization

  • 1. Adventures in Optimization David Golden • @xdg! NY.pm • July 2014
  • 4. Perl hashes are random
 unordered maps
  • 5. Perl 5.16 Perl 5.18 1 => 2 3 => 4 7 => 8 9 => 10 5 => 6 ! 1 => 2 3 => 4 7 => 8 9 => 10 5 => 6 ! 1 => 2 3 => 4 7 => 8 9 => 10 5 => 6 5 => 6 9 => 10 7 => 8 3 => 4 1 => 2 ! 7 => 8 3 => 4 5 => 6 1 => 2 9 => 10 ! 9 => 10 1 => 2 3 => 4 7 => 8 5 => 6 $ perl -wE 'my %h = 1 .. 10; say "$_ => $h{$_}" for keys %h'
  • 6. Perl 5.16 Perl 5.18 1 => 2 3 => 4 7 => 8 9 => 10 5 => 6 ! 1 => 2 3 => 4 7 => 8 9 => 10 5 => 6 ! 1 => 2 3 => 4 7 => 8 9 => 10 5 => 6 5 => 6 9 => 10 7 => 8 3 => 4 1 => 2 ! 7 => 8 3 => 4 5 => 6 1 => 2 9 => 10 ! 9 => 10 1 => 2 3 => 4 7 => 8 5 => 6 $ perl -wE 'my %h = 1 .. 10; say "$_ => $h{$_}" for keys %h'
  • 7. Perl 5.16 Perl 5.18 1 => 2 3 => 4 7 => 8 9 => 10 5 => 6 ! 1 => 2 3 => 4 7 => 8 9 => 10 5 => 6 ! 1 => 2 3 => 4 7 => 8 9 => 10 5 => 6 5 => 6 9 => 10 7 => 8 3 => 4 1 => 2 ! 7 => 8 3 => 4 5 => 6 1 => 2 9 => 10 ! 9 => 10 1 => 2 3 => 4 7 => 8 5 => 6 $ perl -wE 'my %h = 1 .. 10; say "$_ => $h{$_}" for keys %h'
  • 8. What if order matters?
  • 9. # MongoDB
 $db->run_command(
 { insert => $collection, … }
 );
 
 
 
 # some web apps
 http://example.com/?p1=one&p2=two
  • 10. Order isn’t free • Arrays of pairs — no quick random access! • Objects — method call overhead! • Tied hashes — tie + method overhead
  • 12. # Tie interface $t = tie( %myhash, ‘Tie::IxHash’, first => 1, second => 2 ); $myhash{third} = 3; say $myhash{first}; ! # OO interface $t = Tie::IxHash->new( first => 1, second => 2 ); $t->Push(third => 3); say $t->FETCH(‘third’);
  • 13. Tie::IxHash problems • tied!! → very slow! • OO ! → ugly (“FETCH”)! • OO ! → expensive copy! • OO ! → no iterator
  • 14. Maybe I could patch it
  • 15. Tie::IxHash guts sub TIEHASH { my($c) = shift; my($s) = []; $s->[0] = {}; # hashkey index $s->[1] = []; # array of keys $s->[2] = []; # array of data $s->[3] = 0; # iter count bless $s, $c; $s->Push(@_) if @_; return $s; }
  • 16. sub TIEHASH { my($c) = shift; my($s) = []; $s->[0] = {}; # hashkey index $s->[1] = []; # array of keys $s->[2] = []; # array of data $s->[3] = 0; # iter count bless $s, $c; $s->Push(@_) if @_; return $s; } WTF???
  • 18. sub FETCH { my($s, $k) = (shift, shift); return exists( $s->[0]{$k} ) ? $s->[2][ $s->[0]{$k} ] : undef; } Expensive fetch • exists call! • ternary op! • 6 dereferences!
  • 19. sub STORE { my($s, $k, $v) = (shift, shift, shift); if (exists $s->[0]{$k}) { my($i) = $s->[0]{$k}; $s->[1][$i] = $k; $s->[2][$i] = $v; $s->[0]{$k} = $i; } else { push(@{$s->[1]}, $k); push(@{$s->[2]}, $v); $s->[0]{$k} = $#{$s->[1]}; } } Expensive store
  • 20. sub STORE { my($s, $k, $v) = (shift, shift, shift); if (exists $s->[0]{$k}) { my($i) = $s->[0]{$k}; $s->[1][$i] = $k; $s->[2][$i] = $v; $s->[0]{$k} = $i; } else { push(@{$s->[1]}, $k); push(@{$s->[2]}, $v); $s->[0]{$k} = $#{$s->[1]}; } } Anyone notice this?
  • 23. tie %h, "Tie::LLHash", a=>1, b=>2, c=>3, d=>4;
  • 24. sub last { my $self = shift; ! if (@_) { # Set it my $newkey = shift; my $newvalue = shift; ! croak ("'$newkey' already exists") if $self->EXISTS($newkey); ! # Create the new node $self->{'nodes'}{$newkey} = { 'next' => undef, 'value' => $newvalue, 'prev' => undef, }; ! # Put it in its relative place if (defined $self->{'last'}) { $self->{'nodes'}{$newkey}{'prev'} = $self->{'last'}; $self->{'nodes'}{ $self->{'last'} }{'next'} = $newkey; } ! # Finally, make this node the last node $self->{'last'} = $newkey; ! # If this is an empty hash, make it the first node too $self->{'first'} = $newkey unless (defined $self->{'first'}); } Memory allocation per key!
  • 27. sub get { my ( $self, @keys ) = @_; my @get; foreach my $key (@keys) { $key = $self->$_actual_key($key); next unless defined $key; my $exists = $self->exists($key); if ( $self->{is_strict} && !$exists ) { $self->$_croak("Cannot get non-existent key ($key)"); } if ($exists) { CORE::push @get, $self->{array_for}[ $self->$_index($key) + 1 ]; } elsif ( @keys > 1 ) { CORE::push @get, undef; } else { return; } } return wantarray ? @get : @keys > 1 ? @get : $get[0]; } ! my $_actual_key = sub { my ( $self, $key ) = @_; if ( ref $key ) { my $new_key = $self->{curr_key_of}{ refaddr $key}; return refaddr $key unless defined $new_key; $key = $new_key; } return $key; }; Subroutine call per key!
  • 28. sub get { my ( $self, @keys ) = @_; my @get; foreach my $key (@keys) { $key = $self->$_actual_key($key); next unless defined $key; my $exists = $self->exists($key); if ( $self->{is_strict} && !$exists ) { $self->$_croak("Cannot get non-existent key ($key)"); } if ($exists) { CORE::push @get, $self->{array_for}[ $self->$_index($key) + 1 ]; } elsif ( @keys > 1 ) { CORE::push @get, undef; } else { return; } } return wantarray ? @get : @keys > 1 ? @get : $get[0]; } ! my $_actual_key = sub { my ( $self, $key ) = @_; if ( ref $key ) { my $new_key = $self->{curr_key_of}{ refaddr $key}; return refaddr $key unless defined $new_key; $key = $new_key; } return $key; }; Single key fetch overhead!
  • 30. XS, but flawed • Opaque data: Perl hash of doubly-linked list of C structs ! • Fails tests since Perl 5.18 randomization! • Actually, not all that fast (benchmarks later)
  • 32. Special-purpose or weird • Tie::Array::AsHash — array elements split with separator; tie API only! • Tie::Hash::Array — ordered alphabetically; tie API only! • Tie::InsertOrderHash — ordered by insertion; tie API only! • Tie::StoredOrderHash — ordered by last update; tie API only! • Array::Assign — arrays with named access; restricted keys! • Array::OrdHash — overloads array/hash deref and uses internal tied data! • Data::Pairs — array of key-value hashrefs; allows duplicate keys! • Data::OMap — array of key-value hashrefs; no duplicate keys! • Data::XHash — blessed, tied hashref with doubly-linked-list! !
  • 34. What is the simplest thing that could work?
  • 35. • Hash of keys and values! • Array of key order bless { {a=>1, b=>2}, [‘a’, ‘b’] }
  • 36. I couldn’t find it on CPAN
  • 40. sub get { my ( $self, $key ) = @_; return $self->[_DATA]{$key}; } Cheap get • only 2 dereferences! • no need to test exists()
  • 41. sub set { my ( $self, $key, $value ) = @_; if ( !exists $self->[_DATA]{$key} ) { push @{ $self->[_KEYS] }, $key; } return $self->[_DATA]{$key} = $value; } Cheap-ish set • exists plus 4-6 dereferences and maybe push! • comparable toTie::IxHash::FETCH
  • 42. sub clone { my ( $self, @keys ) = @_; my $clone; if (@keys) { my %subhash; @subhash{@keys} = @{ $self->[_DATA] }{@keys}; $clone = [ %subhash, @keys ]; } else { $clone = [ { %{ $self->[_DATA] } }, [ @{ $self->[_KEYS] } ] ]; } return bless $clone, ref $self; } Got my shallow copy
  • 43. sub iterator { my ( $self, @keys ) = @_; @keys = @{ $self->[_KEYS] } unless @keys; my $data = $self->[_DATA]; return sub { return unless @keys; my $key = CORE::shift(@keys); return ( $key => $data->{$key} ); }; } Got my iterator
  • 44. sub delete { my ( $self, $key ) = @_; if ( exists $self->[_DATA]{$key} ) { my $r = $self->[_KEYS]; my $i = List::Util::first { $r->[$_] eq $key } 0 .. $#$r; splice @$r, $i, 1; return delete $self->[_DATA]{$key}; } return undef; } But, delete is expensive
  • 45. Good tradeoffs? • It’s ::Tiny — only about 130 SLOC! • Faster get and set! • Faster copy! • Slower delete
  • 46. But is it actually fast?
  • 48. Profiling!! ! ! → ! finding hot spots in code! Benchmarking! → ! comparing different code
 ! ! ! ! ! ! ! ! to do the same thing
  • 49. Scale can reveal ‘Big-O’ issues in algorithms
  • 51. Combinations • Different ordered hash modules! • Different operations (create, get, set)! • Different scales (10, 100, 1000 elements)
  • 52. Benchmarking tools • Benchmark.pm! • Dumbbench! • Other stuff on CPAN
  • 54. Kolmogorov–Smirnov test • Compare empirical CDFs! • Non-parametric! • Unequal-variance! • Sensitive to CDF location and shape
  • 58. Benchmark: running a, b, each for at least 5 CPU seconds... a: 10 wallclock secs ( 5.14 usr + 0.13 sys = 5.27 CPU) @ 3835055.60/s (n=20210743) b: 5 wallclock secs ( 5.41 usr + 0.00 sys = 5.41 CPU) @ 1574944.92/s (n=8520452) Rate b a b 1574945/s -- -59% a 3835056/s 144% -- Benchmark.pm is verbose ! • Big test matrix is unreadable! • Lots of detail I don’t care about
  • 59. Approach • Given a hash of test labels and code refs! • Output timings in descending order! • Repeat at different scales
  • 60. use Benchmark qw( countit ); ! use constant COUNT => 5; # CPU seconds ! sub time_them { my (%mark) = @_; my %results; ! for my $k ( sort keys %mark ) { my $res = countit( COUNT, $mark{$k} ); my $iter_s = $res->iters / ( $res->cpu_a + 1e-9 ); $results{$k} = $iter_s; } ! printf( "%20s %d/sn", $_, $results{$_} ) for sort { $results{$b} <=> $results{$a} } keys %results; ! say ""; }
  • 61. Use varied, but constant! test data across runs
  • 62. use Math::Random::MT::Auto qw/irand/; ! use constant NUMS => [ 10, 100, 1000 ]; ! my %PAIRS = ( map { $_ => [ map { irand() => irand() } 1 .. $_ ] } @{ NUMS() } );
  • 63. for my $size ( @{ NUMS() } ) { ! say my $title = "Results for ordered hash creation for $size elements"; ! my %mark; ! $mark{"h:o"} = sub { my $h = Hash::Ordered->new( @{ $PAIRS{$size} } ) }; ! $mark{"t:ix_oo"} = sub { my $h = Tie::IxHash->new( @{ $PAIRS{$size} } ) }; ! $mark{"t:ix_th"} = sub { tie my %h, 'Tie::IxHash', @{ $PAIRS{$size} } }; ! $mark{"t:llh"} = sub { tie my %h, 'Tie::LLHash', @{ $PAIRS{$size} } }; ! # … ! time_them(%mark); ! } Example: hash creation
  • 64. for my $size ( @{ NUMS() } ) { ! say my $title = "Results for ordered hash creation for $size elements"; ! my %mark; ! $mark{"h:o"} = sub { my $h = Hash::Ordered->new( @{ $PAIRS{$size} } ) }; ! $mark{"t:ix_oo"} = sub { my $h = Tie::IxHash->new( @{ $PAIRS{$size} } ) }; ! $mark{"t:ix_th"} = sub { tie my %h, 'Tie::IxHash', @{ $PAIRS{$size} } }; ! $mark{"t:llh"} = sub { tie my %h, 'Tie::LLHash', @{ $PAIRS{$size} } }; ! # … ! time_them(%mark); ! } Includes variations
  • 65. for my $size ( @{ NUMS() } ) { ! say my $title = "Results for fetching ~10% of $size elements"; ! my $oh = Hash::Ordered->new( @{ $PAIRS{$size} } ); my $tix_oo = Tie::IxHash->new( @{ $PAIRS{$size} } ); tie my %tix_th, 'Tie::IxHash', @{ $PAIRS{$size} }; tie my %tllh, 'Tie::LLHash', @{ $PAIRS{$size} }; # … ! my ( %mark, $v ); my @keys = keys %{ { @{ $PAIRS{$size} } } }; ! my $n = int( .1 * scalar @keys ) || 1; my @lookup = map { $keys[ int( rand( scalar @keys ) ) ] } 1 .. $n; ! $mark{"h:o"} = sub { $v = $oh->get($_) for @lookup }; $mark{"t:ix_oo"} = sub { $v = $tix_oo->FETCH($_) for @lookup }; $mark{"t:ix_th"} = sub { $v = $tix_th{$_} for @lookup }; $mark{"t:llh"} = sub { $v = $tllh{$_} for @lookup }; # … ! time_them(%mark); } ! Example: fetch elements
  • 66. for my $size ( @{ NUMS() } ) { ! say my $title = "Results for fetching ~10% of $size elements"; ! my $oh = Hash::Ordered->new( @{ $PAIRS{$size} } ); my $tix_oo = Tie::IxHash->new( @{ $PAIRS{$size} } ); tie my %tix_th, 'Tie::IxHash', @{ $PAIRS{$size} }; tie my %tllh, 'Tie::LLHash', @{ $PAIRS{$size} }; # … ! my ( %mark, $v ); my @keys = keys %{ { @{ $PAIRS{$size} } } }; ! my $n = int( .1 * scalar @keys ) || 1; my @lookup = map { $keys[ int( rand( scalar @keys ) ) ] } 1 .. $n; ! $mark{"h:o"} = sub { $v = $oh->get($_) for @lookup }; $mark{"t:ix_oo"} = sub { $v = $tix_oo->FETCH($_) for @lookup }; $mark{"t:ix_th"} = sub { $v = $tix_th{$_} for @lookup }; $mark{"t:llh"} = sub { $v = $tllh{$_} for @lookup }; # … ! time_them(%mark); } ! Pre-generates hashes
  • 67. for my $size ( @{ NUMS() } ) { ! say my $title = "Results for fetching ~10% of $size elements"; ! my $oh = Hash::Ordered->new( @{ $PAIRS{$size} } ); my $tix_oo = Tie::IxHash->new( @{ $PAIRS{$size} } ); tie my %tix_th, 'Tie::IxHash', @{ $PAIRS{$size} }; tie my %tllh, 'Tie::LLHash', @{ $PAIRS{$size} }; # … ! my ( %mark, $v ); my @keys = keys %{ { @{ $PAIRS{$size} } } }; ! my $n = int( .1 * scalar @keys ) || 1; my @lookup = map { $keys[ int( rand( scalar @keys ) ) ] } 1 .. $n; ! $mark{"h:o"} = sub { $v = $oh->get($_) for @lookup }; $mark{"t:ix_oo"} = sub { $v = $tix_oo->FETCH($_) for @lookup }; $mark{"t:ix_th"} = sub { $v = $tix_th{$_} for @lookup }; $mark{"t:llh"} = sub { $v = $tllh{$_} for @lookup }; # … ! time_them(%mark); } ! Pre-generates test keys
  • 68. for my $size ( @{ NUMS() } ) { ! say my $title = "Results for fetching ~10% of $size elements"; ! my $oh = Hash::Ordered->new( @{ $PAIRS{$size} } ); my $tix_oo = Tie::IxHash->new( @{ $PAIRS{$size} } ); tie my %tix_th, 'Tie::IxHash', @{ $PAIRS{$size} }; tie my %tllh, 'Tie::LLHash', @{ $PAIRS{$size} }; # … ! my ( %mark, $v ); my @keys = keys %{ { @{ $PAIRS{$size} } } }; ! my $n = int( .1 * scalar @keys ) || 1; my @lookup = map { $keys[ int( rand( scalar @keys ) ) ] } 1 .. $n; ! $mark{"h:o"} = sub { $v = $oh->get($_) for @lookup }; $mark{"t:ix_oo"} = sub { $v = $tix_oo->FETCH($_) for @lookup }; $mark{"t:ix_th"} = sub { $v = $tix_th{$_} for @lookup }; $mark{"t:llh"} = sub { $v = $tllh{$_} for @lookup }; # … ! time_them(%mark); } ! Benchmark just the fetch
  • 69. for my $size ( @{ NUMS() } ) { ! say my $title = "Results for creating $size element hash then deleting ~10%"; ! my ( %mark, $v ); my @keys = keys %{ { @{ $PAIRS{$size} } } }; ! my $n = int( .1 * scalar @keys ) || 1; my @lookup = map { $keys[ int( rand( scalar @keys ) ) ] } 1 .. $n; ! $mark{"h:o"} = sub { my $oh = Hash::Ordered->new( @{ $PAIRS{$size} } ); $oh->delete($_) for @lookup; }; ! $mark{"t:ix_oo"} = sub { my $tix_oo = Tie::IxHash->new( @{ $PAIRS{$size} } ); $tix_oo->DELETE($_) for @lookup; }; ! # … ! time_them(%mark); } ! Example: deleting elements
  • 70. for my $size ( @{ NUMS() } ) { ! say my $title = "Results for creating $size element hash then deleting ~10%"; ! my ( %mark, $v ); my @keys = keys %{ { @{ $PAIRS{$size} } } }; ! my $n = int( .1 * scalar @keys ) || 1; my @lookup = map { $keys[ int( rand( scalar @keys ) ) ] } 1 .. $n; ! $mark{"h:o"} = sub { my $oh = Hash::Ordered->new( @{ $PAIRS{$size} } ); $oh->delete($_) for @lookup; }; ! $mark{"t:ix_oo"} = sub { my $tix_oo = Tie::IxHash->new( @{ $PAIRS{$size} } ); $tix_oo->DELETE($_) for @lookup; }; ! # … ! time_them(%mark); } ! But, we can’t isolate delete
  • 74. Modules & abbreviations • Hash::Ordered ! ! → h:o! ! [data hash + keys array]! ! • Array::AsHash ! ! → a:ah! ! [data array + index hash]! ! • Tie::IxHash ! ! ! → t:ix! ! [tie + hash + 2 x array]! ! • Tie::LLHash ! ! ! → t:llh! ! [tie + hash + 2LL]! ! • Tie::Hash::Indexed !! → t:h:i! ! [XS + tie + hash + 2LL]! ! • Array::OrdHash! ! → a:oh!! [overloaded + private ties]! ! • Data::XHash! ! ! → d:xh!! [tie + double linked list]! !
  • 75. Creation 10 elements 100 elements 1000 elements t:h:i 129713/s a:ah_rf 104034/s h:o 94121/s a:ah_cp 62539/s t:ix_th 60136/s t:ix_oo 59895/s a:oh 49399/s t:llh 32122/s d:xh_rf 13288/s d:xh_ls 13223/s t:h:i 15026/s a:ah_rf 14304/s h:o 10931/s a:ah_cp 7512/s t:ix_oo 7368/s t:ix_th 7161/s a:oh 6572/s t:llh 3306/s d:xh_ls 1498/s d:xh_rf 1491/s a:ah_rf 1410/s t:h:i 1285/s h:o 1022/s a:ah_cp 763/s t:ix_oo 703/s t:ix_th 697/s a:oh 694/s t:llh 290/s d:xh_rf 147/s d:xh_ls 146/s
  • 76. Fetch 10% of elements 10 elements 100 elements 1000 elements h:o 1417712/s d:xh_oo 1231973/s t:ix_oo 1120271/s t:h:i 792250/s d:xh_rf 722683/s t:ix_th 624603/s a:oh 553755/s t:llh 504533/s a:ah 246063/s h:o 244800/s d:xh_oo 181520/s t:ix_oo 175981/s t:h:i 132963/s d:xh_rf 93519/s t:ix_th 82154/s a:oh 68270/s t:llh 57013/s a:ah 28280/s h:o 24871/s d:xh_oo 19125/s t:ix_oo 17655/s t:h:i 13407/s d:xh_rf 9590/s t:ix_th 8455/s a:oh 6995/s t:llh 5781/s a:ah 2219/s
  • 77. Set 10% of elements 10 elements 100 elements 1000 elements h:o 1353795/s d:xh_oo 952485/s t:h:i 943983/s t:ix_oo 923874/s t:llh 600717/s d:xh_rf 568693/s a:oh 547233/s t:ix_th 519939/s a:ah 164170/s h:o 197232/s t:h:i 131238/s d:xh_oo 121692/s t:ix_oo 114869/s t:llh 71720/s d:xh_rf 67130/s a:oh 63634/s t:ix_th 59784/s a:ah 16843/s h:o 20364/s t:h:i 13254/s d:xh_oo 12512/s t:ix_oo 11542/s t:llh 7295/s d:xh_rf 7004/s a:oh 6376/s t:ix_th 6175/s a:ah 1635/s
  • 78. Adding elements to empty 10 elements 100 elements 1000 elements h:o 367588/s t:h:i 300357/s t:ix_oo 263158/s t:ix_th 214085/s t:llh 187981/s a:oh 141308/s a:ah 96523/s d:xh_oo 87498/s d:xh_rf 84316/s h:o 66495/s t:h:i 57307/s t:ix_oo 49676/s t:ix_th 38222/s a:oh 35476/s t:llh 27998/s d:xh_oo 24371/s d:xh_rf 22326/s a:ah 14114/s h:o 7217/s t:h:i 6244/s t:ix_oo 5671/s a:oh 4335/s t:ix_th 4313/s d:xh_oo 2977/s t:llh 2899/s d:xh_rf 2683/s a:ah 1466/s
  • 79. Deleting* 10% of keys 10 elements 100 elements 1000 elements t:h:i 139517/s h:o 95284/s a:ah 66495/s t:ix_oo 52892/s t:ix_th 50254/s a:oh 45609/s t:llh 28599/s d:xh_rf 13223/s d:xh_oo 13173/s t:h:i 16745/s h:o 6924/s t:ix_oo 4063/s a:oh 3963/s t:ix_th 3590/s a:ah 3014/s t:llh 2459/s d:xh_oo 1449/s d:xh_rf 1434/s t:h:i 1604/s t:llh 269/s a:oh 171/s d:xh_rf 146/s h:o 144/s d:xh_oo 130/s t:ix_oo 85/s t:ix_th 77/s a:ah 36/s
  • 80. Output hash as a list 10 elements 100 elements 1000 elements a:ah 290725/s h:o 170187/s t:ix_oo 92118/s t:h:i 80408/s t:ix_th 48756/s t:llh 38509/s a:oh 36126/s d:xh 35766/s a:ah 39222/s h:o 18839/s t:ix_oo 9525/s t:h:i 7742/s a:oh 5081/s t:ix_th 5014/s d:xh 4160/s t:llh 3841/s a:ah 3703/s h:o 1877/s t:ix_oo 961/s t:h:i 768/s a:oh 508/s t:ix_th 505/s d:xh 413/s t:llh 385/s
  • 83. Module choice matters a lot • 7 CPAN modules tested! • 10x performance difference on some tasks! • Look inside modules before you use them!
  • 84. Simplicity pays off • Less indirection! • Less memory allocation! • Fewer ops per call