On Wed, Apr 18, 2007 at 10:31:25AM -0400, Jerry D. Hedden wrote: > I began looking at adapting Object::InsideOut to using > Hash::Util::FieldHash. My first endeavor was to see how > fast they were. Much to my surprise, their performance is > disappointing. I compared simple get and set accessors for > inside-out classes using field hashes, refaddr and > stringified objects. (See attachments. The code is quite > simple.) > > 'get' operations: > Rate Refaddr FieldHash Stringify > Refaddr 151543/s -- -25% -49% > FieldHash 201418/s 33% -- -32% > Stringify 297227/s 96% 48% -- > > 'set' operations: > Rate FieldHash Refaddr Stringify > FieldHash 79496/s -- -49% -74% > Refaddr 156784/s 97% -- -49% > Stringify 309688/s 290% 98% -- > > While field hashes do a bit better than refaddr in get > operations, stringification is the hands down winner! Why? > > I tried to speed things up a bit by borrowing the trick from > blead 28961, and replaced HUF_id with > > SV* HUF_id(SV* ref, NV cookie) { > UV id = PTR2UV(SvRV(ref)); > return sv_2mortal(newSVpvn((char *)&id, sizeof(id))); > } > > This only have about a 10% improvement: > > 'get' operations: > Rate Refaddr FieldHash Stringify > Refaddr 151543/s -- -31% -49% > FieldHash 221005/s 46% -- -25% > Stringify 294645/s 94% 33% -- > > 'set' operations: > Rate FieldHash Refaddr Stringify > FieldHash 85843/s -- -45% -73% > Refaddr 155647/s 81% -- -50% > Stringify 312161/s 264% 101% -- > > And, of course, all this pales in comparison to what > Object::InsideOut already does. > > 'get' operations: > Rate Refaddr FieldHash Stringify OIO > Refaddr 150377/s -- -25% -50% -83% > FieldHash 199990/s 33% -- -33% -77% > Stringify 300178/s 100% 50% -- -66% > OIO 870557/s 479% 335% 190% -- > > 'set' operations: > Rate FieldHash Refaddr Stringify OIO > FieldHash 79518/s -- -49% -75% -91% > Refaddr 154844/s 95% -- -51% -82% > Stringify 316440/s 298% 104% -- -64% > OIO 867219/s 991% 460% 174% -- > > While I fully appreciate the significance of the work done > by Anno, unless something drastic can be done to improve > their performance, there doesn't seem to be any reason to > bother trying to use field hashes. Well, that sounds like a very harsh conclusion. Unless one's attitude is that speed if everything - in which case you haven't any reason to bother using Perl in the first place. *I* certainly will be using fieldhashes. Even if it's slower. Having said that, I did some testing as well. I don't get much difference between 'refaddr' and stringification. Fieldhashes are slower when setting/getting, although the difference is much less on getting. Create/DESTROY refaddr: 14.45 usec stringify: 13.03 usec fieldhash: 5.62 usec Set refaddr: 5.86 usec stringify: 5.01 usec fieldhash: 7.70 usec Get refaddr: 3.18 usec stringify: 2.78 usec fieldhash: 3.60 usec Cycle refaddr: 24.27 usec stringify: 21.47 usec fieldhash: 35.63 usec #!/opt/perl/current/bin/perl use strict; use warnings; no warnings 'syntax'; use Time::HiRes 'time'; my $RUNS = 1_000_000; { package Refaddr; use Scalar::Util 'refaddr'; my %attr; sub new {bless \do {my $var} => shift} sub set { my $key = refaddr (my $self = shift); $attr {$key} = shift; } sub get { my $key = refaddr (my $self = shift); $attr {$key}; } sub DESTROY { my $key = refaddr (my $self = shift); delete $attr {$key}; } } { package Stringify; my %attr; sub new {bless \do {my $var} => shift} sub set { my $self = shift; $attr {$self} = shift; } sub get { my $self = shift; $attr {$self}; } sub DESTROY { my $self = shift; delete $attr {$self}; } } { package FieldHash; use Hash::Util::FieldHash 'fieldhash'; fieldhash my %attr; sub new {bless \do {my $var} => shift} sub set { my $self = shift; $attr {$self} = shift; } sub get { my $self = shift; $attr {$self}; } } my $t0 = time; for (1 .. $RUNS) {my $obj = Refaddr -> new;} my $t1 = time; for (1 .. $RUNS) {my $obj = Stringify -> new;} my $t2 = time; for (1 .. $RUNS) {my $obj = FieldHash -> new;} my $t3 = time; my $c_r = $t1 - $t0; my $c_s = $t2 - $t1; my $c_f = $t3 - $t2; my $obj_r = Refaddr -> new; my $obj_s = Stringify -> new; my $obj_f = FieldHash -> new; $t0 = time; for (1 .. $RUNS) {$obj_r -> set (1)} $t1 = time; for (1 .. $RUNS) {$obj_s -> set (1)} $t2 = time; for (1 .. $RUNS) {$obj_f -> set (1)} $t3 = time; my $s_r = $t1 - $t0; my $s_s = $t2 - $t1; my $s_f = $t3 - $t2; $t0 = time; for (1 .. $RUNS) {$obj_r -> get} $t1 = time; for (1 .. $RUNS) {$obj_s -> get} $t2 = time; for (1 .. $RUNS) {$obj_f -> get} $t3 = time; my $g_r = $t1 - $t0; my $g_s = $t2 - $t1; my $g_f = $t3 - $t2; $t0 = time; for (1 .. $RUNS) {my $o = Refaddr -> new; $o -> set (1); $o -> get;} $t1 = time; for (1 .. $RUNS) {my $o = Stringify -> new; $o -> set (1); $o -> get;} $t2 = time; for (1 .. $RUNS) {my $o = FieldHash -> new; $o -> set (1); $o -> get;} $t3 = time; my $z_r = $t1 - $t0; my $z_s = $t2 - $t1; my $z_f = $t3 - $t2; printf "Create/DESTROY\n"; printf "\trefaddr: %5.2f usec\n" => 1_000_000 * $c_r / $RUNS; printf "\tstringify: %5.2f usec\n" => 1_000_000 * $c_s / $RUNS; printf "\tfieldhash: %5.2f usec\n" => 1_000_000 * $c_f / $RUNS; printf "Set\n"; printf "\trefaddr: %5.2f usec\n" => 1_000_000 * $s_r / $RUNS; printf "\tstringify: %5.2f usec\n" => 1_000_000 * $s_s / $RUNS; printf "\tfieldhash: %5.2f usec\n" => 1_000_000 * $s_f / $RUNS; printf "Get\n"; printf "\trefaddr: %5.2f usec\n" => 1_000_000 * $g_r / $RUNS; printf "\tstringify: %5.2f usec\n" => 1_000_000 * $g_s / $RUNS; printf "\tfieldhash: %5.2f usec\n" => 1_000_000 * $g_f / $RUNS; printf "Cycle\n"; printf "\trefaddr: %5.2f usec\n" => 1_000_000 * $z_r / $RUNS; printf "\tstringify: %5.2f usec\n" => 1_000_000 * $z_s / $RUNS; printf "\tfieldhash: %5.2f usec\n" => 1_000_000 * $z_f / $RUNS; __END__Thread Previous | Thread Next