lmr | b6208c5 | 2009-10-07 12:43:24 +0000 | [diff] [blame^] | 1 | import os, shutil, logging, re |
| 2 | from autotest_lib.client.bin import test, utils |
| 3 | from autotest_lib.client.common_lib import error |
| 4 | |
| 5 | class npb(test.test): |
| 6 | """ |
| 7 | This module runs the NAS Parallel Benchmarks on the client machine |
| 8 | |
| 9 | @note: Since we use gfortran to complie these benchmarks, this test might |
| 10 | not be able to run on older Operating Systems. |
| 11 | @see: http://www.nas.nasa.gov/Resources/Software/npb.html |
| 12 | """ |
| 13 | version = 1 |
| 14 | def initialize(self, tests=''): |
| 15 | # Initialize failure counter |
| 16 | self.n_fail = 0 |
| 17 | # Get the parameters for run_once() |
| 18 | self.tests = tests |
| 19 | # Ratio is the reason between 1 and the number of CPUs of the system. |
| 20 | self.ratio = 1.0 / utils.count_cpus() |
| 21 | logging.debug('Ratio (1/n_cpus) found for this system: %s' % self.ratio) |
| 22 | |
| 23 | |
| 24 | def setup(self, tarball='NPB3.3.tar.gz'): |
| 25 | tarball = utils.unmap_url(self.bindir, tarball, self.tmpdir) |
| 26 | utils.extract_tarball_to_dir(tarball, self.srcdir) |
| 27 | os.chdir(self.srcdir) |
| 28 | # Prepare the makefile and benchmarks to generate. |
| 29 | utils.system('patch -p1 < ../enable-all-tests.patch') |
| 30 | utils.system('cd NPB3.3-OMP && make suite') |
| 31 | |
| 32 | |
| 33 | def run_once(self): |
| 34 | """ |
| 35 | Run each benchmark twice, with different number of threads. |
| 36 | |
| 37 | A sanity check is made on each benchmark executed: |
| 38 | The ratio between the times |
| 39 | time_ratio = time_one_thrd / time_full_thrds |
| 40 | |
| 41 | Has to be contained inside an envelope: |
| 42 | upper_bound = full_thrds * (1 + (1/n_cpus)) |
| 43 | lower_bound = full_thrds * (1 - (1/n_cpus)) |
| 44 | |
| 45 | Otherwise, we throw an exception (this test might be running under a |
| 46 | virtual machine and sanity check failure might mean bugs on smp |
| 47 | implementation). |
| 48 | """ |
| 49 | os.chdir(self.srcdir) |
| 50 | |
| 51 | # get the tests to run |
| 52 | test_list = self.tests.split() |
| 53 | |
| 54 | if len(test_list) == 0: |
| 55 | raise error.TestError('No tests (benchmarks) provided. Exit.') |
| 56 | |
| 57 | for itest in test_list: |
| 58 | itest_cmd = os.path.join('NPB3.3-OMP/bin/', itest) |
| 59 | try: |
| 60 | itest = utils.run(itest_cmd) |
| 61 | except: |
| 62 | logging.error('NPB benchmark %s has failed. Output: %s', |
| 63 | itest_cmd, itest.stdout) |
| 64 | self.n_fail += 1 |
| 65 | logging.debug(itest.stdout) |
| 66 | |
| 67 | # Get the number of threads that the test ran |
| 68 | # (which is supposed to be equal to the number of system cores) |
| 69 | m = re.search('Total threads\s*=\s*(.*)\n', itest.stdout) |
| 70 | |
| 71 | # Gather benchmark results |
| 72 | ts = re.search('Time in seconds\s*=\s*(.*)\n', itest.stdout) |
| 73 | mt = re.search('Mop/s total\s*=\s*(.*)\n', itest.stdout) |
| 74 | mp = re.search('Mop/s/thread\s*=\s*(.*)\n', itest.stdout) |
| 75 | |
| 76 | time_seconds = float(ts.groups()[0]) |
| 77 | mops_total = float(mt.groups()[0]) |
| 78 | mops_per_thread = float(mp.groups()[0]) |
| 79 | |
| 80 | logging.info('Test: %s', itest_cmd) |
| 81 | logging.info('Time (s): %s', time_seconds) |
| 82 | logging.info('Total operations executed (mops/s): %s', mops_total) |
| 83 | logging.info('Total operations per thread (mops/s/thread): %s', |
| 84 | mops_per_thread) |
| 85 | |
| 86 | self.write_test_keyval({'test': itest_cmd}) |
| 87 | self.write_test_keyval({'time_seconds': time_seconds}) |
| 88 | self.write_test_keyval({'mops_total': mops_total}) |
| 89 | self.write_test_keyval({'mops_per_thread': mops_per_thread}) |
| 90 | |
| 91 | # A little extra sanity check comes handy |
| 92 | if int(m.groups()[0]) != utils.count_cpus(): |
| 93 | raise error.TestError("NPB test suite evaluated the number " |
| 94 | "of threads incorrectly: System appears " |
| 95 | "to have %s cores, but %s threads were " |
| 96 | "executed.") |
| 97 | |
| 98 | # We will use this integer with float point vars later. |
| 99 | full_thrds = float(m.groups()[0]) |
| 100 | |
| 101 | # get duration for full_threads running. |
| 102 | m = re.search('Time in seconds\s*=\s*(.*)\n', itest.stdout) |
| 103 | time_full_thrds = float(m.groups()[0]) |
| 104 | |
| 105 | # repeat the execution with single thread. |
| 106 | itest_single_cmd = ''.join(['OMP_NUM_THREADS=1 ', itest_cmd]) |
| 107 | try: |
| 108 | itest_single = utils.run(itest_single_cmd) |
| 109 | except: |
| 110 | logging.error('NPB benchmark single thread %s has failed. ' |
| 111 | 'Output: %s', |
| 112 | itest_single_cmd, |
| 113 | itest_single.stdout) |
| 114 | self.n_fail += 1 |
| 115 | |
| 116 | m = re.search('Time in seconds\s*=\s*(.*)\n', itest_single.stdout) |
| 117 | time_one_thrd = float(m.groups()[0]) |
| 118 | |
| 119 | # check durations |
| 120 | ratio = self.ratio |
| 121 | time_ratio = float(time_one_thrd / time_full_thrds) |
| 122 | upper_bound = full_thrds * (1 + ratio) |
| 123 | lower_bound = full_thrds * (1 - ratio) |
| 124 | logging.debug('Time ratio for %s: %s', itest_cmd, time_ratio) |
| 125 | logging.debug('Upper bound: %s', upper_bound) |
| 126 | logging.debug('Lower bound: %s', lower_bound) |
| 127 | |
| 128 | violates_upper_bound = time_ratio > upper_bound |
| 129 | violates_lower_bound = time_ratio < lower_bound |
| 130 | if violates_upper_bound or violates_lower_bound: |
| 131 | logging.error('NPB benchmark %s failed sanity check ' |
| 132 | '- time ratio outside bounds' % itest_cmd) |
| 133 | self.n_fail += 1 |
| 134 | else: |
| 135 | logging.debug('NPB benchmark %s sanity check PASS' % itest_cmd) |
| 136 | |
| 137 | |
| 138 | def cleanup(self): |
| 139 | """ |
| 140 | Raise TestError if failures were detected during test execution. |
| 141 | """ |
| 142 | if self.n_fail != 0: |
| 143 | raise error.TestError('NPB test failed.') |
| 144 | else: |
| 145 | logging.info('NPB test passed.') |