Initial benchmark (totally incomplete)
Peter Rabbitson [Wed, 10 Nov 2010 03:00:34 +0000 (04:00 +0100)]
benchmark/class_factory [new file with mode: 0644]

diff --git a/benchmark/class_factory b/benchmark/class_factory
new file mode 100644 (file)
index 0000000..a31724a
--- /dev/null
@@ -0,0 +1,105 @@
+use strictures 1;
+
+use Benchmark qw/:hireswallclock cmpthese/;
+use Getopt::Long::Descriptive;
+
+
+my ($opts, $usage);
+BEGIN {
+  ($opts, $usage) = describe_options(
+    '%c: %o' =>
+    [ 'help|h'          => 'Print usage message and exit' ],
+    [ 'classes|c:i'     => 'How many classes to create per benchmark cycle (def 10)', { default => 10 } ],
+    [ 'accessors|a:i'   => 'How many accessors to create per class (def 100)', { default => 100 } ],
+    [ 'pregenerate|p:i' => 'For how many maximum benchmark cycles should we prepare (def 1000)', { default => 1000 } ],
+    [ 'unique|u'        => 'Make accessor names globally unique (instead of just per class)' ],
+    [ 'bench|b:s'       => 'Which benchmarks to run (all|xs|pp)', { default => 'all', regex => qr/^(?:all|xs|pp)$/ } ],
+    { getopt_conf => [qw/gnu_getopt bundling_override no_ignore_case/] },
+  );
+
+  # can not change this runtime, thus in-block
+  $ENV{MOUSE_PUREPERL} = 1 if $opts->{bench} eq 'pp';
+
+  my @missing;
+  for (qw/
+    Moose
+    Moo
+    Mouse
+  /) {
+    eval "require $_" or push @missing, $_;
+  }
+
+  if (@missing) {
+    die sprintf "Missing modules necessary for benchmark:\n\n%s\n\n",
+      join ("\n", @missing);
+  }
+}
+
+use Method::Generate::Accessor; # need to pre-load for the XS shutoff to work
+
+$usage->die if $opts->{help};
+
+my $counters;
+my $tasks = {};
+
+if ($opts->{bench} =~ /all|pp/) {
+  {
+    local $Method::Generate::Accessor::CAN_HAZ_XS = 0;
+    _add_moosey_has (moo => 'Moo');
+  }
+
+  _add_moosey_has (moose => 'Moose');
+  _add_moosey_has (mouse => 'Mouse')
+    if $ENV{MOUSE_PUREPERL};
+}
+
+if ($opts->{bench} =~ /all|xs/) {
+  {
+    local $Method::Generate::Accessor::CAN_HAZ_XS = 1;
+    _add_moosey_has (moo_XS => 'Moo');
+  }
+  _add_moosey_has (mouse_XS => 'Mouse')
+    unless $ENV{MOUSE_PUREPERL};
+}
+
+# run each task once, prime whatever caches there may be
+$_->() for values %$tasks;
+
+# Actual Benchmarking
+for (1, 2) {
+  print "Perl $], take $_:\n";
+  cmpthese ( -1, $tasks );
+  print "\n";
+}
+
+exit 0; # the end
+
+sub _add_moosey_has {
+  my ($name, $base) = @_;
+
+  my @for_eval;
+
+  # need to pre-gen stuff so that the class names will differ for every bench run
+  for (1 .. $opts->{pregenerate}) {
+    my $perl;
+    for ( 1.. $opts->{classes} ) {
+      my $class = "Bench::${base}::" . ++$counters->{class};
+      $perl .= "package $class; use $base;";
+      for ( 1.. $opts->{accessors} ) {
+        my $attr = 'attribute_' . ++$counters->{acc};
+        $perl .= "has $attr => ( is => rw );";
+      }
+
+      $counters->{accessors} = 0
+        unless $opts->{unique};
+    }
+
+    push @for_eval, $perl;
+  }
+
+  $tasks->{$name} = sub {
+    my $code = shift @for_eval
+      or die "Ran out of pre-generated stuff, raise -p\n";
+    eval $code;
+  };
+}