import time, os
from autotest_lib.client.bin import test, os_dep, utils
from autotest_lib.client.common_lib import error


class btreplay(test.test):
    version = 1

    # http://brick.kernel.dk/snaps/blktrace-git-latest.tar.gz
    def setup(self, tarball = 'blktrace-git-latest.tar.gz'):
        tarball = utils.unmap_url(self.bindir, tarball, self.tmpdir)
        utils.extract_tarball_to_dir(tarball, self.srcdir)

        self.job.setup_dep(['libaio'])
        libs = '-L' + self.autodir + '/deps/libaio/lib -laio'
        cflags = '-I ' + self.autodir + '/deps/libaio/include'
        var_libs = 'LIBS="' + libs + '"'
        var_cflags  = 'CFLAGS="' + cflags + '"'
        self.make_flags = var_libs + ' ' + var_cflags

        os.chdir(self.srcdir)

        utils.system('patch -p1 < ../Makefile.patch')
        utils.system(self.make_flags + ' make')


    def initialize(self):
        self.job.require_gcc()
        self.ldlib = 'LD_LIBRARY_PATH=%s/deps/libaio/lib'%(self.autodir)
        self.results = []


    def run_once(self, dev="", devices="", extra_args='', tmpdir=None):
        # @dev: The device against which the trace will be replayed.
        #       e.g. "sdb" or "md_d1"
        # @devices: A space-separated list of the underlying devices
        #    which make up dev, e.g. "sdb sdc". You only need to set
        #    devices if dev is an MD, LVM, or similar device;
        #    otherwise leave it as an empty string.

        if not tmpdir:
            tmpdir = self.tmpdir

        os.chdir(self.srcdir)

        alldevs = "-d /dev/" + dev
        alldnames = dev
        for d in devices.split():
            alldevs += " -d /dev/" + d
            alldnames += " " + d

        # convert the trace (assumed to be in this test's base
        # directory) into btreplay's required format
        #
        # TODO: The test currently halts here as there is no trace in the
        # test's base directory.
        cmd = "./btreplay/btrecord -d .. -D %s %s" % (tmpdir, dev)
        self.results.append(utils.system_output(cmd, retain_output=True))

        # time a replay that omits "thinktime" between requests
        # (by use of the -N flag)
        cmd = self.ldlib + " /usr/bin/time ./btreplay/btreplay -d "+\
              tmpdir+" -N -W "+dev+" "+extra_args+" 2>&1"
        self.results.append(utils.system_output(cmd, retain_output=True))

        # trace a replay that reproduces inter-request delays, and
        # analyse the trace with btt to determine the average request
        # completion latency
        utils.system("./blktrace -D %s %s >/dev/null &" % (tmpdir, alldevs))
        cmd = self.ldlib + " ./btreplay/btreplay -d %s -W %s %s" %\
              (tmpdir, dev, extra_args)
        self.results.append(utils.system_output(cmd, retain_output=True))
        utils.system("killall -INT blktrace")

        # wait until blktrace is really done
        slept = 0.0
        while utils.system("ps -C blktrace > /dev/null",
                           ignore_status=True) == 0:
            time.sleep(0.1)
            slept += 0.1
            if slept > 30.0:
                utils.system("killall -9 blktrace")
                raise error.TestError("blktrace failed to exit in 30 seconds")
        utils.system("./blkparse -q -D %s -d %s/trace.bin -O %s >/dev/null" %
                     (tmpdir, tmpdir, alldnames))
        cmd = "./btt/btt -i %s/trace.bin" % tmpdir
        self.results.append(utils.system_output(cmd, retain_output=True))


    def postprocess(self):
        for n in range(len(self.results)):
            if self.results[n].strip() == "==================== All Devices ====================":
                words = self.results[n-2].split()
                s = words[1].strip('sytem').split(':')
                e = words[2].strip('elapsd').split(':')
                break

        systime = 0.0
        for n in range(len(s)):
            i = (len(s)-1) - n
            systime += float(s[i]) * (60**n)
        elapsed = 0.0
        for n in range(len(e)):
            i = (len(e)-1) - n
            elapsed += float(e[i]) * (60**n)

        q2c = 0.0
        for line in self.results:
            words = line.split()
            if len(words) < 3:
                continue
            if words[0] == 'Q2C':
                q2c = float(words[2])
                break

        self.write_perf_keyval({'time':elapsed, 'systime':systime,
                                'avg_q2c_latency':q2c})