1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
#!/bin/bash
# Test runner for small C++ performance tests
#
# Author: Chris Foster [chris42f (at) gmail (dot) com]
function print_help
{
cat <<EOF
Usage: cppbench [options] source_file
Utility for running multiple embedded benchmarks from a single c++ source file.
Comments in a specific format allow linewise modifications of the source to
generate various versions on the fly. These are compiled and the runtime of
the resulting executable is timed with the unix "time" utility. The results of
each benchmark in the suite are displayed in human-readable format.
Source code markup:
The source file contains several special comment types:
To specifiy lines which should be uncommented when running the
benchmarks name1, name2, there should be a comment of the form
// code_to_run; //##bench name1 name2 ...
The description for a particular benchmark is of the form
//##description name <string describing test>
Only benchmarks with a description line are considered.
Finally, the compiler, compiler optimizations and linker flags are given as
follows:
//##CXX g++
//##CXXFLAGS -O3 ...
//##LDFLAGS -lm ...
Options:
-h This help
-n name1,name2,... Specify benchmark names to run.
-S Dump assembly listings rather than running.
-v View the modified source before running the benchmark
-l List the benchmark tags defined in the source
EOF
}
if [[ -z $1 ]] ; then
print_help
exit -1
fi
viewSource=0
dumpAssembly=0
listTags=0
while [[ -n $1 ]] ; do
case $1 in
-n)
shift
benchmarkNamesToRun="$(echo $1 | tr ',' ' ')";;
-h)
print_help
exit 0;;
-v)
viewSource=1;;
-S)
dumpAssembly=1;;
-l)
listTags=1;;
*)
sourceFile=$1;;
esac
shift
done
if [[ ! -f $sourceFile ]] ; then
echo "Source file not found" 1>&2
exit -1
fi
# get all the benchmark names
benchmarkNamesAll=$(awk '/\/\/##description/ { print $2 }' $sourceFile)
if [[ -z $benchmarkNamesAll ]] ; then
echo "No benchmarks found" 1>&2
exit -1
fi
if [[ -z $benchmarkNamesToRun ]] ; then
benchmarkNamesToRun="$benchmarkNamesAll"
fi
if [[ $listTags == 1 ]] ; then
echo "Benchmark names:"
for tag in $benchmarkNamesAll ; do
echo " $tag"
done
exit 0
fi
# get compile flags
CXX=$(sed -n -e '/\/\/##CXX\>/ { s/\/\/##CXX\>//p ; q}' $sourceFile)
if [[ -z $CXX ]] ; then
CXX=c++
fi
CXXFLAGS=$(sed -n -e 's/\/\/##CXXFLAGS//p' $sourceFile)
if [[ $dumpAssembly == 1 ]] ; then
CXXFLAGS="${CXXFLAGS} -S"
else
LDFLAGS=$(sed -n -e 's/\/\/##LDFLAGS//p' $sourceFile)
fi
tmpFileName=_cppbench_tmp.cpp
tmpOutName=_cppbench_tmp
# Compile each benchmark.
for name in $benchmarkNamesToRun ; do
notThisNameAlt="\\($(echo $benchmarkNamesAll | sed -e "s/\<$name\> *//" -e 's/ \+/\\|/g')\\)"
sed -e '/\/\/##bench.*\<'"$name"'\>/ {s+\(//\|/\*\|\*/\)++}' -e '/\/\/##bench.*\<'"NOT_$notThisNameAlt"'\>/ {s/\/\///}' $sourceFile > $tmpFileName
echo "-------------------- Benchmark: $name --------------------"
eval echo $CXX $CXXFLAGS $sourceFile $LDFLAGS
if [[ $viewSource == 1 ]] ; then
less $tmpFileName
fi
# Use 'eval' here so that any environment variables in $CXXFLAGS are
# expanded correctly.
eval $CXX $CXXFLAGS $tmpFileName -o $tmpOutName $LDFLAGS
if [[ $? != 0 ]] ; then
exit -1
fi
if [[ $dumpAssembly == 1 ]] ; then
# Move assembly somewhere it can be viewed
mv $tmpOutName "${sourceFile%.cpp}.${name}.s"
echo "generated assembly: ${sourceFile%.cpp}.${name}.s"
else
# output description and time program run
echo -n "Description: "
sed -n -e 's/.*\/\/##description *\<'"$name"'\> *//p' $sourceFile
time ./$tmpOutName 2>/dev/null
echo
fi
done
rm -f $tmpFileName $tmpOutName
|