1 |
commit: 5fb81447de9eac0011f18fbfa2713ad1291c9d9e |
2 |
Author: spiros <andyspiros <AT> gmail <DOT> com> |
3 |
AuthorDate: Sun Jul 3 16:25:13 2011 +0000 |
4 |
Commit: Andrea Arteaga <andyspiros <AT> gmail <DOT> com> |
5 |
CommitDate: Sun Jul 3 16:25:13 2011 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/auto-numerical-bench.git;a=commit;h=5fb81447 |
7 |
|
8 |
Added accuracy for BLAS. Many bugfix. |
9 |
|
10 |
--- |
11 |
.../autobench/files/python/accuracy/main_blas.cpp | 217 ++++++++++++++++++++ |
12 |
app-benchmarks/autobench/files/python/blas.py | 69 +------ |
13 |
.../autobench/files/python/blas_accuracy.py | 216 +++++++++++++++++++ |
14 |
.../files/python/{blas.py => blasbase.py} | 23 +- |
15 |
app-benchmarks/autobench/files/python/btlbase.py | 80 +++++--- |
16 |
app-benchmarks/autobench/files/python/cblas.py | 69 +------ |
17 |
app-benchmarks/autobench/files/python/main.py | 8 +- |
18 |
7 files changed, 506 insertions(+), 176 deletions(-) |
19 |
|
20 |
diff --git a/app-benchmarks/autobench/files/python/accuracy/main_blas.cpp b/app-benchmarks/autobench/files/python/accuracy/main_blas.cpp |
21 |
new file mode 100644 |
22 |
index 0000000..4a7a735 |
23 |
--- /dev/null |
24 |
+++ b/app-benchmarks/autobench/files/python/accuracy/main_blas.cpp |
25 |
@@ -0,0 +1,217 @@ |
26 |
+#include <iostream> |
27 |
+#include <fstream> |
28 |
+#include <sstream> |
29 |
+#include <string> |
30 |
+#include <vector> |
31 |
+#include <cmath> |
32 |
+#include <cstdlib> |
33 |
+ |
34 |
+#define ADD_ |
35 |
+extern "C" { |
36 |
+ void daxpy_(const int*, const double*, const double*, const int*, double*, const int*); |
37 |
+ void dgemv_(const char*, const int*, const int*, const double*, const double*, const int*, const double*, const int*, const double*, double*, const int*); |
38 |
+ void dtrsv_(const char*, const char*, const char*, const int*, const double*, const int*, double*, const int*); |
39 |
+ void dgemm_(const char*, const char*, const int*, const int*, const int*, const double*, const double*, const int*, const double*, const int*, const double*, double*, const int*); |
40 |
+ double dnrm2_(const int*, const double*, const int*); |
41 |
+} |
42 |
+ |
43 |
+using namespace std; |
44 |
+ |
45 |
+template<typename T> |
46 |
+void print_array(const int& N, const T* array) { |
47 |
+ for (const T *p = array, *e = array+N; p != e; ++p) |
48 |
+ cout << *p << " "; |
49 |
+} |
50 |
+ |
51 |
+template<typename T> |
52 |
+void print_matrix(const int& rows, const int& cols, const T* matrix) { |
53 |
+ for (int row = 0; row < rows; ++row) { |
54 |
+ for (int col = 0; col < cols; ++col) |
55 |
+ cout << *(matrix + rows*col + row) << " "; |
56 |
+ cout << "\n"; |
57 |
+ } |
58 |
+} |
59 |
+ |
60 |
+template<typename T> |
61 |
+vector<T> logspace(const T& min, const T& max, const unsigned& N) |
62 |
+{ |
63 |
+ vector<T> result; |
64 |
+ result.reserve(N); |
65 |
+ |
66 |
+ const double emin = log(static_cast<double>(min)), emax = log(static_cast<double>(max)); |
67 |
+ double e, r = (emax-emin)/(N-1); |
68 |
+ for (unsigned i = 0; i < N; ++i) { |
69 |
+ e = emin + i*r; |
70 |
+ result.push_back(static_cast<T>(exp(e))); |
71 |
+ } |
72 |
+ |
73 |
+ return result; |
74 |
+} |
75 |
+ |
76 |
+double axpy_test(const int& size) |
77 |
+{ |
78 |
+ // Set up |
79 |
+ const int ONE = 1; |
80 |
+ const double alpha = 1./3.; |
81 |
+ double *x = new double[size], *y = new double[size]; |
82 |
+ for (int i = 1; i <= size; ++i) { |
83 |
+ x[i-1] = 10. / i; |
84 |
+ y[i-1] = -10./(3. * i); |
85 |
+ } |
86 |
+ |
87 |
+ // Execute |
88 |
+ daxpy_(&size, &alpha, x, &ONE, y, &ONE); |
89 |
+ |
90 |
+ // Compute the error |
91 |
+ double error = dnrm2_(&size, y, &ONE); |
92 |
+ |
93 |
+ delete[] x; delete[] y; |
94 |
+ return error; |
95 |
+} |
96 |
+ |
97 |
+double matrix_vector_test(const int& size) |
98 |
+{ |
99 |
+ // Set up |
100 |
+ const int ONE = 1; |
101 |
+ char TRANS = 'N'; |
102 |
+ const double alpha = 1./size, beta = 1.; |
103 |
+ double *A = new double[size*size], *x = new double[size], *y = new double[size]; |
104 |
+ for (int i = 1; i <= size; ++i) { |
105 |
+ x[i-1] = i; |
106 |
+ y[i-1] = -i; |
107 |
+ for (int j = 1; j <= size; ++j) { |
108 |
+ *(A+i-1+(j-1)*size) = static_cast<double>(i)/j; |
109 |
+ } |
110 |
+ } |
111 |
+ |
112 |
+ // Execute |
113 |
+ dgemv_(&TRANS, &size, &size, &alpha, A, &size, x, &ONE, &beta, y, &ONE); |
114 |
+ |
115 |
+ // Compute the error |
116 |
+ double error = dnrm2_(&size, y, &ONE); |
117 |
+ |
118 |
+ delete[] A; delete[] x; delete[] y; |
119 |
+ return error; |
120 |
+} |
121 |
+ |
122 |
+double trisolve_vector_test(const int& size) |
123 |
+{ |
124 |
+ // Set up |
125 |
+ const int ONE = 1; |
126 |
+ char UPLO = 'U', TRANS = 'N', DIAG = 'U'; |
127 |
+ double *A = new double[size*size], *x = new double[size+1], *y = new double[size]; |
128 |
+ const double alpha = 1.; |
129 |
+ x[size] = 0.; |
130 |
+ for (int i = 1; i <= size; ++i) { |
131 |
+ x[size-i] = x[size-i+1] + 1./i; |
132 |
+ y[i-1] = -1.; |
133 |
+ for (int j = i; j <= size; ++j) { |
134 |
+ *(A+i-1+(j-1)*size) = 1. / (j-i+1); |
135 |
+ } |
136 |
+ } |
137 |
+ |
138 |
+ // Execute |
139 |
+ dtrsv_(&UPLO, &TRANS, &DIAG, &size, A, &size, x, &ONE); |
140 |
+ daxpy_(&size, &alpha, x, &ONE, y, &ONE); |
141 |
+ double error = dnrm2_(&size, y, &ONE); |
142 |
+ |
143 |
+ delete[] A; delete[] x; delete[] y; |
144 |
+ return error; |
145 |
+} |
146 |
+ |
147 |
+double matrix_matrix_test(const int& size) |
148 |
+{ |
149 |
+ // rand48 initialization |
150 |
+ srand48(5); |
151 |
+ |
152 |
+ // sigma = SUM[k=1..size](k) |
153 |
+ double sigma = 0; |
154 |
+ for (int i = 1; i <= size; ++i) |
155 |
+ sigma += i; |
156 |
+ |
157 |
+ // Set up |
158 |
+ const int ONE = 1; |
159 |
+ char TRANS = 'N'; |
160 |
+ const double alpha = drand48(), beta = -2. * alpha * sigma; |
161 |
+ const int size2 = size*size; |
162 |
+ double *A = new double[size2], *B = new double[size2], *C = new double[size2]; |
163 |
+ |
164 |
+ for (int i = 1; i <= size; ++i) |
165 |
+ for (int j = 1; j <= size; ++j) { |
166 |
+ *(A+i-1+size*(j-1)) = static_cast<double>(j)/i; |
167 |
+ *(B+i-1+size*(j-1)) = j; |
168 |
+ *(C+i-1+size*(j-1)) = static_cast<double>(j)/(2.*i); |
169 |
+ } |
170 |
+ |
171 |
+ // Execute |
172 |
+ dgemm_(&TRANS, &TRANS, &size, &size, &size, &alpha, A, &size, B, &size, &beta, C, &size); |
173 |
+ double error = dnrm2_(&size2, C, &ONE); |
174 |
+ |
175 |
+ delete[] A; delete[] B; delete[] C; |
176 |
+ return error; |
177 |
+} |
178 |
+ |
179 |
+template<typename T> |
180 |
+void test(T t, const int& min, const int& max, const unsigned& N, const string& name) |
181 |
+{ |
182 |
+ ostringstream fname; |
183 |
+ ofstream fout; |
184 |
+ double result; |
185 |
+ int N_; |
186 |
+ |
187 |
+ fname << "accuracy_" << name << "_blas.dat"; |
188 |
+ fout.open(fname.str().c_str()); |
189 |
+ cout << name << " test -- " << fname.str() << endl; |
190 |
+ vector<int> axpy_sizes = logspace(min, max, N); |
191 |
+ N_ = 0; |
192 |
+ for (vector<int>::const_reverse_iterator i = axpy_sizes.rbegin(), e = axpy_sizes.rend(); i!=e; ++i) { |
193 |
+ result = t(*i); |
194 |
+ fout << *i << " " << result << endl; |
195 |
+ cout << " size: " << *i << " " << result << " (" << ++N_ << "/100)" << endl; |
196 |
+ } |
197 |
+ fout.close(); |
198 |
+ cout << "\n"; |
199 |
+} |
200 |
+ |
201 |
+int main() |
202 |
+{ |
203 |
+ bool |
204 |
+ axpy=false, axpby=false, rot=false, |
205 |
+ matrix_vector=false, atv=false, symv=false, syr2=false, ger=false, trisolve_vector=false, |
206 |
+ matrix_matrix=false, aat=false, trisolve_matrix=false, trmm=false |
207 |
+ ; |
208 |
+ |
209 |
+ |
210 |
+ for (int i = 1; i < argv; ++i) { |
211 |
+ std::string arg = argc[i]; |
212 |
+ if (arg == "axpy") axpy = true; |
213 |
+ else if (arg == "axpby") axpby = true; |
214 |
+ else if (arg == "rot") rot = true; |
215 |
+ else if (arg == "matrix_vector") matrix_vector = true; |
216 |
+ else if (arg == "atv") atv = true; |
217 |
+ else if (arg == "symv") symv = true; |
218 |
+ else if (arg == "syr2") syr2 = true; |
219 |
+ else if (arg == "ger") ger = true; |
220 |
+ else if (arg == "trisolve_vector") trisolve_vector = true; |
221 |
+ else if (arg == "matrix_matrix") matrix_matrix = true; |
222 |
+ else if (arg == "aat") aat = true; |
223 |
+ else if (arg == "trisolve_matrix") trisolve_matrix = true; |
224 |
+ else if (arg == "trmm") trmm = true; |
225 |
+ |
226 |
+ |
227 |
+ /* AXPY test */ |
228 |
+ if (axpy) |
229 |
+ test(axpy_test, 1, 1000000, 100, "axpy"); |
230 |
+ |
231 |
+ if (matrix_vector) |
232 |
+ test(matrix_vector_test, 1, 3000, 100, "matrix_vector"); |
233 |
+ |
234 |
+ if (trisolve_vector) |
235 |
+ test(trisolve_vector_test, 1, 3000, 100, "trisolve_vector"); |
236 |
+ |
237 |
+ if (matrix_matrix) |
238 |
+ test(matrix_matrix_test, 1, 2000, 100, "matrix_matrix"); |
239 |
+ |
240 |
+ return 0; |
241 |
+ |
242 |
+} |
243 |
|
244 |
diff --git a/app-benchmarks/autobench/files/python/blas.py b/app-benchmarks/autobench/files/python/blas.py |
245 |
index 52bb221..f6193ef 100644 |
246 |
--- a/app-benchmarks/autobench/files/python/blas.py |
247 |
+++ b/app-benchmarks/autobench/files/python/blas.py |
248 |
@@ -1,69 +1,6 @@ |
249 |
-import os, btlbase |
250 |
-import subprocess as sp |
251 |
-import shlex |
252 |
+import blasbase |
253 |
|
254 |
-class Module(btlbase.BTLBase): |
255 |
+class Module(blasbase.BLASBase): |
256 |
def _initialize(self): |
257 |
self.libname = "blas" |
258 |
- self.avail1 = ['axpy', 'axpby', 'rot'] |
259 |
- self.avail2 = ['matrix_vector','atv','symv','syr2','ger', |
260 |
- 'trisolve_vector'] |
261 |
- self.avail3 = ['matrix_matrix', 'aat', 'trisolve_matrix', 'trmm'] |
262 |
- self.avail = self.avail1 + self.avail2 + self.avail3 |
263 |
- |
264 |
- def _parse_args(self, args): |
265 |
- # Parse arguments |
266 |
- tests = [] |
267 |
- for i in args: |
268 |
- if i == '1': |
269 |
- tests += avail1 |
270 |
- continue |
271 |
- if i == '2': |
272 |
- tests += avail2 |
273 |
- continue |
274 |
- if i == '3': |
275 |
- tests += avail3 |
276 |
- continue |
277 |
- if i in self.avail: |
278 |
- tests.append(i) |
279 |
- continue |
280 |
- raise Exception("Argument not recognized: " + i) |
281 |
- |
282 |
- # Sort tests |
283 |
- self.tests = [i for i in self.avail if i in tests] |
284 |
- |
285 |
- # If no test is specified, then choose four standard tests |
286 |
- if len(self.tests) == 0: |
287 |
- self.tests = ['axpy', 'matrix_vector', \ |
288 |
- 'trisolve_vector', 'matrix_matrix'] |
289 |
- |
290 |
- @staticmethod |
291 |
- def _btl_source(): |
292 |
- return "/libs/BLAS/main.cpp" |
293 |
- |
294 |
- @staticmethod |
295 |
- def _btl_includes(): |
296 |
- return ["/libs/BLAS"] |
297 |
- |
298 |
- def _btl_defines(self): |
299 |
- return ["CBLASNAME=" + self.libname, "BLAS_INTERFACE"] |
300 |
- |
301 |
- def _get_flags(self, root, impl, libdir): |
302 |
- # Retrieve pkgconfig settings and map the directories to the new root |
303 |
- path = "%s/etc/env.d/alternatives/%s/%s/%s/pkgconfig" % \ |
304 |
- (root, self.libname, impl, libdir) |
305 |
- pkgconf = sp.Popen('pkg-config --libs --cflags blas', shell=True, \ |
306 |
- stdout=sp.PIPE, env={'PKG_CONFIG_PATH':path}).communicate()[0] |
307 |
- pkgconf = pkgconf.replace('-L/', '-L'+root+'/') |
308 |
- pkgconf = pkgconf.replace('-I/', '-I'+root+'/') |
309 |
- return shlex.split(pkgconf) |
310 |
- |
311 |
- |
312 |
- def get_impls(self, root): |
313 |
- output = sp.Popen( |
314 |
- ['eselect', '--no-color', '--brief', self.libname, 'list'], |
315 |
- env={'ROOT' : root}, stdout=sp.PIPE |
316 |
- ).communicate()[0] |
317 |
- return output.strip().split('\n') |
318 |
- |
319 |
-del btlbase |
320 |
+ blasbase.BLASBase._initialize(self) |
321 |
\ No newline at end of file |
322 |
|
323 |
diff --git a/app-benchmarks/autobench/files/python/blas_accuracy.py b/app-benchmarks/autobench/files/python/blas_accuracy.py |
324 |
new file mode 100644 |
325 |
index 0000000..9e13ed2 |
326 |
--- /dev/null |
327 |
+++ b/app-benchmarks/autobench/files/python/blas_accuracy.py |
328 |
@@ -0,0 +1,216 @@ |
329 |
+from pprint import pprint |
330 |
+from os.path import join as pjoin |
331 |
+import subprocess as sp |
332 |
+import shlex, os |
333 |
+from htmlreport import HTMLreport |
334 |
+ |
335 |
+try: |
336 |
+ import matplotlib.pyplot as plt |
337 |
+ import numpy as np |
338 |
+ with_images = True |
339 |
+except ImportError: |
340 |
+ sys.stderr.write('Error: matplotlib and numpy are needed' + \ |
341 |
+ 'in order to generate the reports!\n') |
342 |
+ sys.stderr.write('Continue anyway.\n\n') |
343 |
+ with_images = False |
344 |
+ |
345 |
+run_cmd = lambda c : sp.Popen(c, stdout=sp.PIPE).communicate()[0] |
346 |
+ |
347 |
+class Module: |
348 |
+ def __init__(self, Print, libdir, args): |
349 |
+ self.Print = Print |
350 |
+ self.libdir = libdir |
351 |
+ self.summary = False |
352 |
+ self.summary_only = False |
353 |
+ |
354 |
+ self._initialize() |
355 |
+ |
356 |
+ passargs = [] |
357 |
+ for i in args: |
358 |
+ if i == '-S': |
359 |
+ self.summary_only = True |
360 |
+ continue |
361 |
+ elif i == '-s': |
362 |
+ self.summary = True |
363 |
+ continue |
364 |
+ else: |
365 |
+ passargs += [i] |
366 |
+ |
367 |
+ self._parse_args(passargs) |
368 |
+ |
369 |
+ def _initialize(self): |
370 |
+ self.libname = 'blas' |
371 |
+ self.avail=['axpy', 'matrix_vector', 'trisolve_vector', 'matrix_matrix'] |
372 |
+ |
373 |
+ def _parse_args(self, args): |
374 |
+ # Parse arguments |
375 |
+ tests = [] |
376 |
+ for i in args: |
377 |
+ if i in self.avail: |
378 |
+ tests.append(i) |
379 |
+ continue |
380 |
+ raise Exception("Argument not recognized: " + i) |
381 |
+ |
382 |
+ # Sort tests |
383 |
+ self.tests = [i for i in self.avail if i in tests] |
384 |
+ |
385 |
+ # If no test is specified, then do everything |
386 |
+ if len(self.tests) == 0: |
387 |
+ self.tests = self.avail |
388 |
+ |
389 |
+ def _get_flags(self, root, impl, libdir): |
390 |
+ # Retrieve pkgconfig settings and map the directories to the new root |
391 |
+ path = pjoin(root, "etc/env.d/alternatives", \ |
392 |
+ self.libname, impl, libdir, "pkgconfig") |
393 |
+ cmd = ['pkg-config', '--libs', '--cflags', self.libname] |
394 |
+ env = {'PKG_CONFIG_PATH':path} |
395 |
+ pkgconf = sp.Popen(cmd, stdout=sp.PIPE, env=env).communicate()[0] |
396 |
+ pkgconf = pkgconf.replace('-L/', '-L'+root+'/') |
397 |
+ pkgconf = pkgconf.replace('-I/', '-I'+root+'/') |
398 |
+ return shlex.split(pkgconf) |
399 |
+ |
400 |
+ def get_impls(self, root): |
401 |
+ output = sp.Popen( |
402 |
+ ['eselect', '--no-color', '--brief', 'blas', 'list'], |
403 |
+ env={'ROOT' : root}, stdout=sp.PIPE |
404 |
+ ).communicate()[0] |
405 |
+ return output.strip().split('\n') |
406 |
+ |
407 |
+ def run_test(self, root, impl, testdir, env, logdir): |
408 |
+ Print = self.Print |
409 |
+ libdir = self.libdir |
410 |
+ name = self.libname |
411 |
+ files = [pjoin(testdir, 'accuracy_%s_%s.dat' % (op, name)) \ |
412 |
+ for op in self.tests] |
413 |
+ |
414 |
+ results = {} |
415 |
+ for op in self.tests: |
416 |
+ results[op] = pjoin(testdir, 'accuracy_%s_%s.dat' % (op, name)) |
417 |
+ |
418 |
+ # Prepare the environment |
419 |
+ if env.has_key('LIBRARY_PATH'): |
420 |
+ env['LIBRARY_PATH'] = pjoin(root,libdir) + ":" + env['LIBRARY_PATH'] |
421 |
+ else: |
422 |
+ env['LIBRARY_PATH'] = pjoin(root, libdir) |
423 |
+ |
424 |
+ if env.has_key('INCLUDE_PATH'): |
425 |
+ env['INCLUDE_PATH'] = \ |
426 |
+ pjoin(root, "/usr/include") + ":" + env['INCLUDE_PATH'] |
427 |
+ else: |
428 |
+ env['INCLUDE_PATH'] = pjoin(root, "/usr/include") |
429 |
+ |
430 |
+ if env.has_key('LD_LIBRARY_PATH'): |
431 |
+ env['LD_LIBRARY_PATH'] = \ |
432 |
+ pjoin(root, libdir) + ":" + env['LD_LIBRARY_PATH'] |
433 |
+ else: |
434 |
+ env['LD_LIBRARY_PATH'] = pjoin(root, libdir) |
435 |
+ |
436 |
+ # Backup the environment |
437 |
+ oldenv = {} |
438 |
+ for k in env.keys(): |
439 |
+ oldenv[k] = \ |
440 |
+ (os.environ.has_key(k) and (os.environ[k],) or (None,))[0] |
441 |
+ |
442 |
+ # Set the environment |
443 |
+ for k,v in env.items(): |
444 |
+ os.environ[k] = v |
445 |
+ |
446 |
+ # Compile test suite |
447 |
+ exe = pjoin(testdir, 'test') |
448 |
+ source = "accuracy/main_blas.cpp" |
449 |
+ flags = self._get_flags(root, impl, libdir) |
450 |
+ cxxflags = run_cmd(['portageq', 'envvar', 'CXXFLAGS']).strip() |
451 |
+ cxx = 'g++' |
452 |
+ cmd = [cxx, '-o', exe, source] + flags + shlex.split(cxxflags) |
453 |
+ logfile = pjoin(logdir, 'compile.log') |
454 |
+ p = sp.Popen(cmd, stdout=file(logfile, 'w'), stderr=sp.STDOUT) |
455 |
+ p.wait() |
456 |
+ if p.returncode != 0: |
457 |
+ Print("Compilation failed") |
458 |
+ Print("See log: " + logfile) |
459 |
+ return |
460 |
+ Print("Compilation successful") |
461 |
+ |
462 |
+ # Run test |
463 |
+ logfile = file(pjoin(logdir, name+"_run.log"), 'w') |
464 |
+ cmd = [pjoin(testdir,"test")] + self.tests |
465 |
+ proc = sp.Popen(cmd, bufsize=1, stdout=sp.PIPE, stderr=sp.PIPE, |
466 |
+ cwd=testdir) |
467 |
+ Print.down() |
468 |
+ while True: |
469 |
+ line = proc.stdout.readline() |
470 |
+ if not line: |
471 |
+ break |
472 |
+ logfile.write(line) |
473 |
+ if len(line.strip()) == 0: |
474 |
+ continue |
475 |
+ if line[0] != ' ': |
476 |
+ Print.up() |
477 |
+ Print(line.strip().split()[-1]) |
478 |
+ Print.down() |
479 |
+ else: |
480 |
+ Print(line.strip()) |
481 |
+ Print.up() |
482 |
+ logfile.close() |
483 |
+ proc.wait() |
484 |
+ if proc.returncode != 0: |
485 |
+ Print('Test failed') |
486 |
+ else: |
487 |
+ Print('Test successful') |
488 |
+ |
489 |
+ return results |
490 |
+ |
491 |
+ |
492 |
+ def save_results(self, results, figdir): |
493 |
+ if not with_images: |
494 |
+ self.Print("Report generation skipped - missing libraries") |
495 |
+ return |
496 |
+ |
497 |
+ # Re-order the result dictionary |
498 |
+ newresults = {} |
499 |
+ for test in self.tests: |
500 |
+ newresults[test] = {} |
501 |
+ for nameimpl in results: |
502 |
+ nameimplstr = pjoin(*nameimpl) |
503 |
+ resdat = results[nameimpl][test] |
504 |
+ newresults[test][nameimplstr] = resdat |
505 |
+ |
506 |
+ # Begin the HTML report |
507 |
+ htmlfname = pjoin(figdir, 'index.html') |
508 |
+ html = HTMLreport(htmlfname) |
509 |
+ |
510 |
+ # Generate summary - a single image with all plots |
511 |
+ if self.summary or self.summary_only: |
512 |
+ # Save summary figure |
513 |
+ sprows = (len(self.tests)+1)/2 |
514 |
+ plt.figure(figsize=(16,6*sprows), dpi=300) |
515 |
+ for i, test in enumerate(self.tests, 1): |
516 |
+ plt.subplot(sprows, 2, i) |
517 |
+ plt.title(test) |
518 |
+ for impl in newresults[test]: |
519 |
+ x,y = np.loadtxt(newresults[test][impl], unpack=True) |
520 |
+ plt.loglog(x,y, label=impl, hold=True) |
521 |
+ plt.legend(loc='best') |
522 |
+ plt.grid(True) |
523 |
+ fname = pjoin(figdir, 'summary.png') |
524 |
+ plt.savefig(fname, format='png') |
525 |
+ html.addFig("Summary", image=os.path.basename(fname), width='95%') |
526 |
+ self.Print('Summary figure saved: ' + fname) |
527 |
+ |
528 |
+ # Generate plots |
529 |
+ if not self.summary_only: |
530 |
+ for test in self.tests: |
531 |
+ plt.figure(figsize=(12,9), dpi=300) |
532 |
+ for impl in newresults[test]: |
533 |
+ x,y = np.loadtxt(newresults[test][impl], unpack=True) |
534 |
+ plt.loglog(x,y, label=impl, hold=True) |
535 |
+ plt.legend(loc='best') |
536 |
+ plt.grid(True) |
537 |
+ fname = pjoin(figdir, test+".png") |
538 |
+ plt.savefig(fname, format='png') |
539 |
+ html.addFig(test, image=os.path.basename(fname)) |
540 |
+ self.Print('Figure ' + fname + ' saved') |
541 |
+ |
542 |
+ html.close() |
543 |
+ |
544 |
+ |
545 |
|
546 |
diff --git a/app-benchmarks/autobench/files/python/blas.py b/app-benchmarks/autobench/files/python/blasbase.py |
547 |
similarity index 77% |
548 |
copy from app-benchmarks/autobench/files/python/blas.py |
549 |
copy to app-benchmarks/autobench/files/python/blasbase.py |
550 |
index 52bb221..2ca9070 100644 |
551 |
--- a/app-benchmarks/autobench/files/python/blas.py |
552 |
+++ b/app-benchmarks/autobench/files/python/blasbase.py |
553 |
@@ -1,10 +1,10 @@ |
554 |
import os, btlbase |
555 |
import subprocess as sp |
556 |
import shlex |
557 |
+from os.path import join as pjoin |
558 |
|
559 |
-class Module(btlbase.BTLBase): |
560 |
+class BLASBase(btlbase.BTLBase): |
561 |
def _initialize(self): |
562 |
- self.libname = "blas" |
563 |
self.avail1 = ['axpy', 'axpby', 'rot'] |
564 |
self.avail2 = ['matrix_vector','atv','symv','syr2','ger', |
565 |
'trisolve_vector'] |
566 |
@@ -16,13 +16,13 @@ class Module(btlbase.BTLBase): |
567 |
tests = [] |
568 |
for i in args: |
569 |
if i == '1': |
570 |
- tests += avail1 |
571 |
+ tests += self.avail1 |
572 |
continue |
573 |
if i == '2': |
574 |
- tests += avail2 |
575 |
+ tests += self.avail2 |
576 |
continue |
577 |
if i == '3': |
578 |
- tests += avail3 |
579 |
+ tests += self.avail3 |
580 |
continue |
581 |
if i in self.avail: |
582 |
tests.append(i) |
583 |
@@ -39,21 +39,22 @@ class Module(btlbase.BTLBase): |
584 |
|
585 |
@staticmethod |
586 |
def _btl_source(): |
587 |
- return "/libs/BLAS/main.cpp" |
588 |
+ return "libs/BLAS/main.cpp" |
589 |
|
590 |
@staticmethod |
591 |
def _btl_includes(): |
592 |
- return ["/libs/BLAS"] |
593 |
+ return ["libs/BLAS"] |
594 |
|
595 |
def _btl_defines(self): |
596 |
return ["CBLASNAME=" + self.libname, "BLAS_INTERFACE"] |
597 |
|
598 |
def _get_flags(self, root, impl, libdir): |
599 |
# Retrieve pkgconfig settings and map the directories to the new root |
600 |
- path = "%s/etc/env.d/alternatives/%s/%s/%s/pkgconfig" % \ |
601 |
- (root, self.libname, impl, libdir) |
602 |
- pkgconf = sp.Popen('pkg-config --libs --cflags blas', shell=True, \ |
603 |
- stdout=sp.PIPE, env={'PKG_CONFIG_PATH':path}).communicate()[0] |
604 |
+ path = pjoin(root, "etc/env.d/alternatives", \ |
605 |
+ self.libname,impl,libdir, "pkgconfig") |
606 |
+ cmd = ['pkg-config', '--libs', '--cflags', self.libname] |
607 |
+ env = {'PKG_CONFIG_PATH':path} |
608 |
+ pkgconf = sp.Popen(cmd, stdout=sp.PIPE, env=env).communicate()[0] |
609 |
pkgconf = pkgconf.replace('-L/', '-L'+root+'/') |
610 |
pkgconf = pkgconf.replace('-I/', '-I'+root+'/') |
611 |
return shlex.split(pkgconf) |
612 |
|
613 |
diff --git a/app-benchmarks/autobench/files/python/btlbase.py b/app-benchmarks/autobench/files/python/btlbase.py |
614 |
index d71650e..1c6f8aa 100644 |
615 |
--- a/app-benchmarks/autobench/files/python/btlbase.py |
616 |
+++ b/app-benchmarks/autobench/files/python/btlbase.py |
617 |
@@ -46,40 +46,53 @@ def btlcompile(exe, source, btldir, includes, defines, libs, libdirs, other, \ |
618 |
exist. If None, no log is generated. |
619 |
""" |
620 |
|
621 |
+ # Compile flags |
622 |
incs = ( |
623 |
"%s/actions" % btldir, |
624 |
"%s/generic_bench" % btldir, |
625 |
"%s/generic_bench/utils" % btldir, |
626 |
"%s/libs/STL" % btldir |
627 |
) + tuple(includes) |
628 |
- incs = ' '.join(['-I'+i for i in incs]) |
629 |
+ incs = ['-I'+i for i in incs] |
630 |
|
631 |
- defs = ' '.join(['-D'+d for d in ["NDEBUG"] + defines]) |
632 |
+ defs = ['-D'+d for d in ["NDEBUG"] + defines] |
633 |
|
634 |
- libs = ' '.join(['-l'+l for l in ["rt"] + libs]) |
635 |
+ libs = ['-l'+l for l in ["rt"] + libs] |
636 |
|
637 |
- libdirs = ' '.join(['-L'+L for L in libdirs]) |
638 |
+ libdirs = ['-L'+L for L in libdirs] |
639 |
|
640 |
- cxxflags = run_cmd(['portageq', 'envvar', 'CXXFLAGS']).strip() |
641 |
+ cxxflags = shlex.split(run_cmd(['portageq', 'envvar', 'CXXFLAGS']).strip()) |
642 |
|
643 |
- otherflags = ' '.join(other) |
644 |
+ otherfl = other |
645 |
|
646 |
- # TODO: use CXX instead of g++ |
647 |
- cl = "g++ -o %s %s %s %s %s %s %s %s" \ |
648 |
- % (exe, source, incs, defs, libs, libdirs, cxxflags, otherflags) |
649 |
- |
650 |
+ # Retrieve compiler |
651 |
+ cxx = 'g++' |
652 |
+ cxx_portage = run_cmd(['portageq', 'envvar', 'CXX']).strip() |
653 |
+ if cxx_portage != '': |
654 |
+ cxx = cxx_portage |
655 |
+ if os.environ.has_key('CXX'): |
656 |
+ cxx = os.environ['CXX'] |
657 |
+ |
658 |
+ # Compile command |
659 |
+ cl = [cxx, '-o', exe, source]+incs+defs+libs+libdirs+cxxflags+other |
660 |
+ |
661 |
+ # Open logfile or redirect to PIPE |
662 |
if logfile is None: |
663 |
fout = sp.PIPE |
664 |
else: |
665 |
fout = file(logfile, 'w') |
666 |
- fout.write(cl + "\n" + 80*'-' + "\n") |
667 |
+ fout.write(str(cl) + "\n" + 80*'-' + "\n") |
668 |
fout.flush() |
669 |
- cl = shlex.split(cl) |
670 |
+ |
671 |
+ # Execute command |
672 |
cp = sp.Popen(cl, stdout=fout, stderr=sp.STDOUT) |
673 |
- cp.communicate() |
674 |
+ cp.wait() |
675 |
+ |
676 |
+ # Close the log file (if any) |
677 |
if logfile is not None: |
678 |
fout.close() |
679 |
- return (cp.returncode, ' '.join(cl)) |
680 |
+ |
681 |
+ return cp.returncode |
682 |
|
683 |
|
684 |
class BTLBase: |
685 |
@@ -134,19 +147,21 @@ class BTLBase: |
686 |
|
687 |
# Prepare the environment |
688 |
if env.has_key('LIBRARY_PATH'): |
689 |
- env['LIBRARY_PATH'] = root+libdir + ":" + env['LIBRARY_PATH'] |
690 |
+ env['LIBRARY_PATH'] = pjoin(root,libdir) + ":" + env['LIBRARY_PATH'] |
691 |
else: |
692 |
- env['LIBRARY_PATH'] = root+libdir |
693 |
+ env['LIBRARY_PATH'] = pjoin(root, libdir) |
694 |
|
695 |
if env.has_key('INCLUDE_PATH'): |
696 |
- env['INCLUDE_PATH'] = root+"/usr/include" +":"+ env['INCLUDE_PATH'] |
697 |
+ env['INCLUDE_PATH'] = \ |
698 |
+ pjoin(root, "/usr/include") + ":" + env['INCLUDE_PATH'] |
699 |
else: |
700 |
- env['INCLUDE_PATH'] = root+"/usr/include" |
701 |
+ env['INCLUDE_PATH'] = pjoin(root, "/usr/include") |
702 |
|
703 |
if env.has_key('LD_LIBRARY_PATH'): |
704 |
- env['LD_LIBRARY_PATH'] = root+libdir + ":" + env['LD_LIBRARY_PATH'] |
705 |
+ env['LD_LIBRARY_PATH'] = \ |
706 |
+ pjoin(root, libdir) + ":" + env['LD_LIBRARY_PATH'] |
707 |
else: |
708 |
- env['LD_LIBRARY_PATH'] = root+libdir |
709 |
+ env['LD_LIBRARY_PATH'] = pjoin(root, libdir) |
710 |
|
711 |
# Backup the environment |
712 |
oldenv = {} |
713 |
@@ -158,15 +173,14 @@ class BTLBase: |
714 |
for k,v in env.items(): |
715 |
os.environ[k] = v |
716 |
|
717 |
- # Compile |
718 |
- # TODO: use CXX instead of g++ |
719 |
+ # Compile test suite |
720 |
btldir = 'btl/' |
721 |
logfile = os.path.join(logdir, name+"_comp.log") |
722 |
- returncode, compilecl = btlcompile( |
723 |
- exe = testdir + "/test", |
724 |
- source = btldir + self._btl_source(), |
725 |
+ returncode = btlcompile( |
726 |
+ exe = pjoin(testdir, "test"), |
727 |
+ source = pjoin(btldir, self._btl_source()), |
728 |
btldir = btldir, |
729 |
- includes = [btldir+d for d in self._btl_includes()], |
730 |
+ includes = [pjoin(btldir, d) for d in self._btl_includes()], |
731 |
defines = self._btl_defines(), |
732 |
libs = [], |
733 |
libdirs = [root+libdir], |
734 |
@@ -180,29 +194,31 @@ class BTLBase: |
735 |
Print("Compilation successful") |
736 |
|
737 |
# Run test |
738 |
- logfile = file(os.path.join(logdir, name+"_run.log"), 'w') |
739 |
- args = [os.path.join(testdir,"test")] + self.tests |
740 |
+ logfile = file(pjoin(logdir, name+"_run.log"), 'w') |
741 |
+ args = [pjoin(testdir,"test")] + self.tests |
742 |
proc = sp.Popen(args, bufsize=1, stdout=sp.PIPE, stderr=sp.PIPE, |
743 |
cwd = testdir) |
744 |
results = {} |
745 |
while True: |
746 |
+ # Each operation test begins with a line on stderr |
747 |
errline = proc.stderr.readline() |
748 |
- logfile.write(errline) |
749 |
if not errline: |
750 |
break |
751 |
+ logfile.write(errline) |
752 |
resfile = errline.split()[-1] |
753 |
testname = resfile[6:-5-len(name)] |
754 |
results[testname] = pjoin(testdir, resfile) |
755 |
Print(resfile) |
756 |
+ |
757 |
+ # 100 different sizes for each operation test |
758 |
Print.down() |
759 |
for i in xrange(100): |
760 |
outline = proc.stdout.readline() |
761 |
logfile.write(outline) |
762 |
Print(outline.rstrip()) |
763 |
Print.up() |
764 |
- Print.up() |
765 |
- proc.wait() |
766 |
logfile.close() |
767 |
+ proc.wait() |
768 |
if proc.returncode != 0: |
769 |
Print('Test failed') |
770 |
else: |
771 |
@@ -226,7 +242,7 @@ class BTLBase: |
772 |
for test in self.tests: |
773 |
newresults[test] = {} |
774 |
for nameimpl in results: |
775 |
- nameimplstr = "%s/%s" % nameimpl |
776 |
+ nameimplstr = pjoin(*nameimpl) |
777 |
resdat = results[nameimpl][test] |
778 |
newresults[test][nameimplstr] = resdat |
779 |
|
780 |
|
781 |
diff --git a/app-benchmarks/autobench/files/python/cblas.py b/app-benchmarks/autobench/files/python/cblas.py |
782 |
index c3d0342..c78867c 100644 |
783 |
--- a/app-benchmarks/autobench/files/python/cblas.py |
784 |
+++ b/app-benchmarks/autobench/files/python/cblas.py |
785 |
@@ -1,69 +1,6 @@ |
786 |
-import os, btlbase |
787 |
-import subprocess as sp |
788 |
-import shlex |
789 |
+import blasbase |
790 |
|
791 |
-class Module(btlbase.BTLBase): |
792 |
+class Module(blasbase.BLASBase): |
793 |
def _initialize(self): |
794 |
self.libname = "cblas" |
795 |
- self.avail1 = ['axpy', 'axpby', 'rot'] |
796 |
- self.avail2 = ['matrix_vector','atv','symv','syr2','ger', |
797 |
- 'trisolve_vector'] |
798 |
- self.avail3 = ['matrix_matrix', 'aat', 'trisolve_matrix', 'trmm'] |
799 |
- self.avail = self.avail1 + self.avail2 + self.avail3 |
800 |
- |
801 |
- def _parse_args(self, args): |
802 |
- # Parse arguments |
803 |
- tests = [] |
804 |
- for i in args: |
805 |
- if i == '1': |
806 |
- tests += avail1 |
807 |
- continue |
808 |
- if i == '2': |
809 |
- tests += avail2 |
810 |
- continue |
811 |
- if i == '3': |
812 |
- tests += avail3 |
813 |
- continue |
814 |
- if i in self.avail: |
815 |
- tests.append(i) |
816 |
- continue |
817 |
- raise Exception("Argument not recognized: " + i) |
818 |
- |
819 |
- # Sort tests |
820 |
- self.tests = [i for i in self.avail if i in tests] |
821 |
- |
822 |
- # If no test is specified, then choose four standard tests |
823 |
- if len(self.tests) == 0: |
824 |
- self.tests = ['axpy', 'matrix_vector', \ |
825 |
- 'trisolve_vector', 'matrix_matrix'] |
826 |
- |
827 |
- @staticmethod |
828 |
- def _btl_source(): |
829 |
- return "/libs/BLAS/main.cpp" |
830 |
- |
831 |
- @staticmethod |
832 |
- def _btl_includes(): |
833 |
- return ["/libs/BLAS"] |
834 |
- |
835 |
- def _btl_defines(self): |
836 |
- return ["CBLASNAME=" + self.libname, "CBLAS_INTERFACE"] |
837 |
- |
838 |
- def _get_flags(self, root, impl, libdir): |
839 |
- # Retrieve pkgconfig settings and map the directories to the new root |
840 |
- path = "%s/etc/env.d/alternatives/%s/%s/%s/pkgconfig" % \ |
841 |
- (root, self.libname, impl, libdir) |
842 |
- pkgconf = sp.Popen('pkg-config --libs --cflags cblas', shell=True, \ |
843 |
- stdout=sp.PIPE, env={'PKG_CONFIG_PATH':path}).communicate()[0] |
844 |
- pkgconf = pkgconf.replace('-L/', '-L'+root+'/') |
845 |
- pkgconf = pkgconf.replace('-I/', '-I'+root+'/') |
846 |
- return shlex.split(pkgconf) |
847 |
- |
848 |
- |
849 |
- def get_impls(self, root): |
850 |
- output = sp.Popen( |
851 |
- ['eselect', '--no-color', '--brief', self.libname, 'list'], |
852 |
- env={'ROOT' : root}, stdout=sp.PIPE |
853 |
- ).communicate()[0] |
854 |
- return output.strip().split('\n') |
855 |
- |
856 |
-del btlbase |
857 |
+ blasbase.BLASBase._initialize(self) |
858 |
\ No newline at end of file |
859 |
|
860 |
diff --git a/app-benchmarks/autobench/files/python/main.py b/app-benchmarks/autobench/files/python/main.py |
861 |
index 991d735..3a02791 100644 |
862 |
--- a/app-benchmarks/autobench/files/python/main.py |
863 |
+++ b/app-benchmarks/autobench/files/python/main.py |
864 |
@@ -7,6 +7,7 @@ import subprocess as sp |
865 |
import time |
866 |
|
867 |
# Retrieve relevant files/directories |
868 |
+# TODO: use external config module to share these variables (or use environ?) |
869 |
curdir = os.path.abspath('.') |
870 |
scriptdir = os.path.dirname(os.path.realpath(__file__)) |
871 |
rootsdir = "/var/tmp/benchmarks/roots/" |
872 |
@@ -236,6 +237,12 @@ for tn,(name,test) in enumerate(tests.items(),1): |
873 |
|
874 |
|
875 |
# Reports will be saved in figdir |
876 |
+ |
877 |
+# Results are reordered: |
878 |
+# results |
879 |
+# |-(name1, impl1) -> resultobject11 |
880 |
+# |-(name1, impl2) -> resultobject12 |
881 |
+# |-(name2, impl1) -> resultobject21 |
882 |
os.path.exists(figdir) or os.makedirs(figdir) |
883 |
results = {} |
884 |
for (name,test) in tests.items(): |
885 |
@@ -244,4 +251,3 @@ for (name,test) in tests.items(): |
886 |
results[(name, impl)] = test['results'][impl] |
887 |
|
888 |
mod.save_results(results, figdir) |
889 |
- |