#!/usr/bin/env perl

=head1 NAME

dkbench - DKbench Perl Benchmark launch script

=head1 DESCRIPTION

This is the benchmarking script, part of the L<Benchmark::DKbench> distribution.

See POD on the main module for info:

 perldoc Benchmark::DKbench

=head1 SYNOPSIS

 dkbench [options]

 Options:
 --threads <i>,  -j <i> : Number of benchmark threads (default is 1).
 --multi,        -m     : Multi-threaded using all your CPU cores/threads.
 --max_threads <i>      : Override the cpu detection to specify max cpu threads.
 --iter <i>,     -i <i> : Number of suite iterations (with min/max/avg at the end).
 --stdev                : Show relative standard deviation (for iter > 1).
 --include <regex>      : Run only benchmarks that match regex.
 --exclude <regex>      : Do not run benchmarks that match regex.
 --time,         -t     : Report time (sec) instead of score.
 --quick,        -q     : Quick benchmark run (implies -t).
 --no_mce               : Do not run under MCE::Loop (implies -j 1).
 --scale <i>,    -s <i> : Scale the bench workload by x times (incompatible with -q).
 --skip_bio             : Skip BioPerl benchmarks.
 --skip_prove           : Skip Moose prove benchmark.
 --time_piece           : Run optional Time::Piece benchmark (see benchmark details).
 --bio_codons           : Run optional BioPerl Codons benchmark (does not scale well).
 --sleep <i>            : Sleep for <i> secs after each benchmark.
 --duration <i>, -d <i> : Minimum duration in seconds for suite run.
 --setup                : Download the Genbank data to enable the BioPerl tests.
 --datapath <path>      : Override the path where the expected benchmark data is found.
 --ver <num>            : Skip benchmarks added after the specified version.
 --help          -h     : Show basic help and exit.

The default run (no options) will run all the benchmarks both single-threaded and
multi-threaded (using all detected CPU cores/hyperthreads) and show you scores and
multi vs single threaded scalability.

=cut

use strict;
use warnings;

use lib 'lib';

use Digest;
use Benchmark::DKbench;
use Benchmark::DKbench::Setup;
use File::Spec::Functions;
use FindBin;
use Getopt::Long;
use Pod::Usage;

my %opt = ();
GetOptions (
    \%opt,
    'skip_bio',
    'skip_prove',
    'time_piece',
    'bio_codons',
    'quick|q',
    'time|t',
    'iter|i=i',
    'multi|m',
    'threads|j=i',
    'max_threads=i',
    'include=s',
    'exclude=s',
    'scale|s=i',
    'no_mce|n',
    'sleep=i',
    'stdev',
    'ver=s',
    'setup',
    'datapath=s',
    'duration|d=i',
    'help|h',
);

pod2usage({ -verbose => 1, -output => \*STDOUT, -noperldoc => 1}) if $opt{help};

Benchmark::DKbench::Setup::fetch_genbank($opt{datapath}) if $opt{setup};

check_kit();
my $max_threads = system_identity();
$max_threads  = $opt{max_threads} if $opt{max_threads};
$opt{threads} = $max_threads if $opt{multi} && $max_threads;
$opt{threads} = 1 if ($opt{threads} && $opt{threads} < 0) || $opt{no_mce};

if ($opt{threads} || !$max_threads || $max_threads == 1) {
    $opt{threads} ||= 1;
    suite_run(\%opt);
} else {
    $opt{threads} = 1;
    my %stat1 = suite_run(\%opt);
    print (("-"x40)."\n");
    $opt{threads} = $max_threads;
    my %stat2 = suite_run(\%opt);
    print (("-"x40)."\n");
    calc_scalability(\%stat1, \%stat2);
}

sub check_kit {
    warn "! Perl version v5.36 or later suggested as a comparison base\n"
        unless $] >= 5.036000;

    my %mod_ver = Benchmark::DKbench::Setup::cpan_versions();

    foreach my $module (sort keys %mod_ver) {
        next if $opt{skip_bio} && $module =~ /^Bio/;
        eval "use $module";
        my $ver = eval "\$${module}::VERSION" || 'none';
        unless ($ver eq $mod_ver{$module}) {
            my $msg = "! $module $mod_ver{$module} suggested as a comparison base ($ver found).";
            $msg .= " Old versions may cause a 'Fail'."
                if $mod_ver{$module} cmp $ver; # $ver is less
            if ($module =~ /^Bio/ && $ver eq 'none') {
                $opt{skip_bio}   = 1;
                $opt{bio_codons} = 0;
                $msg = "* BioPerl not found. You can install it to enable the optional BioPerl benchmarks.\n...applying --skip_bio.\n";
            }
            warn "$msg\n";
        }
    }

    my $datadir = $opt{datapath} || Benchmark::DKbench::Setup::datadir();
    die "!! No distribution data found (expected at $datadir). You could define a different data directory (containing M31.bmp, wikiX.html etc) with the -datapath option. Refer to the documentation for more about installation etc.\n" unless $datadir && -f catfile($datadir, "wiki0.html") && -f catfile($datadir, "M31.bmp");

    unless ($opt{skip_prove} || -e catfile($datadir, 't', 'recipes')) {
        $opt{skip_proove} = 1;
        warn "!! Moose test data folder not found. Was the distribution not installed properly? Applying --skip-prove.\n";
    }

    unless ($opt{skip_bio} || Benchmark::DKbench::Setup::has_genbank($opt{datapath})) {
        $opt{skip_bio} = 1;
        warn "!! gbbct5.seq missing, applying --skip_bio. Use --setup to fetch (or setup_dkbench).\n";
    }

    if ($opt{time_piece} && $^O =~ /darwin/ && !$opt{no_mce}) {
        $opt{time_piece} = 0;
        warn "!! Running localtime forked on MacOS is extremely slow, disabling Time::Piece. You may run it with --no_mce.\n"
    }
}
