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 (onkar.n.mahajan@linux.vnet.ibm.com) """ 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)