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)