From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

use strict;
use File::Find ();
our $VERSION = "1.001";
my %SIGNIFICANT_CONFIG_KEYS = map { $_ => 1 } qw(
cc ccversion gccversion
optimize ccflags
usethreads usemultiplicity
uselargefiles
use64bitint use64bitall uselongdouble
usemymalloc useshrplib
osvers
);
sub new {
my $class = shift;
my $resdir = shift || "perlbench-results";
return undef unless -d $resdir;
my $self = bless {}, $class;
$self->_scan($resdir);
return $self;
}
sub _scan {
my($self, $dir) = @_;
$self->{dir} = $dir;
# locate result files
my @res;
File::Find::find(sub {
if (/\.pb$/) {
my $f = $File::Find::name;
$f = substr($f, length($dir) + 1);
$f =~ s,\\,/,g if $^O eq "MSWin32";
push(@res, $f);
}
}, $dir);
# read results
for my $f (@res) {
#print "$f\n";
my($hostname, $perls, $perl, $tests) = split("/", $f);
die unless $perls eq "perls";
die unless $tests eq "tests";
my $res = _read_pb_file("$dir/$f");
push(@{$self->{h}{$hostname}{p}{$perl}{t}}, $res);
}
# fill in additional information about hosts and perls
while(my($hostname, $hosthash) = each %{$self->{h} || {}}) {
#print "host $hostname\n";
while (my($perl, $perlhash) = each %{$hosthash->{p}}) {
#print " perl $perl\n";
my $perldir = "$dir/$hostname/perls/$perl";
my $version_txt = "$perldir/version.txt";
open(my $fh, "<", $version_txt) || die "Can't open $version_txt: $!";
local($_);
while (<$fh>) {
if (/^This is perl, v(\S+)/) {
$perlhash->{version} = $1;
$perlhash->{name} = "perl-$1";
}
if (/^Binary build (\d+.*) provided by ActiveState/) {
$perlhash->{name} .= " build $1";
$perlhash->{name} =~ s/^perl/ActivePerl/;
}
}
die "Can't determine perl version from $version_txt" unless $perlhash->{version};
close($fh);
if (open(my $fh, "<", "$perldir/config-summary.txt")) {
while (<$fh>) {
if (/^Summary of/ && / patch\s+(\d+)/) {
$perlhash->{version} .= "-p$1";
$perlhash->{name} .= " patch $1";
}
elsif (/\bDEBUGGING\b/) {
$perlhash->{name} .= " (DEBUGGING)";
}
}
close($fh);
}
if (open(my $fh, "<", "$perldir/config.sh")) {
while (<$fh>) {
if (/^(\w+)='([^']*)'$/) {
my($k, $v) = ($1, $2);
$perlhash->{config}{$1} = $2 if $SIGNIFICANT_CONFIG_KEYS{$1};
}
else {
chomp;
warn "Can't parse [$_]";
}
}
}
if (open(my $fh, "<", "$perldir/path.txt")) {
if (defined(my $path = <$fh>)) {
chomp($path);
$perlhash->{path} = $path;
}
}
$perlhash->{dir} = $perldir;
$perlhash->{host} = $hostname;
}
}
}
sub _read_pb_file {
my $file = shift;
open(my $fh, "<", $file) || die "Can't open '$file': $!";
my %hash;
local($_);
while (<$fh>) {
if (/^(\w[\w-]*)\s*:\s*(.*)/) {
my($k, $v) = ($1, $2);
$k = lc($k);
$k =~ s/-/_/g;
$hash{$k} = $v;
}
else {
warn "$file: $_";
}
}
close($fh);
#$hash{file} = $file;
return \%hash;
}
sub hosts {
my $self = shift;
die unless wantarray;
return sort keys %{$self->{h} || {}};
}
sub perls {
my($self, @hosts) = @_;
die unless wantarray;
@hosts = $self->hosts unless @hosts;
my @p;
for my $h (@hosts) {
push(@p, values %{$self->{h}{$h}{p}});
}
@p = sort { _vers_cmp($a->{version}, $b->{version}) || ($a->{config}{osvers} cmp $b->{config}{osvers}) } @p;
return @p;
}
sub _vers_cmp {
my($v1, $v2) = @_;
return $v1 cmp $v2;
}
1;