Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Benchmarks target in Makefile

by bliako (Monsignor)
on Jun 19, 2018 at 11:50 UTC ( [id://1216932]=perlquestion: print w/replies, xml ) Need Help??

bliako has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I would like to add a target for running benchmarks on my code to the Makefile produced by ExtUtils::MakeMaker

I already have a benhmarks.pl file which does everything and prints a report. I would like to have it executed whenever I do: make benchmarks . And only then because it is time consuming and should not be in tests.

thanks,

Replies are listed 'Best First'.
Re: Benchmarks target in Makefile
by pryrt (Abbot) on Jun 19, 2018 at 13:23 UTC

    When I want to add targets to to the produced Makefile, I define the sub MY::postamble in Makefile.PL. You can see an example in https://github.com/pryrt/Math-PRBS/blob/master/Makefile.PL, where I add rules that clean up some of the files that make clean misses, or run a coverage report, or autogenerate my LICENSE and README.md from my main module's embedded POD. (As tobyink pointed out, make benchmarks is long... but maybe you could call the target make bm... er, wait, BM doesn't have the best connotations... ;-) Maybe make bench would be better.)

      got it thanks!

      sub MY::postamble { return <<'POSTAMBLE'; bench :: benchmarks/*.b $(NOECHO) /usr/bin/env perl '$<' POSTAMBLE } WriteMakefile( INSTALL_BASE => blablabla )

      However, I tried to do this:

      sub MY::postamble { return <<'POSTAMBLE'; bench :: $(BENCHMARKS) $(NOECHO) /usr/bin/env perl '$<' POSTAMBLE } WriteMakefile( INSTALL_BASE => blablabla ... postamble => { BENCHMARKS => 'benchmarks/*.b' } );

      But I did not see any '$(BENCHMARKS)' var set in the Makefile. Is that the correct use of postamble you think?

        Based on my reading of ExtUtils::MakeMaker:

        postamble: Anything put here will be passed to MY::postamble() if you have one

        ... and the

        sub MY::postamble { my (undef,%h) = @_; ...
        start to my function that I linked earlier, I believe that MM passes the hash as args to the subroutine, not as variables in the Makefile, so I would suggest something like (untested):
        sub MY::postamble { my (undef,%h) = @_; my $ret = "bench :: $h{BENCHMARKS}\n"; $ret .= <<'POSTAMBLE'; $(NOECHO) /usr/bin/env perl '$<' POSTAMBLE return $ret; } WriteMakefile( INSTALL_BASE => blablabla ... postamble => { BENCHMARKS => 'benchmarks/*.b' } );

      too quick to speak...

      It only runs the first benchmark of many.

      Secondly, perl must be given the path to blib to load the module because at the benchmark stage module is not installed.

      I have noticed in the Makefile that when they want to run multiple tests they do:

      PERL_DL_NONLAZY=1 $(FULLPERLRUN) "-MExtUtils::Command::MM" "-MTest::Harness" "-e" "undef *Test::Harness::Switches; test_harness($(TEST_VERBOSE), '$(INST_LIB)', '$(INST_ARCHLIB)')" $(TEST_FILES)

      I did try the above with my benchmark files and works though I have to add Test::More directives into the benchmark file in order to keep it happy about not running any tests and also to be able to report the results of the benchmark

      sub MY::postamble { my (undef,%h) = @_; require Data::Dumper; #print STDERR Data::Dumper->Dump([\%h], [qw(mm_args{postamble})]); return "BENCHMARK_FILES=$h{BENCHMARK_FILES}\n" . <<'POSTAMBLE'; bench :: $(BENCHMARK_FILES) # PERL_DL_NONLAZY=1 $(FULLPERLRUN) $(BENCHMARK_FILES) PERL_DL_NONLAZY=1 $(FULLPERLRUN) "-MExtUtils::Command::MM" "-M +Test::Harness" "-e" "undef *Test::Harness::Switches; test_harness($(T +EST_VERBOSE), '$(INST_LIB)', '$(INST_ARCHLIB)')" $(BENCHMARK_FILES) POSTAMBLE }

      I wonder if there is a way to do something similar for the multiple benchmark files.

Re: Benchmarks target in Makefile
by tobyink (Canon) on Jun 19, 2018 at 12:16 UTC

    Why not just type ./benchmarks.pl? It's the same number of characters as make benchmarks so shouldn't be too much work.

      well spotted! I am a make guy what can i say?

        $(PERL) not usr.bin.env...
Re: Benchmarks target in Makefile
by bliako (Monsignor) on Jun 20, 2018 at 11:29 UTC

    Not that happy with this solution but I will go along with it. I still need a proper benchmark procedure for running the files in benchmark/ similar to the test procedure for running the files in t/. All via the Makefile (MakeMaker I guess). Let me know if any such thing exists.

    So, the solution for the time being (thanks to pryrt for the postamble part which inserts a custom target in the Makefile!):

    I am going to use prove to run the benchmarks as a fake test.

    prove is a command line tool provided by Test::Harness which allows specifying module search path, i.e. can add blib/ and blib/arch to search path and therefore can load the module before installation. Also important: it accepts multiple benchmark files to run from the command line. Here is some typical usage:

    prove --blib blib --blib blib/arch --verbose benchmarks/02.b benchmarks/01.b

    So, my postamble now looks like this :

    sub MY::postamble { my (undef,%h) = @_; require Data::Dumper; #print STDERR Data::Dumper->Dump([\%h], [qw(mm_args{postamble})]); return "BENCHMARK_FILES=$h{BENCHMARK_FILES}\n" . <<'POSTAMBLE'; #bench :: benchmarks/*.b bench :: $(BENCHMARK_FILES) prove --blib $(INST_LIB) --blib $(INST_ARCHLIB) --verbose $^ POSTAMBLE }

    The relevant bit in the WriteMakefile() hash is:

        postamble => { BENCHMARK_FILES => 'benchmarks/*.b' }

    A typical benchmark file looks like this:

    use strict; use warnings; use Our::New::Module::To::Benchmark; use Benchmark qw/timethese cmpthese :hireswallclock/; use Test::More; my $num_repeats = 2; print "$0 : benchmarks...\n"; # shamelessly ripped off App::Benchmark cmpthese(timethese($num_repeats, { 'blabla, repeats '.$num_repeats.':' => \&do_one_repeat })); plan tests => 1; pass('benchmark : '.__FILE__); sub do_one_repeat { # this is where a run happens for 1 repeat of the benchmark } 1; __END__

    And finally I can do:

    perl Makefile.PL && make all && make test && make bench && make instal +l

    and do some eggs and toast on my hard-working CPU

    PS make bench suggested by tobyink is much cooler than make benchmarks

      My other thought, after reading your most recent post: your benchmarks are seeming rather like the concept of "author tests", which I (and other CPAN authors I've seen) put in the 'xt' directory rather than the 't' directory. See this snippet from my already-linked Makefile.PL preamble:

      # run author-tests on the original authtest :: $(TEST_D) xt && $(MAKE) test TEST_FILES='xt/*.t'
      You could then populate this temporary TEST_FILES value with the $h{BENCHMARK_FILES}. Or, you could still call it your bench target, but use syntax like the above to make it more like the rest of the Makefile.

        OK can try that. But I am reluctant to give away all the puns not making it to the bench!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1216932]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (None)
    As of 2024-04-25 00:55 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      No recent polls found