mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-10 23:30:07 +00:00
206 lines
4.8 KiB
Perl
Executable File
206 lines
4.8 KiB
Perl
Executable File
#! /usr/bin/perl -w
|
|
# Copyright (C) 2013-2014 Free Software Foundation, Inc.
|
|
# This file is part of the GNU C Library.
|
|
|
|
# The GNU C Library is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
# License as published by the Free Software Foundation; either
|
|
# version 2.1 of the License, or (at your option) any later version.
|
|
|
|
# The GNU C Library is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# Lesser General Public License for more details.
|
|
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
# License along with the GNU C Library; if not, see
|
|
# <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
use strict;
|
|
use warnings;
|
|
# Generate a benchmark source file for a given input.
|
|
|
|
if (@ARGV < 1) {
|
|
die "Usage: bench.pl <function>"
|
|
}
|
|
|
|
my $func = $ARGV[0];
|
|
my @args;
|
|
my $ret = "void";
|
|
my $getret = "";
|
|
|
|
# We create a hash of inputs for each variant of the test.
|
|
my $variant = "";
|
|
my @curvals;
|
|
my %vals;
|
|
my @include_headers;
|
|
my @include_sources;
|
|
my $incl;
|
|
|
|
open INPUTS, "<$func-inputs" or die $!;
|
|
|
|
LINE:while (<INPUTS>) {
|
|
chomp;
|
|
|
|
# Directives.
|
|
if (/^## ([\w-]+): (.*)/) {
|
|
# Function argument types.
|
|
if ($1 eq "args") {
|
|
@args = split(":", $2);
|
|
}
|
|
|
|
# Function return type.
|
|
elsif ($1 eq "ret") {
|
|
$ret = $2;
|
|
}
|
|
|
|
elsif ($1 eq "includes") {
|
|
@include_headers = split (",", $2);
|
|
}
|
|
|
|
elsif ($1 eq "include-sources") {
|
|
@include_sources = split (",", $2);
|
|
}
|
|
|
|
# New variant. This is the only directive allowed in the body of the
|
|
# inputs to separate inputs into variants. All others should be at the
|
|
# top or else all hell will break loose.
|
|
elsif ($1 eq "name") {
|
|
|
|
# Save values in the previous variant.
|
|
my @copy = @curvals;
|
|
$vals{$variant} = \@copy;
|
|
|
|
# Prepare for the next.
|
|
$variant=$2;
|
|
undef @curvals;
|
|
next LINE;
|
|
}
|
|
|
|
else {
|
|
die "Unknown directive: ".$1;
|
|
}
|
|
}
|
|
|
|
# Skip over comments and blank lines.
|
|
if (/^#/ || /^$/) {
|
|
next LINE;
|
|
}
|
|
push (@curvals, $_);
|
|
}
|
|
|
|
|
|
my $bench_func = "#define CALL_BENCH_FUNC(v, i) $func (";
|
|
|
|
# Output variables. These include the return value as well as any pointers
|
|
# that may get passed into the function, denoted by the <> around the type.
|
|
my $outvars = "";
|
|
|
|
if ($ret ne "void") {
|
|
$outvars = "static $ret volatile ret;\n";
|
|
}
|
|
|
|
# Print the definitions and macros.
|
|
foreach $incl (@include_headers) {
|
|
print "#include <" . $incl . ">\n";
|
|
}
|
|
|
|
# Print the source files.
|
|
foreach $incl (@include_sources) {
|
|
print "#include \"" . $incl . "\"\n";
|
|
}
|
|
|
|
if (@args > 0) {
|
|
# Save values in the last variant.
|
|
$vals{$variant} = \@curvals;
|
|
my $struct =
|
|
"struct _variants
|
|
{
|
|
const char *name;
|
|
int count;
|
|
struct args *in;
|
|
};\n";
|
|
|
|
my $arg_struct = "struct args {";
|
|
|
|
my $num = 0;
|
|
my $arg;
|
|
foreach $arg (@args) {
|
|
if ($num > 0) {
|
|
$bench_func = "$bench_func,";
|
|
}
|
|
|
|
$_ = $arg;
|
|
if (/<(.*)\*>/) {
|
|
# Output variables. These have to be pointers, so dereference once by
|
|
# dropping one *.
|
|
$outvars = $outvars . "static $1 out$num;\n";
|
|
$bench_func = "$bench_func &out$num";
|
|
}
|
|
else {
|
|
$arg_struct = "$arg_struct $arg volatile arg$num;";
|
|
$bench_func = "$bench_func variants[v].in[i].arg$num";
|
|
}
|
|
|
|
$num = $num + 1;
|
|
}
|
|
|
|
$arg_struct = $arg_struct . "};\n";
|
|
$bench_func = $bench_func . ");\n";
|
|
|
|
print $bench_func;
|
|
print $arg_struct;
|
|
print $struct;
|
|
|
|
my $c = 0;
|
|
my $key;
|
|
|
|
# Print the input arrays.
|
|
foreach $key (keys %vals) {
|
|
my @arr = @{$vals{$key}};
|
|
|
|
print "struct args in" . $c . "[" . @arr . "] = {\n";
|
|
foreach (@arr) {
|
|
print "{$_},\n";
|
|
}
|
|
print "};\n\n";
|
|
$c += 1;
|
|
}
|
|
|
|
# The variants. Each variant then points to the appropriate input array we
|
|
# defined above.
|
|
print "struct _variants variants[" . (keys %vals) . "] = {\n";
|
|
$c = 0;
|
|
foreach $key (keys %vals) {
|
|
print "{\"$func($key)\", " . @{$vals{$key}} . ", in$c},\n";
|
|
$c += 1;
|
|
}
|
|
print "};\n\n";
|
|
# Finally, print the last set of macros.
|
|
print "#define NUM_VARIANTS $c\n";
|
|
print "#define NUM_SAMPLES(i) (variants[i].count)\n";
|
|
print "#define VARIANT(i) (variants[i].name)\n";
|
|
}
|
|
else {
|
|
print $bench_func . ");\n";
|
|
print "#define NUM_VARIANTS (1)\n";
|
|
print "#define NUM_SAMPLES(v) (1)\n";
|
|
print "#define VARIANT(v) FUNCNAME \"()\"\n"
|
|
}
|
|
|
|
# Print the output variable definitions.
|
|
print "$outvars\n";
|
|
|
|
# In some cases not storing a return value seems to result in the function call
|
|
# being optimized out.
|
|
if ($ret ne "void") {
|
|
$getret = "ret = ";
|
|
}
|
|
|
|
# And we're done.
|
|
print "#define BENCH_FUNC(i, j) ({$getret CALL_BENCH_FUNC (i, j);})\n";
|
|
|
|
print "#define FUNCNAME \"$func\"\n";
|
|
print "#include \"bench-skeleton.c\"\n";
|