#!/usr/bin/python -u
"""
fs-bench.py
============

configuration:
	- specify 2 directories WORK_DIRS
	- copy linux-2.6.5.tar.bz2 to *all* WORK_DIRS
	- to get more valid, run this program in Single User Mode

sebas [at] vizZzion [dot] org

"""
from time import time as now
from os import system, path
from sys import exit, argv

# run tests in these directories 
# the first directory will be used as reference
# must be writable
WORK_DIRS = ['/fs-bench']

# must be writable
LOGFILE = '/tmp/fs-bench.log'

# may be True / False
DEBUG = False

if len(argv) > 1:
	if argv[1] == '--help':
		print "fs-bench.py - a small filesystem benchmark program"
		print "please edit fs-bench.py to set up things."
		exit(0)

class someTest : 
	""" a single test, which is run on all WORK_DIRS """
	
	def __init__ (self, command, working_dirs):
		global LOGFILE
		# wrap the command, in order to catch output and set the path """
		self.command = command
		self.cmd = 'PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin ; %s > %s 2>&1' % (command, LOGFILE)
		# set used vars
		self.working_dirs = working_dirs
		self.result = {}
	
	def run (self):
		global DEBUG
		# run command on all dire
		for dir in self.working_dirs:
			print "running %s in %s" % (self.command, dir),
			system ('cd %s' % dir)
			t1 = now ()
			# cd to working dir, run test
			if not system ('cd %s && %s' % (dir, self.cmd)):
				if DEBUG: print '  [WW] command returned error, results may be invalid!'
			self.result[dir] = now () - t1
			print ' ... took %s ' % round(self.result[dir], 2)

class TestSuite:
	""" the whole testsuite, containing different tests, as specified in run_all() and 
		some methods to display the results """
		
	def __init__ (self):
		global WORK_DIRS
		self.WORK_DIRS = WORK_DIRS
		# container for the tests
		self.tests = []
		# storage for results
		self.total = {}
		if not self.check_work_dirs(): exit(1)
		self.define_tests()
		
	def add(self, cmd):
		self.tests.append(someTest(cmd, self.WORK_DIRS))
		
	def check_work_dirs (self):
		for dir in self.WORK_DIRS: 
			# check if directory exists
			if not path.isdir(dir): 
				print "[EE] %s is not an existing path" % dir
				return False
			# check if directory is writable
			try:
				f = open("%s%stestfile.txt" % (dir, path.sep), "w")
			except IOError:
				print "[EE] %s must be writable" % dir
				return False   
		return True
		
	def define_tests(self):
		""" all commands to be run are appended here, and also run as someTest runs	"""
		
		# unpack some data, bzip is pretty CPU intensive, so this might not be a major bench for the FS
		self.add('tar xjf linux-2.6.5.tar.bz2')
		
		# tar *without* compression should be of more value
		self.add('tar cf test.tar linux-2.6.5/')
		
		# let's see how fast grep is
		self.add('grep -r fuck linux-2.6.5/')
		
		# copy also should show FS performance very good
		self.add('cp -R linux-2.6.5/ test/')
		
		# find is used on a regular basis
		self.add('find linux-2.6.5/ foobar')
		
		# rm might be useful
		self.add('rm -rf linux-2.6.5/ test/ test.tar testfile.txt')
		
		# bonnie ... 
		self.add('bonnie++ -s 1g -n 5 -x 1 -u 0')
		
		# slow.c ... 
		self.add('/stuff/slow')
	
	def start(self):
		""" start testsuite : run all tests """
		for test in self.tests: test.run()
		
	
	def show_results_single(self):
		""" display benchmark statistics """
		
		# initalize and reset all totals
		for d in self.WORK_DIRS: self.total[d] = 0
		
		for a in self.tests:
			print '---------> %s ' % a.command
			ref_result = a.result[WORK_DIRS[0]]
			for dir in WORK_DIRS:
				sec = '%ssec' % round(a.result[dir], 2)
				if not ref_result == 0: 
					perc = '%sperc' % round((a.result[dir] / ref_result * 100), 2)
				else:
					perc = '??perc'
				print '%s 	%s 	%s' % (sec, perc, dir)
				# first is reference, 100%
				self.total[dir] += a.result[dir]

	def show_results_total(self):					
		ref_total = self.total[WORK_DIRS[0]]
		total_time = 0
		
		print "=========> test totals:"		
		for dir in self.WORK_DIRS:
			sec = '%s sec' % round(self.total[dir], 2)
			if not ref_total == 0: 
				perc = '%s perc' % round((self.total[dir] / ref_total * 100), 2)
			else:	perc = '??%'
			#print 'perc %s' % perc
			print "%s 	%s 	%s " % (sec, perc, dir)
			#print round(ref_total, 2)
			total_time += self.total[dir]
		print "total time of benchmark: %s " % round(total_time)
	
	def show_results(self):
		self.show_results_single()
		self.show_results_total()
	
		
if __name__ == "__main__":
	""" mainloop """
	ts = TestSuite()
	ts.start()
	ts.show_results()
	system('beep')


