| Index: client/profilers/ftrace/ftrace.py
 | 
| diff --git a/client/profilers/ftrace/ftrace.py b/client/profilers/ftrace/ftrace.py
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..dd13fffd7e3826d782202d6613c26b311d5ed917
 | 
| --- /dev/null
 | 
| +++ b/client/profilers/ftrace/ftrace.py
 | 
| @@ -0,0 +1,133 @@
 | 
| +"""
 | 
| +Function tracer profiler for autotest.
 | 
| +
 | 
| +@author: David Sharp (dhsharp@google.com)
 | 
| +"""
 | 
| +import logging, os, signal, time
 | 
| +from autotest_lib.client.bin import profiler, utils
 | 
| +
 | 
| +
 | 
| +class ftrace(profiler.profiler):
 | 
| +    """
 | 
| +    ftrace profiler for autotest. It builds ftrace from souce and runs
 | 
| +    trace-cmd with configurable parameters.
 | 
| +
 | 
| +    @see: git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git
 | 
| +    """
 | 
| +    version = 1
 | 
| +
 | 
| +    mountpoint = '/sys/kernel/debug'
 | 
| +    tracing_dir = os.path.join(mountpoint, 'tracing')
 | 
| +
 | 
| +    @staticmethod
 | 
| +    def join_command(cmd):
 | 
| +        """
 | 
| +        Shell escape the command for BgJob. grmbl.
 | 
| +
 | 
| +        @param cmd: Command list.
 | 
| +        """
 | 
| +        result = []
 | 
| +        for arg in cmd:
 | 
| +            arg = '"%s"' % utils.sh_escape(arg)
 | 
| +            result += [arg]
 | 
| +        return ' '.join(result)
 | 
| +
 | 
| +
 | 
| +    def setup(self, tarball='trace-cmd.tar.bz2', **kwargs):
 | 
| +        """
 | 
| +        Build and install trace-cmd from source.
 | 
| +
 | 
| +        The tarball was obtained by checking the git repo at 09-14-2010,
 | 
| +        removing the Documentation and the .git folders, and compressing
 | 
| +        it.
 | 
| +
 | 
| +        @param tarball: Path to trace-cmd tarball.
 | 
| +        @param **kwargs: Dictionary with additional parameters.
 | 
| +        """
 | 
| +        self.tarball = utils.unmap_url(self.bindir, tarball, self.tmpdir)
 | 
| +        utils.extract_tarball_to_dir(self.tarball, self.srcdir)
 | 
| +        os.chdir(self.srcdir)
 | 
| +        utils.make("prefix='%s'" % self.builddir)
 | 
| +        utils.make("prefix='%s' install" % self.builddir)
 | 
| +
 | 
| +
 | 
| +    def initialize(self, tracepoints, buffer_size_kb=1408, **kwargs):
 | 
| +        """
 | 
| +        Initialize ftrace profiler.
 | 
| +
 | 
| +        @param tracepoints: List containing a mix of tracpoint names and
 | 
| +                (tracepoint name, filter) tuples. Tracepoint names are as
 | 
| +                accepted by trace-cmd -e, eg "syscalls", or
 | 
| +                "syscalls:sys_enter_read". Filters are as accepted by
 | 
| +                trace-cmd -f, eg "((sig >= 10 && sig < 15) || sig == 17)"
 | 
| +        @param buffer_size_kb: Set the size of the ring buffer (per cpu).
 | 
| +        """
 | 
| +        self.job.require_gcc()
 | 
| +        self.trace_cmd_args = ['-b', str(buffer_size_kb)]
 | 
| +        for tracepoint in tracepoints:
 | 
| +            if isinstance(tracepoint, tuple):
 | 
| +                tracepoint, event_filter = tracepoint
 | 
| +            else:
 | 
| +                event_filter = None
 | 
| +            self.trace_cmd_args += ['-e', tracepoint]
 | 
| +            if event_filter:
 | 
| +                self.trace_cmd_args += ['-f', event_filter]
 | 
| +
 | 
| +        self.builddir = os.path.join(self.bindir, 'build')
 | 
| +        if not os.path.isdir(self.builddir):
 | 
| +            os.makedirs(self.builddir)
 | 
| +        self.trace_cmd = os.path.join(self.builddir, 'bin', 'trace-cmd')
 | 
| +
 | 
| +
 | 
| +    def start(self, test):
 | 
| +        """
 | 
| +        Start ftrace profiler
 | 
| +
 | 
| +        @param test: Autotest test in which the profiler will operate on.
 | 
| +        """
 | 
| +        # Make sure debugfs is mounted and tracing disabled.
 | 
| +        utils.system('%s reset' % self.trace_cmd)
 | 
| +
 | 
| +        output_dir = os.path.join(test.profdir, 'ftrace')
 | 
| +        if not os.path.isdir(output_dir):
 | 
| +            os.makedirs(output_dir)
 | 
| +        self.output = os.path.join(output_dir, 'trace.dat')
 | 
| +        cmd = [self.trace_cmd, 'record', '-o', self.output]
 | 
| +        cmd += self.trace_cmd_args
 | 
| +        self.record_job = utils.BgJob(self.join_command(cmd),
 | 
| +                                      stderr_tee=utils.TEE_TO_LOGS)
 | 
| +
 | 
| +        # Wait for tracing to be enabled. If trace-cmd dies before enabling
 | 
| +        # tracing, then there was a problem.
 | 
| +        tracing_on = os.path.join(self.tracing_dir, 'tracing_on')
 | 
| +        while (self.record_job.sp.poll() is None and
 | 
| +               utils.read_file(tracing_on).strip() != '1'):
 | 
| +            time.sleep(0.1)
 | 
| +        if self.record_job.sp.poll() is not None:
 | 
| +            utils.join_bg_jobs([self.record_job])
 | 
| +            raise error.CmdError(self.record_job.command,
 | 
| +                                 self.record_job.sp.returncode,
 | 
| +                                 'trace-cmd exited early.')
 | 
| +
 | 
| +    def stop(self, test):
 | 
| +        """
 | 
| +        Stop ftrace profiler.
 | 
| +
 | 
| +        @param test: Autotest test in which the profiler will operate on.
 | 
| +        """
 | 
| +        os.kill(self.record_job.sp.pid, signal.SIGINT)
 | 
| +        utils.join_bg_jobs([self.record_job])
 | 
| +        # shrink the buffer to free memory.
 | 
| +        utils.system('%s reset -b 1' % self.trace_cmd)
 | 
| +
 | 
| +        #compress output
 | 
| +        utils.system('bzip2 %s' % self.output)
 | 
| +        compressed_output = self.output + '.bz2'
 | 
| +        # if the compressed trace file is large (10MB), just delete it.
 | 
| +        compressed_output_size = os.path.getsize(compressed_output)
 | 
| +        if compressed_output_size > 10*1024*1024:
 | 
| +            logging.warn('Deleting large trace file %s (%d bytes)',
 | 
| +                         compressed_output, compressed_output_size)
 | 
| +            os.remove(compressed_output)
 | 
| +        # remove per-cpu files in case trace-cmd died.
 | 
| +        utils.system('rm -f %s.cpu*' % self.output)
 | 
| 
 |