"""
perf is a tool included in the linux kernel tree that
supports functionality similar to oprofile and more.

@see: http://lwn.net/Articles/310260/
"""

import logging
import os
import signal
import stat
import subprocess

from autotest.client import profiler, os_dep, utils


class perf(profiler.profiler):
    version = 1

    def initialize(self, events=["cycles", "instructions"], trace=False, **dargs):
        if type(events) == str:
            self.events = [events]
        else:
            self.events = events
        self.trace = trace
        self.perf_bin = os_dep.command('perf')
        perf_help = utils.run('%s report help' % self.perf_bin,
                              ignore_status=True).stderr
        self.sort_keys = None
        for line in perf_help.split('\n'):
            a = "sort by key(s):"
            if a in line:
                line = line.replace(a, "")
                self.sort_keys = [k.rstrip(",") for k in line.split() if
                                  k.rstrip(",") != 'dso']
        if not self.sort_keys:
            self.sort_keys = ['comm', 'cpu']

    def start(self, test):
        self.logfile = os.path.join(test.profdir, "perf")
        cmd = ("exec %s record -a -o %s" %
               (self.perf_bin, self.logfile))
        if "parent" in self.sort_keys:
            cmd += " -g"
        if self.trace:
            cmd += " -R"
        for event in self.events:
            cmd += " -e %s" % event
        self._process = subprocess.Popen(cmd, shell=True,
                                         stderr=subprocess.STDOUT)

    def stop(self, test):
        os.kill(self._process.pid, signal.SIGINT)
        self._process.wait()

    def report(self, test):
        for key in self.sort_keys:
            reportfile = os.path.join(test.profdir, '%s.comm' % key)
            cmd = ("%s report -i %s --sort %s,dso" % (self.perf_bin,
                                                      self.logfile,
                                                      key))
            outfile = open(reportfile, 'w')
            p = subprocess.Popen(cmd, shell=True, stdout=outfile,
                                 stderr=subprocess.STDOUT)
            p.wait()

        if self.trace:
            tracefile = os.path.join(test.profdir, 'trace')
            cmd = ("%s script -i %s" % (self.perf_bin, self.logfile,))

            outfile = open(tracefile, 'w')
            p = subprocess.Popen(cmd, shell=True, stdout=outfile,
                                 stderr=subprocess.STDOUT)
            p.wait()

        # The raw detailed perf output is HUGE.  We cannot store it by default.
        perf_log_size = os.stat(self.logfile)[stat.ST_SIZE]
        logging.info('Removing %s after generating reports (saving %s bytes).',
                     self.logfile, perf_log_size)
        os.unlink(self.logfile)
