Skip to content
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

Benchmark results #2

Open
tobyink opened this issue Sep 3, 2019 · 5 comments
Open

Benchmark results #2

tobyink opened this issue Sep 3, 2019 · 5 comments
Assignees
Labels
enhancement New feature or request

Comments

@tobyink
Copy link

tobyink commented Sep 3, 2019

Not really an issue, but thought I'd send you these.

Benchmark source

use v5.16;
use warnings;
use Benchmark 'cmpthese';
use Test::More;

package SMT::test {
	use Sub::Multi::Tiny qw( $foo $bar );
	sub first :M($foo, $bar) {
		return $foo ** $bar;
	}
	sub second :M($foo) {
		return $foo + 42;
	}
}

package M {
	use Kavorka qw(multi fun);

	multi fun test ($foo, $bar) {
		return $foo ** $bar;
	}
	multi fun test ($foo) {
		return $foo + 42;
	}
}

is(M::test(8,2), 64);
is(M::test(3,3), 27);
is(M::test(58), 100);
is(SMT::test(8,2), 64);
is(SMT::test(3,3), 27);
is(SMT::test(58), 100);

cmpthese -1, {
	M    => q{   M::test(3,3);  SMT::test(0); },
	SMT  => q{ SMT::test(3,3);  SMT::test(0); },
};

Results on my laptop:

ok 1
ok 2
ok 3
ok 4
ok 5
ok 6
        Rate  SMT    M
SMT 255999/s   -- -11%
M   286959/s  12%   --

I had expected a bit of a slow down from your use of guards and global variables, but it actually performs at a pretty decent rate.

As you use a stringy eval to build your dispatcher, you could probably speed things up a little by avoiding the hashtable arity lookup thing at run time, and putting if(@_==1) {...} elsif(@_==2) {...} into the evaluated string itself. The only advantage in keeping the hash table lookup would be if you wanted to be able to insert new entries into it at run-time, but right now the hash is a lexical variable, so short of some PadWalker tricks, can't be altered by runtime code anyway.

@cxw42
Copy link
Owner

cxw42 commented Sep 3, 2019

@tobyink Thanks for the early review and feedback! I am delighted that I'm not the only one following metacpan/recent :) .

  • In the cmpthese, shouldn't the M=> line call M::test(0)? (Edit See Benchmark results #2 (comment))

  • I appreciate the suggestion re. the dispatcher, which is indeed currently very preliminary. I am planning to add typechecks (building off our work together on Class::Tiny::ConstrainedAccessor) and where, and then see what types of optimizations make sense.

@cxw42 cxw42 added the enhancement New feature or request label Sep 3, 2019
@cxw42
Copy link
Owner

cxw42 commented Sep 3, 2019

OK - I was able to run the benchmark thanks to Alt::Devel::CallParser::ButWorking. With the original code, I get similar results - SMT 341672/s, M (Kavorka) 381869/s.

When I change the SMT::test(0) call in the M line (and rename M to Kavorka), I get rather different results:

        Rate  Kav  SMT
Kav  50717/s   -- -84%
SMT 324589/s 540%   --

Edit Of course, SMT's dispatcher is much less sophisticated than Kavorka's, and that is probably part of the speed. This tells me that, as SMT grows, it would be worth using dispatchers specific to the set of implementations for each function.

Modified source

use v5.16;
use warnings;
use Benchmark 'cmpthese';
use Test::More;

package SMT::test {
	use Sub::Multi::Tiny qw( $foo $bar );
	sub first :M($foo, $bar) {
		return $foo ** $bar;
	}
	sub second :M($foo) {
		return $foo + 42;
	}
}

package K {						# <==== "K"avorka
	use Kavorka qw(multi fun);

	multi fun test ($foo, $bar) {
		return $foo ** $bar;
	}
	multi fun test ($foo) {
		return $foo + 42;
	}
}

is(K::test(8,2), 64);
is(K::test(3,3), 27);
is(K::test(58), 100);
is(SMT::test(8,2), 64);
is(SMT::test(3,3), 27);
is(SMT::test(58), 100);

cmpthese -1, {
	Kav  => q{   K::test(3,3);    K::test(0); },	# <====
	SMT  => q{ SMT::test(3,3);  SMT::test(0); },
};

@cxw42 cxw42 self-assigned this Sep 3, 2019
@tobyink
Copy link
Author

tobyink commented Sep 4, 2019

Hmm, wow, that's weird. For one parameter, SMT is way faster. For two, Kavorka is faster.

@tobyink
Copy link
Author

tobyink commented Sep 4, 2019

I think I know why. Type::Params::multisig is smarter at dispatching; I need to steal some of that logic into Kavorka.

@cxw42
Copy link
Owner

cxw42 commented Sep 11, 2019

Thanks for the pointer to multisig! Just-released v0.000006 has a multisig-based dispatcher that seems to work fairly nicely, and it was much easier to write thanks to Type::Params! I haven't done any benchmarking yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants