1import os, string, logging, re, random, shutil 2from autotest_lib.client.bin import test, os_dep, utils 3from autotest_lib.client.common_lib import error 4 5 6def find_mnt_pt(path): 7 """ 8 Find on which mount point a given path is mounted. 9 10 @param path: Path we want to figure its mount point. 11 """ 12 pth = os.path.abspath(path) 13 while not os.path.ismount(pth): 14 pth = os.path.dirname(pth) 15 return pth 16 17 18class ffsb(test.test): 19 """ 20 This class wraps FFSB (Flexible File System Benchmark) execution 21 under autotest. 22 23 @author Onkar N Mahajan (onkar.n.mahajan@linux.vnet.ibm.com) 24 """ 25 version = 1 26 params = {} 27 tempdirs = [] 28 bytes = {'K':1024 , 'k':1024, 29 'M':1048576, 'm':1048576, 30 'G':1073741824, 'g':1073741824, 31 'T':1099511627776 , 't':1099511627776} 32 33 34 def initialize(self): 35 self.job.require_gcc() 36 self.results = [] 37 self.nfail = 0 38 39 40 def set_ffsb_params(self, usrfl): 41 """ 42 This function checks for the user supplied FFSB profile file 43 and validates it against the availble resources on the 44 guest - currently only disk space validation is supported 45 but adjusting the number of threads according to the vcpus 46 exported by the qemu-kvm also needs to be added. 47 48 @param usrfl: Path to the user profile file. 49 """ 50 d = {} 51 fr = open(usrfl,'r') 52 for line in fr.read().split('\n'): 53 p = re.compile(r'\s*\t*\[{1}filesystem(\d+)\]{1}') 54 m = p.match(line) 55 if m: 56 fsno = int(line[m.start(1):m.end(1)]) 57 d[fsno] = [] 58 p = re.compile(r'(\s*\t*location)\=(.*)') 59 m = p.match(line) 60 if m: 61 path = line[m.start(2):m.end(2)] 62 mntpt = find_mnt_pt(path) 63 f = os.statvfs(mntpt) 64 avl_dsk_spc = f.f_bfree * f.f_bsize 65 avl_dsk_spc *= 0.95 66 d[fsno].append(mntpt) 67 d[fsno].append(int(avl_dsk_spc)) 68 p = re.compile(r'(\s*\t*num_files)\=(\d+)') 69 70 m = p.match(line) 71 if m: 72 usrnumfl = int(line[m.start(2):m.end(2)]) 73 d[fsno].append(usrnumfl) 74 p = re.compile(r'(\s*\t*max_filesize)\=(\d+[kKMmGgTt]?)') 75 m = p.match(line) 76 if m: 77 usrmaxflsz = line[m.start(2):m.end(2)] 78 usrmaxflsz = int(usrmaxflsz[0:-1]) * self.bytes[usrmaxflsz[-1]] 79 d[fsno].append(usrmaxflsz) 80 for k in d.keys(): 81 while d[k][2]*d[k][3] >= d[k][1]: 82 d[k][2] -= 1 83 if d[k][2] == 0: 84 d[k][2] = 1 85 d[k][3] = d[k][1] 86 # If the ffsb mount point is on the same file system 87 # then use the available disk space after the previous 88 # tests 89 for k1 in d.keys(): 90 if d[k1][0] == d[k][0]: 91 d[k1][1] -= (d[k][2]*d[k][3]) 92 fr.close() 93 return d 94 95 96 def dup_ffsb_profilefl(self): 97 """ 98 Validates the path from the FFSB configuration file, the 99 disk space available for the test, warn the user and 100 change the file sizes and/or number of files to be used for 101 generating the workload according to the available disk space 102 on the guest. 103 """ 104 self.usrfl = '%s/%s' % (os.path.split(self.srcdir)[0],'profile.cfg') 105 self.sysfl = '%s/%s' % (self.srcdir,'profile.cfg') 106 107 params = self.set_ffsb_params(self.usrfl) 108 109 fsno = 0 110 fr = open(self.usrfl,'r') 111 fw = open(self.sysfl,'w') 112 for line in fr.read().split('\n'): 113 p = re.compile(r'\s*\t*\[{1}filesystem(\d+)\]{1}') 114 m = p.match(line) 115 if m: 116 fsno = int(line[m.start(1):m.end(1)]) 117 p = re.compile(r'(\s*\t*location)\=(.*)') 118 m = p.match(line) 119 if m: 120 while True: 121 dirnm = ''.join(random.choice(string.letters) for i in xrange(9)) 122 if line[m.end(2) - 1] == '/': 123 newline = '%s%s' % (line[0:m.end(2)], dirnm) 124 ffsbdir = '%s%s' % (line[m.start(2):m.end(2)], dirnm) 125 else: 126 newline = '%s/%s' % (line[0:m.end(2)], dirnm) 127 ffsbdir = '%s/%s' % (line[m.start(2):m.end(2)], dirnm) 128 self.tempdirs.append(ffsbdir) 129 if os.path.exists(ffsbdir): 130 continue 131 else: 132 os.makedirs(ffsbdir) 133 break 134 fw.write(newline+'\n') 135 continue 136 p = re.compile(r'(\s*\t*num_files)\=(.*)') 137 m = p.match(line) 138 if m: 139 newline = '%s=%s' % (line[0:m.end(1)], str(params[fsno][2])) 140 fw.write(newline+'\n') 141 continue 142 p = re.compile(r'(\s*\t*max_filesize)\=(\d+[kKMmGgTt]?)') 143 m = p.match(line) 144 if m: 145 newline = '%s%s' % (line[0:m.start(2)], str(params[fsno][3])) 146 fw.write(newline+'\n') 147 continue 148 fw.write(line+'\n') 149 fr.close() 150 fw.close() 151 152 153 def setup(self, tarball='ffsb-6.0-rc2.tar.bz2'): 154 """ 155 Uncompress the FFSB tarball and compiles it. 156 157 @param tarball: FFSB tarball. Could be either a path relative to 158 self.srcdir or a URL. 159 """ 160 tarball = utils.unmap_url(self.bindir, tarball, self.tmpdir) 161 utils.extract_tarball_to_dir(tarball, self.srcdir) 162 os.chdir(self.srcdir) 163 os_dep.command('gcc') 164 utils.configure() 165 utils.make() 166 167 168 def run_once(self): 169 """ 170 Runs a single iteration of the FFSB. 171 """ 172 self.dup_ffsb_profilefl() 173 # Run FFSB using abspath 174 cmd = '%s/ffsb %s/profile.cfg' % (self.srcdir, self.srcdir) 175 logging.info("FFSB command: %s", cmd) 176 self.results_path = os.path.join(self.resultsdir, 177 'raw_output_%s' % self.iteration) 178 try: 179 self.results = utils.system_output(cmd, retain_output=True) 180 logging.info(self.results) 181 utils.open_write_close(self.results_path, self.results) 182 except error.CmdError, e: 183 self.nfail += 1 184 logging.error('Failed to execute FFSB : %s', e) 185 186 187 def postprocess(self): 188 """ 189 Do test postprocessing. Fail the test or clean up results. 190 """ 191 if self.nfail != 0: 192 raise error.TestError('FFSB test failed.') 193 else: 194 logging.info('FFSB test passed') 195 logging.info('Cleaning up test data...') 196 for l in self.tempdirs: 197 shutil.rmtree(l) 198