| import os, string, logging, re, random, shutil |
| from autotest_lib.client.bin import test, os_dep, utils |
| from autotest_lib.client.common_lib import error |
| |
| |
| def find_mnt_pt(path): |
| """ |
| Find on which mount point a given path is mounted. |
| |
| @param path: Path we want to figure its mount point. |
| """ |
| pth = os.path.abspath(path) |
| while not os.path.ismount(pth): |
| pth = os.path.dirname(pth) |
| return pth |
| |
| |
| class ffsb(test.test): |
| """ |
| This class wraps FFSB (Flexible File System Benchmark) execution |
| under autotest. |
| |
| @author Onkar N Mahajan ([email protected]) |
| """ |
| version = 1 |
| params = {} |
| tempdirs = [] |
| bytes = {'K':1024 , 'k':1024, |
| 'M':1048576, 'm':1048576, |
| 'G':1073741824, 'g':1073741824, |
| 'T':1099511627776 , 't':1099511627776} |
| |
| |
| def initialize(self): |
| self.job.require_gcc() |
| self.results = [] |
| self.nfail = 0 |
| |
| |
| def set_ffsb_params(self, usrfl): |
| """ |
| This function checks for the user supplied FFSB profile file |
| and validates it against the availble resources on the |
| guest - currently only disk space validation is supported |
| but adjusting the number of threads according to the vcpus |
| exported by the qemu-kvm also needs to be added. |
| |
| @param usrfl: Path to the user profile file. |
| """ |
| d = {} |
| fr = open(usrfl,'r') |
| for line in fr.read().split('\n'): |
| p = re.compile(r'\s*\t*\[{1}filesystem(\d+)\]{1}') |
| m = p.match(line) |
| if m: |
| fsno = int(line[m.start(1):m.end(1)]) |
| d[fsno] = [] |
| p = re.compile(r'(\s*\t*location)\=(.*)') |
| m = p.match(line) |
| if m: |
| path = line[m.start(2):m.end(2)] |
| mntpt = find_mnt_pt(path) |
| f = os.statvfs(mntpt) |
| avl_dsk_spc = f.f_bfree * f.f_bsize |
| avl_dsk_spc *= 0.95 |
| d[fsno].append(mntpt) |
| d[fsno].append(int(avl_dsk_spc)) |
| p = re.compile(r'(\s*\t*num_files)\=(\d+)') |
| |
| m = p.match(line) |
| if m: |
| usrnumfl = int(line[m.start(2):m.end(2)]) |
| d[fsno].append(usrnumfl) |
| p = re.compile(r'(\s*\t*max_filesize)\=(\d+[kKMmGgTt]?)') |
| m = p.match(line) |
| if m: |
| usrmaxflsz = line[m.start(2):m.end(2)] |
| usrmaxflsz = int(usrmaxflsz[0:-1]) * self.bytes[usrmaxflsz[-1]] |
| d[fsno].append(usrmaxflsz) |
| for k in d.keys(): |
| while d[k][2]*d[k][3] >= d[k][1]: |
| d[k][2] -= 1 |
| if d[k][2] == 0: |
| d[k][2] = 1 |
| d[k][3] = d[k][1] |
| # If the ffsb mount point is on the same file system |
| # then use the available disk space after the previous |
| # tests |
| for k1 in d.keys(): |
| if d[k1][0] == d[k][0]: |
| d[k1][1] -= (d[k][2]*d[k][3]) |
| fr.close() |
| return d |
| |
| |
| def dup_ffsb_profilefl(self): |
| """ |
| Validates the path from the FFSB configuration file, the |
| disk space available for the test, warn the user and |
| change the file sizes and/or number of files to be used for |
| generating the workload according to the available disk space |
| on the guest. |
| """ |
| self.usrfl = '%s/%s' % (os.path.split(self.srcdir)[0],'profile.cfg') |
| self.sysfl = '%s/%s' % (self.srcdir,'profile.cfg') |
| |
| params = self.set_ffsb_params(self.usrfl) |
| |
| fsno = 0 |
| fr = open(self.usrfl,'r') |
| fw = open(self.sysfl,'w') |
| for line in fr.read().split('\n'): |
| p = re.compile(r'\s*\t*\[{1}filesystem(\d+)\]{1}') |
| m = p.match(line) |
| if m: |
| fsno = int(line[m.start(1):m.end(1)]) |
| p = re.compile(r'(\s*\t*location)\=(.*)') |
| m = p.match(line) |
| if m: |
| while True: |
| dirnm = ''.join(random.choice(string.letters) for i in xrange(9)) |
| if line[m.end(2) - 1] == '/': |
| newline = '%s%s' % (line[0:m.end(2)], dirnm) |
| ffsbdir = '%s%s' % (line[m.start(2):m.end(2)], dirnm) |
| else: |
| newline = '%s/%s' % (line[0:m.end(2)], dirnm) |
| ffsbdir = '%s/%s' % (line[m.start(2):m.end(2)], dirnm) |
| self.tempdirs.append(ffsbdir) |
| if os.path.exists(ffsbdir): |
| continue |
| else: |
| os.makedirs(ffsbdir) |
| break |
| fw.write(newline+'\n') |
| continue |
| p = re.compile(r'(\s*\t*num_files)\=(.*)') |
| m = p.match(line) |
| if m: |
| newline = '%s=%s' % (line[0:m.end(1)], str(params[fsno][2])) |
| fw.write(newline+'\n') |
| continue |
| p = re.compile(r'(\s*\t*max_filesize)\=(\d+[kKMmGgTt]?)') |
| m = p.match(line) |
| if m: |
| newline = '%s%s' % (line[0:m.start(2)], str(params[fsno][3])) |
| fw.write(newline+'\n') |
| continue |
| fw.write(line+'\n') |
| fr.close() |
| fw.close() |
| |
| |
| def setup(self, tarball='ffsb-6.0-rc2.tar.bz2'): |
| """ |
| Uncompress the FFSB tarball and compiles it. |
| |
| @param tarball: FFSB tarball. Could be either a path relative to |
| self.srcdir or a URL. |
| """ |
| tarball = utils.unmap_url(self.bindir, tarball, self.tmpdir) |
| utils.extract_tarball_to_dir(tarball, self.srcdir) |
| os.chdir(self.srcdir) |
| os_dep.command('gcc') |
| utils.configure() |
| utils.make() |
| |
| |
| def run_once(self): |
| """ |
| Runs a single iteration of the FFSB. |
| """ |
| self.dup_ffsb_profilefl() |
| # Run FFSB using abspath |
| cmd = '%s/ffsb %s/profile.cfg' % (self.srcdir, self.srcdir) |
| logging.info("FFSB command: %s", cmd) |
| self.results_path = os.path.join(self.resultsdir, |
| 'raw_output_%s' % self.iteration) |
| try: |
| self.results = utils.system_output(cmd, retain_output=True) |
| logging.info(self.results) |
| utils.open_write_close(self.results_path, self.results) |
| except error.CmdError, e: |
| self.nfail += 1 |
| logging.error('Failed to execute FFSB : %s', e) |
| |
| |
| def postprocess(self): |
| """ |
| Do test postprocessing. Fail the test or clean up results. |
| """ |
| if self.nfail != 0: |
| raise error.TestError('FFSB test failed.') |
| else: |
| logging.info('FFSB test passed') |
| logging.info('Cleaning up test data...') |
| for l in self.tempdirs: |
| shutil.rmtree(l) |