diff options
author | Andrea Arteaga <andyspiros@gmail.com> | 2012-10-16 12:20:45 +0200 |
---|---|---|
committer | Andrea Arteaga <andyspiros@gmail.com> | 2012-10-16 12:20:45 +0200 |
commit | 3d746fa02f581b1421e52f0352b120467fd3467d (patch) | |
tree | 4fabffd4430bd89eca881830ec52ba5e143b73e6 | |
parent | Updated LAPACK main program. Updated labels. Updated sample for LAPACK. (diff) | |
download | auto-numerical-bench-3d746fa02f581b1421e52f0352b120467fd3467d.tar.gz auto-numerical-bench-3d746fa02f581b1421e52f0352b120467fd3467d.tar.bz2 auto-numerical-bench-3d746fa02f581b1421e52f0352b120467fd3467d.zip |
Added and tested module lapackAccuracy.
-rw-r--r-- | btl/generic_bench/accuracy.hpp | 94 | ||||
-rw-r--r-- | btl/generic_bench/timers/LinuxTimer.hpp | 66 | ||||
-rw-r--r-- | btl/libs/LAPACK/accuracy.cpp | 89 | ||||
-rw-r--r-- | numbench/modules/__init__.py | 3 | ||||
-rw-r--r-- | numbench/modules/internal/btlBase.py | 8 | ||||
-rw-r--r-- | numbench/modules/internal/lapackAccuracyBase.py | 64 | ||||
-rw-r--r-- | numbench/modules/lapackAccuracy.py | 28 | ||||
-rw-r--r-- | numbench/utils/btl.py | 118 |
8 files changed, 408 insertions, 62 deletions
diff --git a/btl/generic_bench/accuracy.hpp b/btl/generic_bench/accuracy.hpp new file mode 100644 index 0000000..eb3265f --- /dev/null +++ b/btl/generic_bench/accuracy.hpp @@ -0,0 +1,94 @@ +//===================================================== +// Copyright (C) 2012 Andrea Arteaga <andyspiros@gmail.com> +//===================================================== +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program 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 General Public License for more details. +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +#ifndef ACCURACY_HPP +#define ACCURACY_HPP + +#include "timers/LinuxTimer.hpp" + +#include <string> +#include <vector> +#include <cmath> + +template<class Action> +void bench_accuracy (int size_min, int size_max, int nb_point, + bool silent = false) +{ + std::string filename = "accuracy_"+Action::name()+".dat"; + + if (!silent) + std::cout << "starting " << filename << std::endl; + + // Initialization vectors + std::vector<double> errors(nb_point); + std::vector<double> devs(nb_point); + std::vector<int> sizes(nb_point); + + // Initialization timer + LinuxTimer timer; + + // Log-distributed sizes + size_lin_log(nb_point, size_min, size_max, sizes); + + // Loop on sizes + for (int i = nb_point-1; i >= 0; --i) { + if (!silent) + std::cout << " " << "size = " << sizes[i] << ", " << std::flush; + + // Initialize action with given size + Action action(sizes[i]); + + int repetitions = 0; + double average = 0., stddev = 0., e; + + // Perform time loop and store average and standard deviation + timer.start(); + do { + e = action.getResidual(); + + average += e; + stddev += e*e; + ++repetitions; + + } while(timer.elapsed() < 1.); + + // Compute average and standard deviation + average /= repetitions; + stddev = std::sqrt(stddev/repetitions - average*average); + + errors[i] = average; + devs[i] = stddev; + + // Output + if (!silent) + std::cout << "average = " << average << ", stddev = " << stddev + << std::endl; + } + + // Dump the result + if (!silent) { + std::ofstream outfile(filename.c_str()); + + for (int i = 0; i < nb_point; ++i) + outfile << sizes[i] << " " << errors[i] << " " << devs[i] << "\n"; + + outfile.close(); + + } +} + +#endif // ACCURACY_HPP diff --git a/btl/generic_bench/timers/LinuxTimer.hpp b/btl/generic_bench/timers/LinuxTimer.hpp new file mode 100644 index 0000000..65bba8c --- /dev/null +++ b/btl/generic_bench/timers/LinuxTimer.hpp @@ -0,0 +1,66 @@ +//===================================================== +// Copyright (C) 2012 Andrea Arteaga <andyspiros@gmail.com> +//===================================================== +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program 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 General Public License for more details. +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +#ifndef LINUXTIMER_HPP +#define LINUXTIMER_HPP + +#include <sys/time.h> + +class LinuxTimer +{ +public: + LinuxTimer() : ZERO(0.) { } + + void start() + { + t = walltime(&ZERO); + } + + double elapsed() + { + return walltime(&t); + } + +private: + double t; + + const double ZERO; + + static double walltime(const double *t0) { + double mic; + double time; + double mega = 0.000001; + struct timeval tp; + struct timezone tzp; + static long base_sec = 0; + static long base_usec = 0; + + (void) gettimeofday(&tp, &tzp); + if (base_sec == 0){ + base_sec = tp.tv_sec; + base_usec = tp.tv_usec; + } + + time = (double)(tp.tv_sec - base_sec); + mic = (double)(tp.tv_usec - base_usec); + time = (time + mic * mega) - *t0; + return(time); + } +}; + + +#endif // LINUXTIMER_HPP diff --git a/btl/libs/LAPACK/accuracy.cpp b/btl/libs/LAPACK/accuracy.cpp new file mode 100644 index 0000000..6aa7d23 --- /dev/null +++ b/btl/libs/LAPACK/accuracy.cpp @@ -0,0 +1,89 @@ +//===================================================== +// Copyright (C) 2012 Andrea Arteaga <andyspiros@gmail.com> +//===================================================== +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program 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 General Public License for more details. +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// + +#include <string> +#include <iostream> + +// Include the numeric interface +#ifdef NI_LAPACK +# define NI_FORTRAN +#endif + +#include "NumericInterface.hpp" + +typedef NumericInterface<double> Interface; + +// Include the BTL +#include "utilities.h" +#include "bench.hh" +#include "accuracy.hpp" + +// Include the operations +#include "actionsLAPACK.hpp" + + +using namespace std; + +BTL_MAIN; + +int main(int argv, char **argc) +{ + bool + do_GeneralSolve=false, do_LeastSquaresSolve=false, + + do_LUdecomp=false, do_Choleskydecomp=false, do_QRdecomp=false + ; + + int N = 100; + + + for (int i = 1; i < argv; ++i) { + std::string arg = argc[i]; + + if (arg == "GeneralSolve") do_GeneralSolve = true; + else if (arg == "LeastSquaresSolve") do_LeastSquaresSolve = true; + + else if (arg == "LUdecomp") do_LUdecomp= true; + else if (arg == "Choleskydecomp") do_Choleskydecomp= true; + else if (arg == "QRdecomp") do_QRdecomp= true; + + // Check switch -N + else if (arg[0] == '-' && arg[1] == 'N') { + if (arg[2] != '\0') + N = atoi(arg.c_str()+2); + else + N = atoi(argc[++i]); + } + } + + if (do_GeneralSolve) + bench_accuracy<Action_GeneralSolve<Interface> >(MIN_MM,MAX_MM, N); + if (do_LeastSquaresSolve) + bench_accuracy<Action_LeastSquaresSolve<Interface> >(MIN_MM,MAX_MM, N); + + if(do_LUdecomp) + bench_accuracy<Action_LUdecomp<Interface> >(MIN_MM,MAX_MM, N); + if(do_Choleskydecomp) + bench_accuracy<Action_Choleskydecomp<Interface> >(MIN_MM,MAX_MM, N); + if(do_QRdecomp) + bench_accuracy<Action_QRdecomp<Interface> >(MIN_MM,MAX_MM, N); + + + return 0; +} + diff --git a/numbench/modules/__init__.py b/numbench/modules/__init__.py index 5b7cd3c..a734d3b 100644 --- a/numbench/modules/__init__.py +++ b/numbench/modules/__init__.py @@ -25,7 +25,8 @@ modnames = [ 'lapack', 'lapacke', 'scalapack', - 'fftw' + 'fftw', + 'lapackAccuracy' ] diff --git a/numbench/modules/internal/btlBase.py b/numbench/modules/internal/btlBase.py index 6b9fea1..edd2a50 100644 --- a/numbench/modules/internal/btlBase.py +++ b/numbench/modules/internal/btlBase.py @@ -24,9 +24,13 @@ def reportConf(*args): def runTest(self, test, btlconfig): + fnameprefix = btlconfig.get('fnameprefix', 'bench') + + fname = lambda j : fnameprefix + '_' + j + '_' + self.libname + '.dat' + # Check if results already exist - tmpres = dict( \ - [(i, pjoin(btlconfig['testdir'], 'bench_'+i+'_'+self.libname+'.dat')) \ + tmpres = dict(\ + [(i, pjoin(btlconfig['testdir'], fname(i))) \ for i in btlconfig['tests']]) if all([exists(i) for i in tmpres.values()]): diff --git a/numbench/modules/internal/lapackAccuracyBase.py b/numbench/modules/internal/lapackAccuracyBase.py new file mode 100644 index 0000000..6a72a32 --- /dev/null +++ b/numbench/modules/internal/lapackAccuracyBase.py @@ -0,0 +1,64 @@ +#===================================================== +# Copyright (C) 2012 Andrea Arteaga <andyspiros@gmail.com> +#===================================================== +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program 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 General Public License for more details. +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +import numbench.utils.btl as btl +import numbench.utils.alternatives as alt +import btlBase +from os.path import join as pjoin + + +availableTests = ('GeneralSolve', 'LeastSquaresSolve', + 'LUdecomp', 'Choleskydecomp', 'QRdecomp') +defaultTests = ('GeneralSolve', 'LUdecomp', 'Choleskydecomp') + + +def init(self, args): + self.tests = btl.selectTests(availableTests, args) + if len(self.tests) == 0: + self.tests = defaultTests + + +def getImplementations(self, test): + return alt.getImplementations(test['root'], self.libname) + + +def runTest(self, test, implementation): + # Set up btlconfig + btlconfig = dict ( + source='libs/LAPACK/accuracy.cpp', + exe=pjoin(test['testdir'], implementation, 'test'), + logdir=pjoin(test['logdir'], implementation), + testdir=pjoin(test['testdir'], implementation), + btlincludes=('libs/LAPACK',), + defines=("NI_NAME=" + self.libname, "NI_" + self.libname.upper()), + flags=alt.getFlags(test, self.libname, implementation), + tests = self.tests, + fnameprefix = 'accuracy' + ) + + return btlBase.runTest(self, test, btlconfig) + +getTests = btlBase.getTests +reportConf = btlBase.reportConf + +def reportConf(*args): + return dict( + xscale='log', + yscale='log', + xlabel='size', + ylabel='relative error' + ) diff --git a/numbench/modules/lapackAccuracy.py b/numbench/modules/lapackAccuracy.py new file mode 100644 index 0000000..ad805a9 --- /dev/null +++ b/numbench/modules/lapackAccuracy.py @@ -0,0 +1,28 @@ +#===================================================== +# Copyright (C) 2012 Andrea Arteaga <andyspiros@gmail.com> +#===================================================== +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program 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 General Public License for more details. +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +import internal.lapackAccuracyBase as base + +class Module: + libname = 'lapack' + descr = 'Accuracy test module for LAPACK implementations' + + __init__ = base.init + getImplementations = base.getImplementations + runTest = base.runTest + getTests = base.getTests + reportConf = base.reportConf diff --git a/numbench/utils/btl.py b/numbench/utils/btl.py index cc0a7fe..9888e14 100644 --- a/numbench/utils/btl.py +++ b/numbench/utils/btl.py @@ -30,32 +30,32 @@ btldefines = ('NDEBUG',) def compileTest(test, btlconfig): - + # Include directories includes = [pjoin(cfg.btldir, i) for i in btlincludes] if btlconfig.has_key('btlincludes'): includes += [pjoin(cfg.btldir, i) for i in btlconfig['btlincludes']] if btlconfig.has_key('includes'): includes += btlconfig['includes'] - + # Linked libraries libraries = list(btllibraries) if btlconfig.has_key('libraries'): libraries += btlconfig['libraries'] - + # Library directories libdirs = [pjoin(test['root'], cfg.libdir)] if btlconfig.has_key('libdirs'): libdirs += btlconfig['libdirs'] - + # Defined preprocessor macros defines = list(btldefines) if btlconfig.has_key('defines'): defines += btlconfig['defines'] - + # Other flags flags = [] - + # Interpret flags interpret = shlex.split(bu.run_cmd(['portageq', 'envvar', 'CXXFLAGS'])) if btlconfig.has_key('flags'): @@ -71,81 +71,81 @@ def compileTest(test, btlconfig): else: flags.append(flag) del interpret - - + + # Set compile-time environment compileenv = test['compileenv'].copy() - + if compileenv.has_key('INCLUDE_PATH'): compileenv['INCLUDE_PATH'] += ':' + ':'.join(includes) else: compileenv['INCLUDE_PATH'] = ':'.join(includes) - + libenv = ':'.join(libdirs) if compileenv.has_key('LIBRARY_PATH'): compileenv['LIBRARY_PATH'] += ':' + libenv else: compileenv['LIBRARY_PATH'] = libenv - + if compileenv.has_key('LD_LIBRARY_PATH'): compileenv['LD_LIBRARY_PATH'] += ':' + libenv else: compileenv['LD_LIBRARY_PATH'] = libenv - + pathenv = ':'.join([pjoin(test['root'], l) for l in ('bin', 'usr/bin')]) if compileenv.has_key('PATH'): compileenv['PATH'] += pathenv else: compileenv['PATH'] = pathenv - + # Set run-time environment runenv = test['runenv'].copy() - + if runenv.has_key('LD_LIBRARY_PATH'): runenv['LD_LIBRARY_PATH'] += ':' + libenv else: runenv['LD_LIBRARY_PATH'] = libenv - + pathenv = ':'.join([pjoin(test['root'], l) for l in ('bin', 'usr/bin')]) if runenv.has_key('PATH'): runenv['PATH'] += pathenv else: runenv['PATH'] = pathenv - + btlconfig['runenv'] = runenv - - + + # Set C++ compiler cxx = '/usr/bin/g++' - + portageq_cxx = bu.run_cmd(['portageq', 'envvar', 'CXX']) if portageq_cxx.strip() != "": cxx = portageq_cxx del portageq_cxx - + if btlconfig.has_key('CXX'): cxx = btlconfig['CXX'] - + if compileenv.has_key('CXX'): cxx = compileenv['CXX'] - - + + # Form command-line arguments args = [cxx, pjoin(cfg.btldir, btlconfig['source']), '-o', btlconfig['exe']] - args += ['-I'+I for I in includes] - args += ['-l'+l for l in libraries] - args += ['-L'+L for L in libdirs] - args += ['-D'+D for D in defines] + args += ['-I' + I for I in includes] + args += ['-l' + l for l in libraries] + args += ['-L' + L for L in libdirs] + args += ['-D' + D for D in defines] args += flags - + # Open logfile and write environment bu.mkdir(btlconfig['logdir']) logfile = pjoin(btlconfig['logdir'], "btlCompile.log") logfs = file(logfile, 'w') - logfs.write('\n'.join([n+'='+v for n,v in compileenv.items()])) - logfs.write(3*'\n' + ' '.join(args) + 3*'\n') + logfs.write('\n'.join([n + '=' + v for n, v in compileenv.items()])) + logfs.write(3 * '\n' + ' '.join(args) + 3 * '\n') logfs.flush() - + # Execute compilation bu.mkdir(dirname(btlconfig['exe'])) proc = sp.Popen(args, stdout=logfs, stderr=sp.STDOUT, env=compileenv) @@ -156,7 +156,7 @@ def compileTest(test, btlconfig): logfs.write("\n\n<<< Compilation terminated successfully >>>") else: logfs.write("\n\n<<< Compilation failed >>>") - + # Close, return logfs.close() return retcode @@ -167,30 +167,30 @@ def runTest(test, btlconfig): runenv = btlconfig['runenv'] if not runenv.has_key('BTL_CONFIG'): runenv['BTL_CONFIG'] = '--real' - + # Check linking logfs = file(pjoin(btlconfig['logdir'], 'btlLinking.log'), 'w') sp.Popen(['ldd', '-v', btlconfig['exe']], stdout=logfs, env=runenv).wait() logfs.close() - - + + # Prepare arguments args = (btlconfig['exe'],) + tuple(btlconfig['tests']) if btlconfig.has_key('preargs'): args = tuple(btlconfig['preargs']) + args if btlconfig.has_key('postargs'): args = args + tuple(btlconfig['postargs']) - + # Open log logfs = file(pjoin(btlconfig['logdir'], "btlRun.log"), 'w') - logfs.write('\n'.join([n+'='+v for n,v in runenv.items()])) - logfs.write(3*'\n' + ' '.join(args) + 3*'\n') + logfs.write('\n'.join([n + '=' + v for n, v in runenv.items()])) + logfs.write(3 * '\n' + ' '.join(args) + 3 * '\n') logfs.flush() - + # Error log errfname = pjoin(btlconfig['logdir'], "btlRun.err") errfs = file(errfname, 'w') - + # Open pipe try: proc = sp.Popen(args, bufsize=1, stdout=sp.PIPE, stderr=errfs, \ @@ -200,36 +200,36 @@ def runTest(test, btlconfig): Print('Execution failed to start') Print('Command line: ' + ' '.join(args)) return -1, None - - + + result = {} - + # Interpret output Print('Begin execution') while True: # Use regexps to see which operation is benchmarked now linere = \ - r'.*/bench.hh \[[0-9]*?] : starting (bench_(.*)_[a-zA-Z0-9]*.dat)' + r'.*starting ([a-zA-Z]*_(.*)_[a-zA-Z0-9]*.dat)' operation = None while operation is None: line = proc.stdout.readline() if not line: break - + try: resfile, operation = re.match(linere, line).groups() logfs.write(line) except: pass - + # Check is program is terminated if operation is None: break - + result[operation] = pjoin(btlconfig['testdir'], resfile) Print(operation + " -> " + resfile) - - + + # Many different sizes for each operation test Print.down() cur = 0 @@ -243,7 +243,7 @@ def runTest(test, btlconfig): return 1, None logfs.write(outline) logfs.flush() - + # Interpret line outline = outline.strip() try: @@ -253,25 +253,25 @@ def runTest(test, btlconfig): except: cur += 1 Print(outline) - - + + Print.up() proc.wait() Print("Execution finished with return code " + str(proc.returncode)) - + # Close logs logfs.close() errp = errfs.tell() errfs.close() if errp == 0: os.unlink(errfname) - - + + # Close, return logfs.close() return proc.returncode, result - - - + + + def selectTests(availableTests, args): - return tuple([i for i in availableTests if i in args]) + return tuple([i for i in availableTests if i in args]) |