New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tiny speed-up #6

Closed
tobyink opened this Issue Sep 5, 2013 · 4 comments

Comments

Projects
None yet
3 participants
@tobyink
Contributor

tobyink commented Sep 5, 2013

I'm being lazy and submitting an issue rather than a pull request.

Line 21 is currently:

$class->create_attributes( $pkg, @_ );

It could be:

$class->create_attributes( $pkg, @_ ) if @_;

This would slightly speed up Class::Tiny::Antlers, which calls Class::Tiny::import to do its stuff even before attributes are created.

dagolden pushed a commit that referenced this issue Sep 5, 2013

@aero

This comment has been minimized.

Show comment
Hide comment
@aero

aero Sep 7, 2013

I benchmarked several light-weight class builder modules. (Creating Object, Accessor)

Class::Accessor::Fast vs Class::Tiny

>perl -MBenchmark -e "{package CF; use base 'Class::Accessor::Fast'; CF->mk_accessors(qw/a/); } {package CT; use Class::Tiny qw/a/ }; my $cf; my $ct; timethese(100000, { CF => sub { $cf=CF->new({a=>2}) }, CT => sub { $ct = CT->new(a=>3) } }); sleep 1; timethese(1000000, { CFa => sub { $cf->a }, CTa => sub { $ct->a } })"
Benchmark: timing 100000 iterations of CF, CT...
        CF: -1 wallclock secs ( 0.38 usr +  0.00 sys =  0.38 CPU) @ 266666.67/s (n=100000)
            (warning: too few iterations for a reliable count)
        CT:  2 wallclock secs ( 1.69 usr +  0.00 sys =  1.69 CPU) @ 59347.18/s (n=100000)
Benchmark: timing 1000000 iterations of CFa, CTa...
       CFa:  1 wallclock secs ( 0.50 usr +  0.00 sys =  0.50 CPU) @ 2004008.02/s (n=1000000)
       CTa:  1 wallclock secs ( 1.12 usr +  0.00 sys =  1.12 CPU) @ 891265.60/s (n=1000000)

Mo vs Class::Tiny

>perl -MBenchmark -e "{package M; use Mo; has a => (is => 'rw'); } {package CT; use Class::Tiny qw/a/ }; my $m; my $ct; timethese(100000, { M=> sub { $m=M->new({a=>2}) }, CT => sub { $ct = CT->new(a=>3) } }); sleep 1; timethese(1000000, { Ma => sub { $m->a }, CTa => sub { $ct->a } })"
Benchmark: timing 100000 iterations of CT, M...
        CT:  1 wallclock secs ( 1.81 usr +  0.00 sys =  1.81 CPU) @ 55279.16/s (n=100000)
         M:  1 wallclock secs ( 0.56 usr +  0.00 sys =  0.56 CPU) @ 178253.12/s (n=100000)
Benchmark: timing 1000000 iterations of CTa, Ma...
       CTa:  2 wallclock secs ( 1.05 usr +  0.00 sys =  1.05 CPU) @ 956022.94/s (n=1000000)
        Ma:  1 wallclock secs ( 0.50 usr +  0.00 sys =  0.50 CPU) @ 2000000.00/s (n=1000000)

Class::Tiny is significantly slower than the others.
More performance improvement is possible ?

aero commented Sep 7, 2013

I benchmarked several light-weight class builder modules. (Creating Object, Accessor)

Class::Accessor::Fast vs Class::Tiny

>perl -MBenchmark -e "{package CF; use base 'Class::Accessor::Fast'; CF->mk_accessors(qw/a/); } {package CT; use Class::Tiny qw/a/ }; my $cf; my $ct; timethese(100000, { CF => sub { $cf=CF->new({a=>2}) }, CT => sub { $ct = CT->new(a=>3) } }); sleep 1; timethese(1000000, { CFa => sub { $cf->a }, CTa => sub { $ct->a } })"
Benchmark: timing 100000 iterations of CF, CT...
        CF: -1 wallclock secs ( 0.38 usr +  0.00 sys =  0.38 CPU) @ 266666.67/s (n=100000)
            (warning: too few iterations for a reliable count)
        CT:  2 wallclock secs ( 1.69 usr +  0.00 sys =  1.69 CPU) @ 59347.18/s (n=100000)
Benchmark: timing 1000000 iterations of CFa, CTa...
       CFa:  1 wallclock secs ( 0.50 usr +  0.00 sys =  0.50 CPU) @ 2004008.02/s (n=1000000)
       CTa:  1 wallclock secs ( 1.12 usr +  0.00 sys =  1.12 CPU) @ 891265.60/s (n=1000000)

Mo vs Class::Tiny

>perl -MBenchmark -e "{package M; use Mo; has a => (is => 'rw'); } {package CT; use Class::Tiny qw/a/ }; my $m; my $ct; timethese(100000, { M=> sub { $m=M->new({a=>2}) }, CT => sub { $ct = CT->new(a=>3) } }); sleep 1; timethese(1000000, { Ma => sub { $m->a }, CTa => sub { $ct->a } })"
Benchmark: timing 100000 iterations of CT, M...
        CT:  1 wallclock secs ( 1.81 usr +  0.00 sys =  1.81 CPU) @ 55279.16/s (n=100000)
         M:  1 wallclock secs ( 0.56 usr +  0.00 sys =  0.56 CPU) @ 178253.12/s (n=100000)
Benchmark: timing 1000000 iterations of CTa, Ma...
       CTa:  2 wallclock secs ( 1.05 usr +  0.00 sys =  1.05 CPU) @ 956022.94/s (n=1000000)
        Ma:  1 wallclock secs ( 0.50 usr +  0.00 sys =  0.50 CPU) @ 2000000.00/s (n=1000000)

Class::Tiny is significantly slower than the others.
More performance improvement is possible ?

@ghost

This comment has been minimized.

Show comment
Hide comment
@ghost

ghost Sep 7, 2013

Collaborator

Possibly, but Class::Tiny is optimized for size, not speed. Plus, it's not feature set compatible. Class::Tiny constructor takes hashref or list, does validation, checks for BUILD, etc. The accessors support lazy defaults, etc.

Maybe the accessor could be adaptive and not have the extra check for setting the lazy default if none was given for that attribute. But that's only saving a single if comparison. In real world code, I'm not sure how significant that is.

Collaborator

ghost commented Sep 7, 2013

Possibly, but Class::Tiny is optimized for size, not speed. Plus, it's not feature set compatible. Class::Tiny constructor takes hashref or list, does validation, checks for BUILD, etc. The accessors support lazy defaults, etc.

Maybe the accessor could be adaptive and not have the extra check for setting the lazy default if none was given for that attribute. But that's only saving a single if comparison. In real world code, I'm not sure how significant that is.

@ghost

This comment has been minimized.

Show comment
Hide comment
@ghost

ghost Sep 7, 2013

Collaborator

I've pushed some commits that speed things up for simple cases, particularly for accessors without defaults.

Note as well that Class::Tiny supports DEMOLISH, so DESTROY gets called for every object in the benchmark, which Mo and CAF don't do.

I have a couple more minor ideas, but I think I'm near the point of diminishing returns.

Collaborator

ghost commented Sep 7, 2013

I've pushed some commits that speed things up for simple cases, particularly for accessors without defaults.

Note as well that Class::Tiny supports DEMOLISH, so DESTROY gets called for every object in the benchmark, which Mo and CAF don't do.

I have a couple more minor ideas, but I think I'm near the point of diminishing returns.

@ghost

This comment has been minimized.

Show comment
Hide comment
@ghost

ghost Sep 7, 2013

Collaborator

I've shipped 0.007 to CPAN. It's comparable to Mo with the 'build' feature if a DESTROY method is added.

I think this is probably "fast enough" -- any faster and we'd give up the few useful features that Class::Tiny offers.

Collaborator

ghost commented Sep 7, 2013

I've shipped 0.007 to CPAN. It's comparable to Mo with the 'build' feature if a DESTROY method is added.

I think this is probably "fast enough" -- any faster and we'd give up the few useful features that Class::Tiny offers.

@dagolden dagolden closed this Sep 7, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment